Wild GIF12

Dieses Kartenlesegerät für GRM10-Speicherkarten (für Leica-Vermessungsgeräte), bzw. die Windows-Software dazu, hat folgende Macken:
  1. Closed source
  2. Benötigt ein echtes Parallelport mit 5-V-Pegeln (3,3 V reichen nicht)
  3. Liest die Parallelport-Adressen vom BIOS-Datenbereich (was bei PCI / PCIexpress nicht klappt, nicht einmal unter Win9x/Me)
  4. Läuft unter Win9x/Me nicht mit LPT3 (Bug, erfordert Patch)
  5. Läuft nicht mit USB2LPT (falls usb2lpt.sys-Treiber älter als Oktober 2013)
  6. Läuft nicht unter 64-Bit-Windows (verlässt sich auf Kernel-Mode-Treiber giveio.sys und mapmem.sys)
Das System ist ja auch schon recht alt. Schätzungsweise 1990. Im folgenden die Ausführungen zur Lösung.
[Foto]
So sieht das Gerät mit High-Speed-USB2LPT aus, und funktioniert so auch unter Windows 7 64bit
Dazu weitere Bilder und Downloads:

5-V-Pegel

Echte Parallelports sowie ein Exemplar einer PCIexpress-Karte hatte tatsächlich 5 V Ausgangspegel. Im Zweifelsfall mit einem Multimeter nachmessen! Einige Ausgänge werden zur Stromversorgung benutzt, auch wenn im Lesegerät eine 9-V-Batterie enthalten ist. (Diese wird bei mir nicht benötigt.)

Die Beobachtung der Pegel mit lptchk funktioniert nicht. Die Ausgangspegel brechen zu stark ein.

Das Problem taucht auch bei USB2LPT 1.7 (High-Speed) auf. Ohne lptchk. Hierfür ist eine gesonderte Lösung praktikabel, siehe unten.

Von Leica kommt jener Vorschlag [sic!] um mit 3,3-V-Laptop-LPTs zurechtzukommen. Kann nicht funktionieren, weil ohne Geräteeingriff am Pin 25 gar keine 9 Volt herauskommen. Auch hier wäre der unten angegebene Bustreiber die bessere und die Batterie schonende Lösung.

Unterstützung von PCI / PCIexpress-Karten

Hier ist dafür zu sorgen, dass die Basisadresse im BIOS-Datenbereich (ab Adresse 0040:0008) steht. Dies kann InpOut32.dll (ab Oktober 2013) erledigen, mit folgender Kommandozeile:
rundll32.exe .\inpout32.dll,Info q
Dieses Kommando muss nach Betriebssystemstart, vor dem Starten von wgif12nt, mit Administratorrechten ausgeführt werden. Es sucht vorhandene Parallelports und trägt deren Basisadresse im BIOS-Datenbereich ein, damit diese von wgif12nt.exe gefunden werden können.

Wie der Name BIOS-Datenbereich andeutet, wird dieser vom BIOS gefüllt und benutzt. Derartige PCI- und PCIexpress-Karten tauchen aber erst beim Windows-Hochlauf auf und sind für das BIOS nicht sichtbar.

Alternativ kann man die Lösung für 64-Bit-Windows benutzen, siehe unten.

Der Vorteil von entsprechend geeigneten ExpressCard-Karten ist, dass diese in Notebooks mit passendem Slot laufen und der Zugriff ohne Geschwindigkeitsverlust einhergeht. ExpressCard basiert auf PCIexpress und ist hier gleichbedeutend.

Ungeeignete ExpressCard-Karten sind USB-basiert und ensprechen solchen USB-Parallel-Adaptern, die nur für Drucker geeignet sind.

LPT3 unter Win9x/Me sowie 64-Bit-Windows

Ein Bug erlaubt hierbei nur LPT1 und LPT2. Dafür ist die EXE-Datei zu patchen. Am einfachsten, wenn man das Programm fpatch.com hat.
fpatch.com -s06668b750883e601 -p+7 -r03 WGif12NT.exe
Sucht nach der angegebenen Bytefolge und ändert das letzte Byte (die Indexmaske) auf 3.

Für 64-Bit-Windows ist noch mehr zu tun, siehe unten.

USB2LPT-Lauffähigkeit

Ich hätte nie gedacht, dass ein Programm auf die Idee kommt, unter NT im BIOS-Datenbereich nach der Portadresse zu suchen. Dieses Programm tut es!

Daher ist USB2LPT.SYS nunmehr (seit Oktober 2013) so erweitert, dass es den Datenbereich auch unter NT entsprechend patcht. Um sicher zu gehen auch im 64-Bit-Windows. Unter 9x/Me tat es der Treiber immer schon.

Ohne weitere Maßnahmen läuft nur der ATmega8-basierte USB2LPT 1.6 Low-Speed. Wegen seiner 5-V-Pegel. Das Auslesen einer 3-KByte-Datei dauert damit ca. 10 Minuten. Unter Windows 2000 oder XP. Unter Windows Vista und 7 noch einiges langsamer. Wegen der verbotenen BULK-Pipes.

Damit USB2LPT 1.7 High-Speed läuft, muss:

Damit sinken die Übertragungszeiten auf akzeptable Werte (etwa 1 Minute für 3 Kilobyte), unabhängig von der Windows-Version. Schneller geht's nicht — es sei denn man hätte den Quelltext von wgif12nt.exe. Ein echtes Parallelport, am Notebook etwa als ExpressCard, ist die bessere Alternative.

Lauffähigkeit unter 64-Bit-Windows

Bei mir kann der Suffix .dll entfallen. Herr Markus Neu hatte bei sich den Suffix zwingend gebraucht, was ich nicht nachvollziehen kann.

Der Vorsatz .\ sorgt dafür, dass InpOut32.dll nicht zuerst im Pfad gesucht wird, sondern nur die Datei im aktuellen Verzeichnis benutzt wird. Sonst würde eine eventuell bereits global installierte ältere InpOut32.dll im %SystemRoot%\SysWOW64-Verzeichnis stören.

Das lässt sich ganz allgemein mit meiner Ausgabe von inpout32.dll (ab Oktober 2013) bewerkstelligen. Und zwar mit dieser Kommandozeile:
rundll32.exe .\InpOut32.dll,CatchIo WGif12NT.exe
Admin-Rechte sind beim erstmaligen Start erforderlich, um den enthaltenen Treiber inpoutx64.sys zu laden. Die Dateien giveio.sys und mapmem.sys kann man getrost löschen, da sie unter 64-Bit-Windows schlichtweg unbrauchbar sind.

Im Falle von PCI/PCIexpress-Karten wird das Aktualisieren des BIOS-Datenbereiches nicht benötigt. Damit LPT3 funktioniert, ist ein Patch (siehe oben) vonnöten. Im übrigen funktioniert diese Lösung auch unter 32-Bit-Windows, ohne Aktualisierung des BIOS-Datenbereiches.

USB2LPT funktioniert damit auch. Allerdings benötigt sein Treiber (zurzeit) den deaktivierten Treiberzertifizierungszwang. Dazu ist bei jedem Booten von Windows Vista oder 7 F8 zu drücken und der entsprechende Menüpunkt auszuwählen. Bei Windows 8 sowie 8.1 ist das Prozedere noch komplizierter. Zwar funktioniert USB2LPT inzwischen auch ohne Treiber, ist dann aber viel langsamer.

Zunächst funktionierte die Lösung nicht, weil der Zugriff auf den BIOS-Datenbereich bei vorgegaukeltem Windows 9x Schutzverletzungen (Exceptions) hervorbrachte. Die aktuelle Version von inpout32.dll verarbeitet jede Art von Ladebefehl aus dem BIOS-Bereich. Dazu ist ein entsprechender X86-Befehlsdekoder eingebaut.

Neu: Es steht ein 64-bittriges giveio.sys zur Verfügung, mit dem Portzugriffe aus dem User-Mode ohne Zeitverzug durch das Exception-Handling möglich sind. Er erweist sich als funktionssicher und ist sogar zertifiziert. Diese Variante ist nunmehr zu bevorzugen.

Disassemblierung der DOS-Software

Das Verständnis der Datenübertragung und des Speicherformates ist die einzige Chance, das Gerät wirklich und dauerhaft in die Zukunft zu retten. Alles andere (auch USB2LPT) ist auf Dauer nur ein Herumstümpern. Auf 16 KByte kann ja nicht so viel sein, und das DOS-Programm ist nicht allzu kompliziert. Natürlich ist die Echse mit einem Exe-Packer bearbeitet worden, aber das ist ja für den Durchschnittshacker kaum ein Problem. Die Disassemblierung der wesentlichen Bestandteile muss folgende Teile offenlegen: Den übrigen Ramsch mit dem Fenster-Manager und der Turbo-Pascal-Laufzeitbibliothek muss man der Komplexität wegen ignorieren; die Schwierigkeit besteht dabei, genau die wichtigen von den unwichtigen Routinen zu trennen. Die Segmentierung (Pascal-Units) hilft dabei. Erwartungsgemäß ist das Programm mit heißer Nadel gestrickt worden und fürchterlich strukturiert (auch das erkennt man am Disassembler).

Die Datenkompression erfolgt anscheinend nach diesem Schema:

Datenkompression/Expansion
Das Dateisystem besteht aus einem 256-Byte-Wurzelverzeichnis mit 13 für den Anwender nutzbaren nummerierten „Slots“ (keine Dateinamen) mit festlegbarer Maximalgröße in KByte-Schritten. (Wer die ganzen KByte aufbürdet ist unklar, möglicherweise benötigt das Vermessungsgerät diese Stückelung.) Die Dateien sind nach derzeitigem Erkenntnisstand immer in 8-Byte-Stückelung.

Hier noch mal das IDA5-Projekt der DOS-Software.

Ein richtiger USB-Adapter?

Ein bestens konstruierter USB-Adapter sollte ohne speziell zugeschnittene Anwendersoftware auskommen. Damit kann man auf die Daten unabhängig vom Betriebssystem zugreifen. Die Mikrocontroller-Software fällt dafür komplexer aus. Dafür gibt es zwei Implementierungsmöglichkeiten:

Beide Ansätze erfordern eine Hintertür zur Speicherplatzreservierung. Die Unterstützung diverser Schutzattribute ist nicht möglich und ohnehin obsolet.

Firmware für MTP

habe ich mich dazu aufgerappelt, das Media Transfer Protocol in einen ATmega32U4 auf einem Arduino Pro Micro zu implementieren. Der Arduino-Urlader wurde durch meinen Ableger von ubaboot ersetzt: Er ist mit 0,5 KByte schön klein. Da die Firmware nicht größer als 7,5 KByte groß wird, dienen die restlichen 24 KByte als Datenspeicher.

Wenn man das Gehäuse einer GRM10-Speicherkarte mit dem 3D-Drucker nachahmt und eine geeignete Leiterplatte macht, kann man sich so eine neues Medium bauen, das:

Genial, nicht wahr? Jetzt wird bloß noch Zeit und ein Vermessungsgerät zum Testen benötigt, denn die serielle Schnittstelle zum Vermessungsgerät hin muss ja auch noch ausgeschnüffelt und nachgeahmt werden. Und Zeit zum Programmieren.

In Funktion (Windows 10)
Firmware, funktioniert wie ein 24-Kilobyte-USB-Stick. Benötigt mein ubaboot als Urlader und läuft auf ATmega32U4 mit 16-MHz-Quarz. Die gleiche Firmware auf's Notwendige eingedampft, bei gleicher Funktionalität unter Windows 10. Vor allem beim RAM-Verbrauch wurde erheblich reduziert.

Ausgangspunkt war eine Teensy-Firmware für einen 32-Bit-Controller, die hiermit für die 8-Bit-Architektur zurechtgestutzt und speziell für den ATmega32U4 angepasst wurde, um nicht zu fett zu werden. Außerdem ist's so verständlicher geworden.

Wie man leicht erkennt, bietet sich MTP auch für Datenlogger an. Diese müssten dann readonly sein und können die Excel-ASCII-Daten auf Abruf von einem hochdichten Logspeicher auspacken und ausspucken.

Lange habe ich damit gekämpft, das Flash-Schreiben hinzubekommen: Die Firmware verlässt sich nun voll und ganz auf den Mini-Urlader ubaboot für do_spm(). Andere Schwierigkeiten waren Bugs, Bugs und noch mehr kleine Käferchen. Ist nunmehr alles gelöst.

Mit Caterina?

Zugegeben, den Urlader ubaboot auf einen Arduino draufzubringen ist nichts für Anfänger. Wäre es nicht schön, den bereits vorhandenen Urlader Caterina nutzen zu können? Klar, der verbraucht 2 Kilobyte Flash, nicht nur 512 Byte. Na gut.

Der entscheidende Punkt ist, eine Adresse für do_spm herauszufinden. Da vom Urlader keine Disassemblerlistings im Web herumgeistern, sondern nur HEX-Dateien, muss man:

Das Disassemblieren mit Bordmitteln erfordert das Überführen der HEX-Datei in eine ELF-Datei, und das geht wie folgt:

avr-objcopy -I ihex -O elf32-avr --rename-section .sec1=.text,contents,alloc,load,readonly,code Caterina-Micro.hex Caterina-Micro.elf
avr-objdump -d Caterina-Micro.elf > Caterina-Micro.lst

Alternativ geht auch:

avr-objcopy -I ihex -O elf32-avr Caterina-Micro.hex Caterina-Micro.elf
avr-objdump -D Caterina-Micro.elf > Caterina-Micro.lst

Der Disassembler disassembliert stupid alles zu Assemblerbefehlen. Er hat keine Kodepfadanalyse.

Der Befehl spm kommt dabei ziemlich oft vor. Das kommt vom #include <avr/boot.h>. Keiner davon hat ret in der Nähe, das heißt, es ist kein Unterprogramm vorhanden, sondern alles inline. Das hätte man auch nach dem Studium des Quelltextes Caterina.c in Verbindung mit avr/boot.h herausfinden können.

Damit ist Caterina für diese Firmware sowie für alle Projekte, die Flash als Schreib-Lese-Datenspeicher verwenden wollen, ungeeignet. Doof, nicht weitergedacht. (Hätte ich das von Dean Cameron auch erwarten können?)

Ende Gelände, Aus die Maus!

Mit Atmels Urlader?

Dieser Urlader wird original von Atmel in den Chips ausgeliefert und zwackt 4 KByte von den 32 KByte ab. Auf PC-Seite gibt dieser sich als „hersteller-spezifisch“ aus und wird per Atmels INF-Datei an libusb gebunden. Im Geräte-Manager steht „Atmel DFU“. Auf Arduino-Boards wurde dieser durch den Arduino-Hersteller durch Caterina überschrieben. Daher findet sich dieser Urlader nur in unverlöteten Chips sowie auf Entwicklungsboards, die nicht auf Arduino basieren, etwa dem eHaJo-Board, wie er im Projekt Frequenzmesser verwendet wurde.

Die gleiche Prozedur wurde an der Datei ATMega32U4-usbdevice_dfu-1_0_0.hex ausgeführt, die man als megaUSB_DFU_Bootloaders.zip von AtmelMicrochip herunterladen kann. Dabei zeigt sich, dass man hier nicht nur passende Einsprungpunkte findet, sondern am Ende des Urladers eine Sprungtabelle extra für diesen Zweck existiert.

7fe4:	jmp	0x7dda	;Flash-Page löschen (SPMCSR = 3) + Schreiben (SPMCSR = 5) + Rücksprung (SPMCSR = 0x11), Z in R17:R16
7fe8:	jmp	0x7e22	;Signatur lesen (SPMCSR = 0x21), Z in R17:R16, Ergebnis in R16
7fec:	jmp	0x7e32	;Sperrbits lesen (SPMCSR = 9), Z in R17:R16, Ergebnis in R16
7ff0:	jmp	0x7e42	;Wort in Flash setzen (SPMCSR = 1), Wort in R17:R16, Z in R19:R18
7ff4:	jmp	0x7de4	;Flash-Page schreiben (SPMCSR = 5) und Rücksprung (SPMCSR = 0x11), Z in R17:R16
7ff8:	jmp	0x7e06	;Flash-Page löschen (SPMCSR = 3) und Rücksprung (SPMCSR = 0x11), Z in R17:R16
7ffc:	jmp	0x7e52	;Sperrbits setzen (SPMCSR = 9), Sperrbits in R16
Mit dem Atmel-Urlader geht's. Man muss für avr-gcc trotzdem noch Wrapper-Funktionen schreiben.

Das Code-Wirrwarr kann weder durch Assembler noch avr-gcc entstanden sein. Atmel hat das wohl eher mit IAR „verbrochen“. (Immerhin sind die vielen Unterprogrammaufrufe alle mit RCALL, nicht mit CALL gemacht.) Alle 7 Unterprogramme warten vorher und nachher auf das Ende des Flash-Vorgangs (SPMCSR.0 = 0), aber nicht auf den EEPROM. R0, R20 sowie Z werden „verbraten“.

Noch kleiner?

Zumindest für den Convac-Ätzer bietet es sich an, den 1-KByte-EEPROM künftig nicht mehr mit der seriellen Schnittstelle und CDC abzubilden, sondern als eine einzige Datei mittels MTP. In diesem Fall zum Lesen und Schreiben. Dann hat man eine einfache Backup- und Restore-Möglichkeit für die mühsam eingegebenen Daten.

Da die Firmware bereits elend groß ist, wäre es nunmehr wichtig, diese Funktionalität kleiner als CDC hinzubekommen. Am meisten könnte man an der Bereitstellung der Deskriptoren sparen. Für jenes Projekt.

Herausgekommen ist dieses MTP-Gerät mit 1,5 KByte Größe. Es ist ein Readonly-Gerät mit genau 1 Datei von 1 KByte, die den Inhalt des EEPROM wiedergibt. Nicht sonderlich hilfreich, aber ein Gradmesser: Die MTP-Routinen erstrecken sich von 0x014A bis 0x031E, das sind 0x1D6 Bytes, weniger als 1/2 Kilobyte. Aber Readonly ist nicht so recht nützlich.

Die konsequente Weiterentwicklung ist das MTP-Gerät mit 1 veränderbaren Datei. Leider lässt es sich nicht vermeiden, dass der Anwender diese Datei „erfolgreich löschen“ darf und kann. Sie verschwindet von der Explorer-Ansicht, obwohl sie weiterhin existiert, wie man durch Ab- und Anstecken verifizieren kann. Auch diesmal reflektiert die Datei den EEPROM-Inhalt, diesmal in variabler Länge von 0 bis 1024. Die MTP-Routinen erstrecken sich von 0x0464 bis 0x06F6, das sind 0x292 Bytes, knapp 3/4 Kilobyte. Nicht schlecht. Der avr-gcc-Schalter -mrelax hilft.


Das Musterexemplar wurde dankenswerterweise vom Vermessungsbüro Glaubitz zur Verfügung gestellt.