IT security, FreeBSD, Linux, mail server hardening, post-quantum crypto, DNS, retro computing & hands-on hardware hacks. Privater Tech-Blog seit 2003.

Schlagwort: Open Source (Seite 1 von 2)

TC1 Multifunction Tester: Open-Source Firmware flashen, kalibrieren und die Stolperfallen dabei

TC1 Multi-function Tester mit originaler M-Tester Firmware auf dem Display

Es gibt diese kleinen Bauteiltester aus China, die für 15 bis 20 Euro auf AliExpress oder Amazon rumschwirren. Der TC1, auch bekannt als LCR-TC1. Transistoren, Widerstände, Kondensatoren, MOSFETs, Dioden. Bauteil in den ZIF-Sockel stecken, Knopf drücken, fertig. Für den Preis eigentlich erstaunlich brauchbar. Aber die originale Firmware ist halt, sagen wir mal, solide Mittelklasse. Die Messgenauigkeit geht in Ordnung, aber nicht mehr, und die Zahl der erkannten Bauteile ist überschaubar. In der Open-Source-Welt gibt es zwei Firmware-Varianten für diese Tester: Die k-firmware als stabiles Original und die m-firmware von madires als aktiv weiterentwickelter Rewrite. Präzisere Messungen, mehr erkannte Bauteile, bessere IR-Protokollunterstützung, flexiblere Konfiguration und ein sauberes Menü mit Kalibrierung. Also habe ich mich drangesetzt.

Was als „schnell mal neue Firmware drauf“ geplant war, wurde ein mehrtägiger Abstieg in die Untiefen von STC-Microcontrollern, falschen Pinouts und parasitärer Stromversorgung. Aber der Reihe nach.

Was steckt im TC1?

PCB-Rueckseite des TC1 mit ATmega324PA Hauptprozessor und STC15L104W Power-Management-Chip

Auf der Rückseite der Platine sitzen zwei Chips, die man kennen muss:

Nahaufnahme des ATmega324PA-U-TH Chips auf der TC1-Platine

U1: ATmega324PA — der Hauptprozessor. Ein Atmel AVR im TQFP-44 Gehäuse, 32 KB Flash, 2 KB SRAM, 1 KB EEPROM. Hier läuft die eigentliche Tester-Firmware. Wird über ISP (In-System Programming) geflasht, also braucht man einen Programmer.

Nahaufnahme des STC15L104W (U4) Power-Management-Chips im SOP-8 Gehaeuse

U4: STC15L104W — ein winziger 8051-kompatibler Mikrocontroller im SOP-8 Gehäuse von STC Micro. Der macht das Power-Management: Einschalten per Tastendruck, automatisches Abschalten nach Timeout. Klingt trivial, ist aber der Chip, der mir die meisten Kopfschmerzen bereitet hat.

Beide Chips brauchen neue Firmware. Die m-firmware liefert die Hex-Dateien für beide: ComponentTester.hex für den ATmega und u4.hex für den STC. Klingt einfach. War es nicht.

Erster Versuch: Backup der Original-Firmware

Bevor man irgendwas überschreibt, will man natürlich ein Backup. Gute Idee, klappt nur nicht. Die Lock Bits des ATmega sind auf 0xC0 gesetzt. Das bedeutet: Lesen des Flash-Inhalts ist gesperrt. Man kann die Firmware löschen und neu schreiben, aber nicht auslesen. Kein Backup möglich. Also Augen zu und durch.

U4 flashen: Der schwierigste Teil

Der STC15L104W hat einen eingebauten UART-Bootloader. Klingt praktisch. Man braucht theoretisch nur einen USB-TTL Adapter, sendet das Hex-File und der Chip programmiert sich selbst. Theoretisch. In der Praxis muss der Chip für den Bootloader einen sauberen Power-Cycle bekommen, also Strom weg, Strom wieder an. Und genau hier fängt das Drama an.

Im eingelöteten Zustand liegt VCC des STC über den Button-Schaltkreis auf GND. Der Bootloader startet schlicht nicht. Der Chip muss raus.

Atten ST-862D Heissluft-Rework-Station zum Ausloeten des STC15L104W
Sugon T3602 Dual-Channel Loetstation mit Temperaturanzeige auf dem Arbeitsplatz

Also Atten ST-862D Heißluftstation raus, SOP-8 Chip bei 280°C vorsichtig von der Platine gehoben, Pads sauber gemacht. Zum späteren Wiedereinlöten dann die Sugon T3602. Für solche SMD-Arbeiten will man vernünftiges Werkzeug, mit einem 15-Euro-Lötkolben aus dem Baumarkt wird das nichts.

Der CH341 und seine 5V-Lüge

Erster Versuch: CH341 USB-TTL Adapter. Steht „3.3V“ drauf, also sollte das passen. Der STC15L104W ist ein 3.3V-only Chip, 5V auf den Datenleitungen wären sein Todesurteil. Also Multimeter dran, TX-Pin messen und… 5V. Auf dem TX-Pin. Trotz „3.3V“-Stellung. Der CH341 hat zwar einen 3.3V Spannungsregler für VCC, aber die Logikpegel auf TX bleiben bei 5V. Das steht nirgendwo auf dem Board, nirgendwo im Datenblatt des Adapters. Man muss es wissen oder messen.

Hätte ich nicht nachgemessen, wäre der STC jetzt Elektroschrott. Lektion gelernt: Immer nachmessen, nie dem Aufdruck vertrauen.

FT232RL USB-TTL Adapter mit Jumper auf 3.3V fuer das STC15L104W Flashing

Also einen FT232RL USB-TTL Adapter bestellt. Der hat einen echten 3.3V/5V Jumper, der tatsächlich auch die Logikpegel umschaltet. Nachgemessen: TX bei 3.3V. Endlich.

Das Pinout-Desaster

Jetzt wirds peinlich. Ich habe stundenlang versucht, den STC über Pin 1 (P3.4) und Pin 3 (P3.5) anzusprechen. Keine Reaktion. Kein Bootloader. Nichts. Irgendwann habe ich nochmal das Datenblatt studiert und festgestellt: P3.4 und P3.5 sind GPIO-Pins. Die UART-Pins (RXD/TXD) liegen auf P3.0 und P3.1, also Pin 5 und Pin 6. Das SOP-8 Pinout:

        ┌──────────┐
Pin 1  │● P3.4    │  Pin 8  (P3.3)
Pin 2  │  VCC     │  Pin 7  (P3.2)
Pin 3  │  P3.5    │  Pin 6  ← TXD (P3.1)
Pin 4  │  GND     │  Pin 5  ← RXD (P3.0)
       └──────────┘

Stunden. Am falschen Pin. Das sind so Momente, in denen man kurz aufstehen und was trinken gehen sollte. Keine Ahnung, warum ich die falschen Pins unbedingt wollte… Ich hab auf das Datenblatt geschaut und… na, vielleicht war die Brille dreckig, keine Ahnung. „Leider“ kamen da auch sinlose Daten bei zustande, was erst nach einer falschen Baudrate ausgesehen hat; vielleicht ist das eine gute Ausrede, warum ich da so lange hängen geblieben bin?!

Parasitäre Stromversorgung und der Breadboard-Aufbau

Ausgeloeteter STC15L104W auf Breadboard verkabelt mit FT232RL Adapter zum Flashen

Das nächste Problem: Der STC-Bootloader braucht einen Power-Cycle zum Starten. Also VCC abziehen, Flash-Tool starten, VCC wieder anlegen. Sollte klappen. Tat es aber nicht zuverlässig. Warum? Der Chip versorgt sich über die TX/RX-Datenleitungen parasitär mit Strom. Selbst wenn VCC getrennt ist, reicht der Strom über die Schutzdioden in den I/O-Pins, um den Chip am Leben zu halten. Kein sauberer Power-Cycle, kein Bootloader.

Die Lösung: Beim Power-Cycle ALLE Drähte trennen, nicht nur VCC. Erst das Flash-Tool starten (wartet auf den Chip), dann alle Leitungen gleichzeitig einstecken. Dazu ein 220 Ohm Serienwiderstand auf der TX-Leitung als Schutz und ein 100nF Stützkondensator zwischen VCC und GND für eine stabile Versorgung.

Geflasht habe ich unter Linux mit stcgal:

stcgal -P stc15 -p /dev/ttyUSB1 -l 2400 -b 4800 -t 12000 u4.hex

Der Trick ist die niedrige Baudrate (-l 2400 für die initiale Kommunikation, -b 4800 zum Flashen) und das erhöhte Timeout (-t 12000). Zur Verifikation habe ich das Ganze nochmal mit STC-ISP v6.96S unter Windows (VirtualBox) gegengeprüft. Beides erfolgreich. Chip wieder eingelötet, weiter gehts.

U1 flashen: Der einfache Teil

Arduino Uno als ISP-Programmer mit Dupont-Kabeln an den Digital-Pins
Arduino Uno Power-Seite mit VCC und GND Verkabelung fuer ISP-Programmierung

Der ATmega324PA wird über ISP programmiert. Als Programmer dient ein ganz normaler Arduino Uno mit dem ArduinoISP-Sketch. Den lädt man in der Arduino IDE über File → Examples → ArduinoISP auf den Uno. Dann die Pins verbinden: MOSI (D11), MISO (D12), SCK (D13), RESET (D10) vom Arduino an den J4-Header auf der TC1-Rückseite, plus VCC und GND.

ISP-Kabel am J4-Header auf der TC1-Platinenrueckseite angeschlossen
Seitenansicht des TC1 mit angeschlossenem ISP-Kabel am J4-Header

Auf der TC1-Platine gibt es ein J4-Pad für ISP. Ich habe da einen Pin-Header aufgelötet, das macht das Leben bei zukünftigen Updates deutlich einfacher. Dann mit avrdude:

avrdude -c avrisp -p m324pa -P /dev/ttyACM0 -b 19200 -U flash:w:ComponentTester.hex:i

Das ging durch. Erster Versuch. Nach dem STC-Drama fühlte sich das fast verdächtig einfach an.

„Kas Rh- _BB“ — Was zur Hölle?

Nach dem Flashen das Display eingeschaltet und… „Kas Rh- _BB“ statt „Bat 3.83V ok“. Die Zeichen sahen aus wie ein kaputtes Font-Rendering. Stundenlang habe ich nach SPI-Fehlern gesucht, den Display-Treiber hinterfragt (ST7735 vs. SEMI_ST7735), die Pin-Belegung dreimal geprüft. Nichts half.

Die Lösung war so simpel wie ärgerlich: „Kas“ ist der Anfang von „Kaseikyo“, einem IR-Protokollnamen. Die m-firmware speichert Strings standardmäßig im EEPROM (DATA_EEPROM in der config.h). Aber ich hatte nur die .hex-Datei geflasht, nicht die .eep-Datei fürs EEPROM. Die Firmware las also zufällige alte Daten aus dem EEPROM und interpretierte sie als Text.

Der Fix: In der config.h DATA_FLASH statt DATA_EEPROM setzen. Dann werden alle Strings direkt im Flash-Speicher abgelegt und man braucht kein separates EEPROM-Flashing. Nochmal kompiliert, nochmal geflasht. Uff… Bis ich darauf gekommen bin *kopfschüttel*. Zugegeben, darüber nachgedacht habe ich aber ich war mir fast sicher das in einem mit geflashed zu haben. Fast sicher halt. Eine Nacht darüber schlafen hat geholfen, klassisch also im Problem festgefressen.

Batteriespannung: 19V aus einer LiPo-Zelle?

Nächstes Problem: Das Display zeigte 19V Batteriespannung an. Der TC1 läuft mit einer einzelnen LiPo-Zelle, das sind 3,7 bis 4,2V. Die Standard-Konfiguration der m-firmware geht von einem Spannungsteiler auf der Batterieleitung aus (BAT_DIVIDER mit R1=10k, R2=3.3k für einen 9V-Block). Der TC1 hat aber keinen Spannungsteiler, die Batteriespannung geht direkt an den ADC.

Fix: BAT_DIRECT statt BAT_DIVIDER in der config.h. Dazu die Schwellwerte anpassen: BAT_WEAK=3400 und BAT_LOW=3100 (in mV) für eine einzelne LiPo-Zelle.

TC1 Display zeigt Bat 3.83V ok und Probing nach korrekter BAT_DIRECT Konfiguration

So soll das aussehen. 3.83V, alles ok.

Menü und Kalibrierung

TC1 Menue mit Adjustment-Option fuer die Kalibrierung nach Firmware-Flash

Noch ein Stolperstein: Das Menü war nicht erreichbar. Die m-firmware hat verschiedene Wege, das Menü aufzurufen. Beim TC1 funktioniert das über UI_SHORT_CIRCUIT_MENU: Alle drei Probe-Pins im ZIF-Sockel kurzschließen und Start drücken. Dann öffnet sich das Menü mit Optionen für PWM, IR-Detector, Opto Coupler, Test und eben Adjustment.

Die Kalibrierung selbst ist einfach: Adjustment auswählen, mit leerem ZIF-Sockel starten, dann wenn gefordert einen Kurzschluss zwischen 123 einstecken. Die Firmware misst die internen Referenzen und speichert die Korrekturdaten. Dann den Kurzschluss wieder raus und es wird die Gegenprobe gemessen.

Die vollständige Konfiguration

Für alle, die das selbst machen wollen, hier die kompletten Änderungen gegenüber der Standard-Konfiguration der m-firmware (ComponentTester v1.56m):

Makefile:

MCU = atmega324p
FREQ = 16

config.h:

#define DATA_FLASH              /* Strings im Flash statt EEPROM */
#define UI_AUTOHOLD             /* Messergebnis halten bis Tastendruck */
#define UI_SHORT_CIRCUIT_MENU   /* Menü über Kurzschluss aller Probes */
#define BAT_DIRECT              /* Kein Spannungsteiler auf Batterie */
#define BAT_WEAK    3400        /* Warnung unter 3.4V */
#define BAT_LOW     3100        /* Abschaltung unter 3.1V */

config_644.h (Hardware-Mapping für den TC1):

/* Display: ST7735 über SPI Bit-Bang */
#define LCD_ST7735
#define LCD_RES     PB4
#define LCD_DC      PB5
#define LCD_SDA     PB6
#define LCD_SCL     PB7
#define LCD_FLIP_X
#define LCD_ROTATE
#define LCD_OFFSET_X    2
#define LCD_OFFSET_Y    1
#define LCD_LATE_ON
#define SPI_BITBANG         /* SDA auf PB6 statt Hardware-MOSI PB5 */

/* Probe-Widerstände auf PORTC statt PORTD */
/* PC0-PC5 für die drei Probe-Paare */

/* Power und Button */
#define POWER_PORT  PORTD
#define POWER_PIN   PD2
#define BUTTON_PIN  PD1

/* ADC-Pins vertauscht gegenüber Default */
#define TP_ZENER    PA4
#define TP_REF      PA3

Das Ergebnis

TC1 Startbildschirm zeigt Component Tester v1.56m nach erfolgreichem Flash

Component Tester v1.56m. Läuft.

TC1 mit m-firmware zeigt korrekt gemessenen 220 Ohm Widerstand an
TC1 erkennt MOSFET N-ch enh. mit Vth, Cgs und Rds Werten nach Firmware-Update

Widerstände, MOSFETs, alles wird sauber erkannt. Die Werte passen.

MOSFET-Messung auf dem TC1 nach Kalibrierung mit praezisen Vth und Rds Werten

Nach der Kalibrierung werden die Messwerte nochmal präziser. Vth 2065mV, Cgs 11.27nF, Rds 0.03 Ohm. Für einen 20-Euro-Tester absolut brauchbar.

Fazit und Quellen

War das ganze Prozedere nötig? Die originale Firmware funktioniert ja grundsätzlich. Aber wenn man sich auf die Messwerte verlassen will und nicht bei jedem unbekannten Bauteil rätseln möchte, lohnt sich der Aufwand. Die m-firmware liefert präzisere Ergebnisse, erkennt deutlich mehr Bauteile und hat ein richtiges Menü mit Kalibrierung. Und der J4-Header ist jetzt drauf, das nächste Firmware-Update ist dann tatsächlich in fünf Minuten erledigt.

Die fertige Firmware mit allen Config-Anpassungen für den TC1 und eine Schritt-für-Schritt-Anleitung habe ich auf GitHub gepackt. Da liegt auch die U4-Firmware (tc1-u4, GPL v3) und ein Verweis auf die m-firmware (EUPL v1.2).

Wer sich tiefer einlesen will:

Siehe auch:, Multifunktionstester für Elektronikbauteile: Schnell & günstig prüfen​

Fragen zum TC1 oder eigene Erfahrungen beim Flashen? Dann kannst du mich gerne fragen.

Commodore Floppy Disk Preservation: Firmware-Bug im xum1541 gefunden und gefixt

Commodore 1571 Laufwerk mit xum1541 (Teensy2) beim Auslesen einer 5,25-Zoll-Diskette unter Linux

In meinem Keller stehen Kisten voller alter 5,25-Zoll-Disketten. Commodore-Software aus den späten 80ern, Spiele, Tools, selbstgeschriebener Kram. Das Problem mit Floppy-Disks: die Magnetisierung lässt mit der Zeit nach. Alle paar Jahre sollte man die Daten einmal komplett lesen und zurückschreiben, sonst wird das Medium irgendwann unlesbar. Mein letztes Auffrischen ist eine Weile her, also war es mal wieder Zeit. Zugegeben, ich arbeite nur noch extrem selten mit meinem Commodore; aber wenn ich es mache, ist es immer eine kleine Zeitreise voller Nostalgie für mich. Die Geräusche, der Geruch, die Wartezeit. Hin und wieder tut es mir einfach gut, noch mal die alten Spiele zu spielen, mit den Tools zu arbeiten oder auch meine ersten eigenen Programme noch mal zu starten, in den Code zu schauen *kopfschütteln*…. Ich habe sogar noch alte Hausaufgaben auf Disketten 😀

Stapel aus Commodore 1571 Diskettenlaufwerken mit 5,25-Zoll-Disketten und dem 1570/1571 Handbuch

Was als routinemäßige Sicherungsaktion geplant war, wurde dann allerdings eine mehrtägige Debugging-Session. Inklusive eines Firmware-Bugs, der seit sechs Jahren im Code schlummerte.

Die Ausgangslage

Mein Setup: Zwei Commodore 1571 Laufwerke, angeschlossen über einen xum1541 USB-Adapter an einem Linux-Rechner. Der xum1541 sitzt auf einem TEENSY2-Board (ATmega32U4) und spricht über USB mit OpenCBM, einer Open-Source-Treibersammlung für Commodore-Laufwerke. Die Software-Seite hatte ich in einer vorherigen Session bereits verifiziert. Beide Laufwerke laufen bei fast perfekten 300,5 RPM, lesen und schreiben fehlerfrei auf beiden Seiten und liefern sogar bit-identische Images im Crosscheck.

Der Plan war simpel: Alle Disketten systematisch als 1:1-Image sichern, die physischen Medien durch Zurückschreiben auffrischen und nebenbei prüfen, ob die Inhalte bereits in Online-Archiven wie CSDB, Gamebase64 oder dem Internet Archive vorhanden sind.

Der xum1541 im gelben Gehäuse. Links das USB-Kabel zum Linux-Rechner, rechts das IEC-Kabel zur 1571:

xum1541 USB-Adapter im gelben 3D-gedruckten Gehäuse mit USB- und IEC-Kabel angeschlossen

Und ein Blick auf die Platine mit dem Teensy2-Board (ATmega32U4), in dem der Firmware-Bug steckte:

Geöffneter xum1541-Adapter mit Teensy2-Board (ATmega32U4) auf der Platine, USB-Anschluss und IEC-DIN-Buchse

Disk 001: Pirates! und das Kopierschutz-Problem

Die erste Disk war eine Pirates!-Kopie (Microprose, 1987), „imported by The Critters Inc 1221“. Mit d64copy ausgelesen, 683 Blocks, keine Fehler. Dann zurückgeschrieben und zur Verifikation nochmal gelesen. Checksummen stimmten nicht überein.

Die Analyse ergab: Das Original-D64 enthält drei Sektoren mit Error Code 5 (Data Block Checksum Error) auf Track 23 und 24. Das ist klassischer C64-Kopierschutz. Microprose nutzte absichtliche Lesefehler, um Raubkopien zu erkennen. Das Spiel prüft beim Start ob diese Fehler vorhanden sind, fehlen sie, verweigert es den Dienst.

d64copy arbeitet auf Sektor-Ebene und kann solche GCR-Level-Fehler nicht reproduzieren. Die Error-Info wird zwar im D64 gespeichert (Emulatoren wie VICE werten sie aus), aber auf der physischen Disk gehen die absichtlichen Fehler beim Zurückschreiben verloren. Für eine echte 1:1-Kopie inklusive Kopierschutz braucht man nibtools. Das arbeitet direkt auf GCR/Nibble-Ebene und liest die Rohdaten vom Laufwerk, inklusive aller Timing-Patterns und absichtlichen Fehler.

nibtools bauen und der erste Crash

nibtools liegt als Quellcode im OpenCBM-Quellbaum, muss aber separat gebaut werden. Ich habe den markusC64-v637 Branch von GitHub genommen. Build mit dem cc65 Cross-Compiler für den 6502-Floppy-Code und gcc für die Host-Tools ging glatt. Erster Versuch:

nibread -D8 image.nib

Ergebnis: LIBUSB_ERROR_PIPE. Der USB-Transfer bricht sofort ab, nachdem der Drive-Code hochgeladen ist. nibtools erkennt die 1571 korrekt und versucht SRQ-Burst-Transfers zu nutzen, ein schnelles serielles Protokoll das die CIA-UART der 1571 verwendet. Aber der Transfer scheitert schon beim Communication-Test.

Drei Schichten tief: der Firmware-Bug

Schicht 1: Bekannter SRQ-Bug in Firmware v7. Die xum1541-Firmware v7 hatte einen dokumentierten Bug: IEC_SRQ war als 0x80 definiert (Bit 7), aber die Lookup-Tabelle iec2hw_table hatte nur 16 Einträge (4 Bits). SRQ-Operationen griffen ins Leere. In v8 gefixt: IEC_SRQ auf 0x10 geändert, Tabelle auf 32 Einträge erweitert. Commit 3ef4fc0d von Spiro Trikaliotis, 2021.

Problem: Es gab kein fertiges v8-Hex für das TEENSY2-Board. Nur für ZOOMFLOPPY und PROMICRO. Die Boards haben unterschiedliche Mikrocontroller-Pin-Belegungen, also kann man die Firmware nicht einfach zwischen Boards tauschen. Lösung: AVR-Toolchain installiert (gcc-avr, avr-libc), v8 für TEENSY2 selbst gebaut und über den HalfKay-Bootloader geflasht.

teensy_loader_cli --mcu=atmega32u4 -w -v firmware.hex

Risikofrei, da der Bootloader in einem geschützten Flash-Bereich sitzt. Knopf am Teensy drücken, flashen, fertig.

Schicht 2: v8 geflasht, gleiches Problem. Auch mit v8 kommt LIBUSB_ERROR_PIPE. Die OpenCBM-Library musste ebenfalls neu gebaut werden, sie prüft die Firmware-Version und war noch auf v7 kompiliert. Neu gebaut, installiert. Immer noch Crash.

Schicht 3: Der eigentliche Bug. Also tiefer in den Quellcode. In board-teensy2.h, Funktion iec_srq_write():

// BUGGY — seit Commit 57bb6726 (April 2020)
PORTD = (((data >> 4) & IO_DATA) ^ IO_DATA) | IO_SRQ;

Das wurde 1:1 von der ZoomFloppy-Implementierung kopiert. Aber die Pin-Belegung ist bei den Boards unterschiedlich:

  • ZoomFloppy hat IO_DATA auf Port D, Bit 4 (PD4)
  • TEENSY2 hat IO_DATA auf Port F, Bit 0 (PF0)

Der Code schrieb auf den komplett falschen Port mit dem falschen Bit-Shift. Das erklärt warum der Communication-Test sofort fehlschlug. Die SRQ-Daten kamen nie auf den richtigen Pins an.

Der Fix, analog zur korrekten PROMICRO-Implementierung:

// FIXED
uint8_t port_base_data = (DDRF & IO_ATN) | IO_SRQ;
// ...
DDRF = (((data >> 7) & IO_DATA) ^ IO_DATA) | port_base_data;

Die Änderungen im Detail: PORTD wird zu DDRF (richtiger Port für die IEC-Leitungen beim TEENSY2), der Shift von data >> 4 auf data >> 7 (Bit 7 des Datenbytes auf Bit 0 des Ports, wo IO_DATA liegt), und der ATN-Zustand wird über port_base_data erhalten, was vorher nicht berücksichtigt war. Timing von 0,935 µs auf 0,80 µs angepasst, passend zur PROMICRO-Implementierung.

Firmware neu gebaut (8260 Bytes, 32 mehr als vorher), geflasht. nibread läuft sofort fehlerfrei durch alle 41 Tracks. Der Bug steckte seit April 2020 im Code. Jeder mit einem TEENSY2-basierten xum1541 hatte dieses Problem bei SRQ-Transfers.

Den Fix habe ich als Pull Request eingereicht, der am 26. März vom OpenCBM-Maintainer Spiro Trikaliotis gemerged wurde. Damit ist auch ein seit 2021 offenes Issue im nibtools-Repository endlich geschlossen. Dort hatten andere User auf macOS und Fedora mit Teensy-basierten Adaptern exakt die gleichen LIBUSB-Fehler gemeldet, ohne dass die Ursache gefunden wurde.

Die bittere Lektion mit Disk 001

Die erste Pirates!-Disk, der Import von The Critters Inc, war zu diesem Zeitpunkt bereits zerstört. Ich hatte sie vor dem Fix mit d64copy zurückgeschrieben. Das hat die GCR-Level-Kopierschutzmuster überschrieben. Das anschließend mit nibread erstellte NIB-Image zeigt nur noch die „reparierten“ Sektoren, nicht den originalen Kopierschutz. Disk und Images entsorgt.

Die Lektion ist simpel und ärgerlich zugleich: Nie zurückschreiben, bevor das NIB-Image existiert.

Der Workflow ab Disk 002

Ab der zweiten Disk lief der Prozess dann sauber:

  1. nibread -D8 — GCR-Rohdaten lesen, inklusive Kopierschutz
  2. d64copy — Sektor-Level-Image für Emulatoren
  3. nibwrite — 1:1 zurückschreiben aus dem NIB (erhält Kopierschutz)
  4. d64copy nochmal lesen + MD5-Vergleich zur Verifikation

Ergebnisse

DiskInhaltStatus
001Pirates! (The Critters Inc)Verloren — Kopierschutz vor dem Fix zerstört
002Ace of Aces, Light Force, Hacker + TrainersGesichert + aufgefrischt, Killer Track auf Track 1 erhalten
003Commando, The Last V8, Robin of the WoodVerloren — Medium physisch zu schwer beschädigt
004Warplay, Worldcup 86, Hyper OlympicsGesichert, Original-Disk defekt (T18/S15)
005Pirates! (The Red Lions Import, 2-Disk)Gesichert + aufgefrischt + verifiziert

Technische Eckdaten

Für die Leute die es genau wissen wollen:

  • Hardware: 2× Commodore 1571, xum1541 (TEENSY2, ATmega32U4), Linux-Host
  • Software: OpenCBM (from source), nibtools (markusC64-v637), VICE 3.7.1
  • RPM: Konstant 300,5 RPM (Nominal: 300). Die 1571 ist elektronisch geregelt, kein Trimmpoti
  • Kopierschutz-Typen: Error Code 5 (Checksum Errors) auf Pirates!, Killer Track (Track komplett mit Sync-Bytes) auf der Crocodile Soft Compilation
  • NIB-Format: ~336 KB pro Disk (41 Tracks × 8192 Bytes GCR-Rohdaten)
  • D64-Format: ~175 KB pro Disk (683 Sektoren × 256 Bytes + optional 683 Bytes Error-Info)

Fazit

Was als „schnell mal Disketten auffrischen“ geplant war, endete in einer Reise durch sechs Jahre alten Firmware-Code. Der Bug in iec_srq_write() war ein klassischer Copy-Paste-Fehler, der nie aufgefallen ist, weil kaum jemand nibtools mit einem TEENSY2-Board benutzt. SRQ-Burst-Transfers braucht man nur für nibtools, und die meisten Leute nutzen ohnehin einen ZoomFloppy-Adapter, wo der Code korrekt ist.

Der Verlust von Disk 001 ärgert mich immer noch. Aber die Lektion sitzt: Erst NIB, dann zurückschreiben. Und wenn ein Tool beim ersten Mal nicht funktioniert, lohnt es sich manchmal die Firmware aufzuschrauben, statt das Tool wegzulegen.

Der Blick ins Regal, wo das alles steht. Ja, es ist voll da unten:

Retro-Computing-Regal mit Commodore-Monitor, 1571 Laufwerk, C128 Tastatur, Diskettenstapeln und dem gelben xum1541-Adapter
Zweite Perspektive des Retro-Regals mit Commodore 1541-II, Disketten- und Kassettensammlung

Siehe auch: Commodore – PC Projekt (mein erster Versuch mit cbm4linux und einem XM1541-Kabel, anno 2009) und VC-64 Turbo Tape (1986).

Fragen? Einfach melden.

Voltcraft CM 2016: Endlich eine Linux-GUI für das Ladegerät

Seit bestimmt zehn Jahren steht hier ein Voltcraft Charge Manager CM 2016 auf dem Schreibtisch. Irgendwann bei Conrad gekauft, als die tatsächlich noch Geschäfte in der Innenstadt hatten. Damals mit zwei kleinen Kindern war der Akkuverbrauch enorm. Spielzeugautos, Taschenlampen, Fernbedienungen, irgendwas war immer leer. Einwegbatterien waren teurer als heute (zumindest in meiner Erinnerung), und so wurde das Ladegerät schnell zum wichtigsten Gerät im Haushalt.

Das CM 2016 hat sechs unabhängige Ladeschächte (vier für AA/AAA, zwei für 9V-Blöcke) und kann deutlich mehr als nur Laden. Es misst Kapazitäten, erkennt defekte Akkus, kann Lade-/Entladezyklen fahren und hält Akkus per Trickle-Charge am Leben. Wer seine Akkus ernsthaft pflegen will, braucht so ein Gerät. Damit halten die Zellen länger, man kann sie wiederaufbereiten und erkennt rechtzeitig, wann einer reif für die Tonne ist.

Voltcraft Charge Manager CM 2016 Frontansicht mit Display und eingelegtem Akku
Der Voltcraft Charge Manager CM 2016 mit eingelegtem Akku

In den letzten Jahren wurde es zugegebenermaßen weniger eingesetzt. Trotzdem laufen noch immer diverse Smarthome-Geräte und Notfall-Taschenlampen mit Akkus, und da ist ein ordentliches Ladegerät einfach Pflicht.

Das Problem: kein Linux, kein gar nichts

Das CM 2016 kommt mit einer Windows-Software. CM2016 Logger V2.10, eine .NET-Anwendung von 2013. Unter Linux funktioniert die selbstverständlich nicht. Es gibt ein paar Projekte, die das Gerät auf der Kommandozeile auslesen können, ein Java-Tool hier, ein Python-Script dort. Eine echte GUI für Linux oder FreeBSD? Fehlanzeige. Selbst als ich vor ein paar Tagen noch einmal gesucht habe: nichts. Eine kommerzielle Java-GUI existiert zwar, aber nur als 30-Tage-Trial.

Also habe ich mich selbst daran gesetzt.

Das Ergebnis: eine native GTK4-Anwendung

Das Ergebnis ist eine vollständige Desktop-Anwendung in Python mit GTK4 und libadwaita. Quelloffen, MIT-lizenziert, auf GitHub:

https://github.com/Kernel-Error/voltcraft-cm2016

Voltcraft CM 2016 GUI: Hauptfenster mit Datentabelle und Live-Aufzeichnung
Hauptfenster mit Datentabelle während einer Live-Aufzeichnung

Die App erkennt das CM 2016 automatisch per USB (Silicon Labs CP210x Chip) und zeigt alle sechs Schächte in Echtzeit an. Alle zwei Sekunden kommen neue Messdaten rein: Spannung, Strom, Kapazität, Laufzeit, Programmstatus.

Was die App kann

  • Echtzeit-Überwachung aller 6 Ladeschächte mit Autoscroll und Slot-Filterung
  • Spannungs- und Strom-Diagramme als Linien- oder Balkendiagramm mit Zeitfenster-Steuerung
  • Chart-Zoom per Maus-Drag, Scrollrad oder Tastatur, dazu Daten-Tooltips
  • Export als CSV oder Spreadsheet (.xlsx mit eingebetteten Diagrammen)
  • Druckfunktion für Messprotokolle im DIN A4 Querformat
  • Speichern und Laden von Aufzeichnungen (.cm2016 Dateien), inklusive Crash-Recovery über Temp-Dateien
  • Sleep-Inhibit: das System schläft nicht ein, solange aufgezeichnet wird
  • 7 Sprachen: Deutsch, Englisch, Französisch, Niederländisch, Italienisch, Spanisch, Polnisch
Voltcraft CM 2016 GUI: Spannungs- und Strom-Diagramme
Liniendiagramme für Spannung und Strom über die Zeit
Voltcraft CM 2016 GUI: Balkendiagramm
Balkendiagramm-Ansicht
Voltcraft CM 2016 GUI: Port-Auswahl Dialog
Port-Auswahl mit automatischer Geräteerkennung

Das Protokoll: nicht ganz so dokumentiert wie gedacht

Das CM 2016 sendet alle zwei Sekunden einen 127-Byte-Frame über die serielle Schnittstelle (19200 Baud, 8N1). Die ersten sieben Bytes sind immer CM2016 , dann folgen zehn Bytes Header und je 18 Bytes pro Ladeschacht.

Klingt einfach. Ist es auch, bis man die existierende Dokumentation mit echten Messdaten vergleicht. Dabei sind mir ein paar Dinge aufgefallen, die so nirgendwo korrekt dokumentiert waren:

  • Kapazitätsfelder sind 32-Bit Little-Endian, nicht 24-Bit wie es in mehreren Quellen steht. Charge-Capacity und Discharge-Capacity belegen jeweils vier Bytes.
  • Der dokumentierte Byte-Swap für Discharge-Capacity war falsch. Mehrere Referenzprojekte haben die Bytes in der falschen Reihenfolge gelesen, was zu absurden Kapazitätswerten geführt hat.
  • Die Header-Bytes 7-16 waren bisher größtenteils undokumentiert. Tatsächlich stecken da die Firmware-Version, die eingestellte Akku-Chemie (NiMH/NiZn), Temperaturdaten und ein Action-Counter drin. Alles Big-Endian, im Gegensatz zu den Slot-Daten, die Little-Endian sind.
  • Die Kapazitätsskalierung hängt vom Slot-Typ ab: Slots 1-4 (AA/AAA) teilen durch 100, die beiden 9V-Slots teilen durch 1000. Gleiches gilt für den Strom: AA/AAA-Slots durch 1000, 9V-Slots durch 10000.

Das alles musste mit dem echten Gerät verifiziert werden. Akku rein, verschiedene Programme durchlaufen lassen, Rohwerte mit dem Display vergleichen. Klassisches Reverse Engineering, nur eben mit Ladeströmen statt mit Netzwerkpaketen.

Technik unter der Haube

Die Anwendung nutzt GTK4 mit libadwaita für eine zeitgemäße GNOME-Oberfläche. Dark Mode funktioniert automatisch. Die Diagramme werden mit Cairo gerendert, Benachrichtigungen laufen über den libadwaita ToastOverlay. Für den seriellen Zugriff kommt pyserial zum Einsatz, die CP210x-Erkennung läuft über die USB Vendor/Product ID von Silicon Labs.

Der Spreadsheet-Export erzeugt .xlsx-Dateien mit eingebetteten Diagrammen über openpyxl. Die Druckfunktion generiert DIN A4 Querformat mit allen Slots und Diagrammen. Sessions lassen sich als .cm2016-Dateien speichern und wieder laden, und falls die Anwendung während einer Aufzeichnung abstürzt, gibt es eine automatische Recovery über Temp-Dateien.

Insgesamt 135 Unit-Tests decken Parser, Protokoll und die Export-Funktionen ab.

Installation

Die App braucht GTK 4.14+ und libadwaita 1.5+. Unter Debian/Ubuntu/Mint:

sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-4.0 gir1.2-adw-1
git clone https://github.com/Kernel-Error/voltcraft-cm2016.git
cd voltcraft-cm2016
python3 -m venv --system-site-packages .venv
source .venv/bin/activate
pip install -e .

Unter Fedora:

sudo dnf install python3-gobject gtk4 libadwaita

Unter Arch:

sudo pacman -S python-gobject gtk4 libadwaita

Dann einfach cm2016 starten, USB-Kabel anschließen, fertig.

Ein .deb-Paket gibt es auf der GitHub Releases Seite. Ein Flatpak-Manifest liegt im Repository, die Einreichung bei Flathub ist eingereicht.

Falls jemand das gleiche Gerät hat und Fragen zur App oder zum Protokoll hat, einfach fragen.

Siehe auch: NB-2033-U: Reverse Engineering eines Fingerabdrucklesers für Linux

NEXT Biometrics NB-2033-U: Reverse Engineering eines Fingerabdrucklesers für Linux

Illustration eines USB-Fingerabdrucklesers mit Linux-Tux und USB-Protokollanalyse (Reverse Engineering NB-2033-U)

Im letzten Beitrag zum Thema hatte ich angekündigt, dass ich mir auch den NB-2033-U vornehmen will. Der steckt in einem zweiten Fujitsu Notebook hier, dem von meiner Tochter Maja. Gleicher Hersteller, gleiche Sensorfamilie, sollte ähnlich laufen wie beim NB-2020-U. Dachte ich.

Falsch gedacht.

Hersteller sagt: geht nicht

Ich hatte bei NEXT Biometrics nach Protokolldokumentation oder einem SDK für den NB-2033-U gefragt. Kevin Hung, Director FAE, antwortete freundlich aber eindeutig:

„Both 2020-U and 2033-U have different firmware and USB stack. The code flow (libusb) related to 2033-U and 2020-U is different. This could be the reason for 2033-U failure/unsupported in linux. As of now, it is not supported.“

Kein SDK, keine Doku, kein Support. Und 74 Einträge auf linux-hardware.org mit Status „failed“ für die USB ID 298d:2033. Weltweit kein Linux-Support für dieses Gerät.

Gut. Dann eben Reverse Engineering.

Erster Versuch: Windows-Treiber belauschen

Plan A war klassisch: Windows-Treiber in einer VM laufen lassen, USB-Traffic mitschneiden. VirtualBox installiert, USB-Passthrough konfiguriert, Windows gestartet. Der Fingerabdruckleser tauchte im Gerätemanager auf. Mit Code 31. Treiber konnte das Gerät nicht starten. Secure Boot hatte VirtualBox den Kernel-Treiber nicht signiert, und der USB-Passthrough war damit unbrauchbar.

Plan A verworfen.

Plan B: Das SDK direkt auf Linux

Das SDK von NEXT Biometrics (libNBBiometrics.so) unterstützt den NB-2033-U intern. Es kommuniziert direkt über libusb, ohne Kernel-Treiber. Das heißt: ich kann das SDK-Sample direkt auf dem Linux-Notebook laufen lassen und gleichzeitig den USB-Traffic mit usbmon mitschneiden.

Dafür musste Secure Boot deaktiviert werden. usbmon ist ein Kernel-Modul, und lockdown=integrity (von Secure Boot gesetzt) blockiert es auch für root. Secure Boot im BIOS aus, lockdown=none in GRUB, Neustart. Danach:

modprobe usbmon
cat /sys/kernel/debug/usb/usbmon/3u > /tmp/capture.txt &
./NBBSample

7654 Zeilen USB-Traffic. Das komplette Protokoll des NB-2033-U, aufgezeichnet während einer Enrollment-Session.

Was dabei rauskam

Das Protokoll ist komplett anders als beim NB-1010-U/NB-2020-U. Kevins Aussage stimmte. Hier die wesentlichen Unterschiede:

EigenschaftNB-1010-U / NB-2020-UNB-2033-U
Bulk IN EndpointEP 3 (0x83)EP 1 (0x81)
Kommandoformat[0x80][CMD][SEQ][0x00]...[CMD][0x00][LEN_LO][LEN_HI][PAYLOAD] (TLV)
Finger-ErkennungEinzelnes 0x38Zwei 0x0D Config + 0x38
Bildübertragung90 Chunks à 540 Bytes180 Chunks à 268 Bytes
InitEinmal 0x07Zweimal 0x07 nötig

Gleicher Sensor-Die (256×180 Pixel, 385 DPI, aktiv thermisch), aber ein komplett anderer USB-Stack. Der NB-2033-U nutzt ein TLV-Format (Type-Length-Value) statt des festen Kommandoschemas vom NB-1010-U. Jedes Kommando hat eine eigene Längenangabe, und die Antworten sind anders strukturiert.

Die Kommandos im Detail

Aus dem USB-Capture konnte ich sechs Kommandos identifizieren:

  • 0x07 — Init/Wake. Muss zweimal gesendet werden, sonst reagiert der Sensor nicht.
  • 0x0D — Sensor-Konfiguration. Wird zweimal vor jeder Finger-Erkennung gebraucht, um den „Enhanced“ Modus zu aktivieren.
  • 0x38 — Finger-Erkennung. Byte 4 der Antwort ist der Detect-Level. Schwellwert 40.
  • 0x12 — Capture starten. Liefert 180 Zeilen à 256 Pixel, 8-Bit Graustufen.
  • 0x13 — Geräteinformationen (Hersteller, Modell, Seriennummer).
  • 0xF7 — Firmware-Version.

Thermischer Sensor: Eigenheiten

Der Sensor misst Temperaturänderungen, nicht statischen Kontakt. Das klingt nach einem Detail, ist aber für die Treiber-Implementierung entscheidend. Finger auflegen erzeugt einen kurzen Spike im Detect-Wert (10 bis 50+). Finger bleibt liegen, und der Wert fällt zurück auf Basisniveau. Der Treiber muss also den Spike erkennen, nicht einen dauerhaften Zustand.

Dazu kommt: Nach dem Init gibt es transiente Spikes, die ungefähr 1,5 Sekunden brauchen, bis sie abklingen. Ohne Settle-Pause nach dem Init erkennt der Treiber Phantom-Finger.

Der Treiber

Rausgekommen ist nb2033.c, ein eigenständiger libfprint-Treiber mit rund 350 Zeilen. Kein proprietärer Code, keine SDK-Abhängigkeit. Das SDK diente nur als Referenz für die Capture-Analyse, der Treiber ist sauber von Grund auf geschrieben. Lizenz: LGPL 2.1+ wie alle libfprint-Treiber.

Die State Machine:

  1. Init (0x07 × 2) mit 1,5 Sekunden Settle-Pause
  2. Finger-Detect-Polling (0x0D + 0x0D + 0x38, Schwellwert 40)
  3. Pre-Capture Config (0x0D)
  4. Capture (0x12) mit 150 ms Pause, dann 180 Zeilen lesen
  5. Bild an libfprint übergeben

Test

Getestet auf Majas Fujitsu Notebook mit Linux Mint 22.3:

$ fprintd-enroll
Using device /net/reactivated/Fprint/Device/0
Enrolling right-index-finger finger.
Enroll result: enroll-stage-passed
[... 5/5 Stages ...]
Enroll result: enroll-completed
$ fprintd-verify
Using device /net/reactivated/Fprint/Device/0
Listing enrolled fingers:
 - #0: right-index-finger
Verify result: verify-match (true)

Richtiger Finger: Match. Falscher Finger: No Match. Enrollment sauber, Verifikation zuverlässig.

Upstream

Der Merge Request ist eingereicht: MR !574 bei libfprint. Fünf Dateien: der neue Treiber, meson.build, autosuspend.hwdb und die Allowlist. CI läuft durch. Der verwandte MR !569 für den NB-2020-U ist noch in Review.

Für die Wiki-Aktualisierung (das Gerät von der „unsupported“ Liste nehmen) gibt es Issue #134.

Fazit

Der Hersteller sagt „not supported“, 74 Linux-User melden „failed“, und trotzdem war das an einem Nachmittag erledigt. SDK auf Linux ausführen, USB-Traffic mitschneiden, Protokoll rekonstruieren, Treiber schreiben, testen, upstream einreichen. Alles mit Open-Source-Tools: usbmon, libusb, libfprint.

Das Ergebnis: Majas Notebook hat jetzt einen funktionierenden Fingerabdruckleser unter Linux. Und sobald der Merge Request durch ist, haben ihn alle anderen auch.

Wie immer: Bei Fragen, fragen.

peon-ping — Sound-Benachrichtigungen für Claude Code (und andere AI-Agents)

Wer mit AI-Coding-Agents arbeitet, kennt das Spiel. Claude Code läuft, macht sein Ding — und man sitzt daneben und wartet. Oder man wechselt kurz den Fokus, verpasst die Rückfrage und wundert sich zehn Minuten später, warum nichts mehr passiert. Terminal-Babysitting in Reinform.

Ein Bekannter hat mir dann peon-ping empfohlen. Kurz ausprobiert — direkt behalten. Danke dafür!

Was ist peon-ping?

peon-ping ist ein kleines Open-Source-Tool (MIT-Lizenz), das Sound-Benachrichtigungen für AI-Coding-Agents nachrüstet. Der Name ist Programm — im Default-Modus hört man den Peon aus Warcraft III. „Ready to work?“ wenn eine Session startet, „Work, work.“ wenn eine Aufgabe fertig ist, „Something need doing?“ wenn der Agent eine Eingabe braucht. Und wenn man zu schnell hintereinander Prompts abfeuert: „Me busy, leave me alone!“

peon-ping

Das Tool unterstützt nicht nur Claude Code, sondern auch Cursor, Codex, Windsurf, Kiro, GitHub Copilot und diverse andere Agents. Für Claude Code erfolgt die Integration über den nativen Hook-Mechanismus — es werden automatisch Hooks in ~/.claude/settings.json registriert.

Warum das Sinn ergibt

Das Problem ist simpel: Man startet Claude Code mit einer Aufgabe, wechselt in den Browser oder ein anderes Terminal — und verpasst den Moment, in dem der Agent fertig ist oder eine Frage hat. Ohne Feedback sitzt man entweder da und starrt auf den Output, oder man verliert Zeit, weil der Agent längst auf Eingabe wartet.

peon-ping löst das mit akustischem Feedback. Verschiedene Sounds für verschiedene Events — Task fertig, Fehler aufgetreten, Eingabe nötig, Rate-Limit erreicht. Dazu optional Desktop-Notifications als visuelles Overlay und sogar Push-Benachrichtigungen aufs Handy via ntfy.sh. Man kann also ruhig den Fokus wechseln und weiß trotzdem immer, was der Agent gerade treibt.

Installation unter Linux

Die Installation ist erfrischend simpel. Ein Einzeiler:

curl -fsSL peonping.com/install | bash

Alternativ gibt es auch Homebrew (brew install PeonPing/tap/peon-ping) oder Nix. Nach der Installation einmal das Setup laufen lassen:

peon-ping-setup

Das Setup registriert die Hooks in eurer Claude-Code-Konfiguration und installiert das Default-Sound-Pack. Fertig. Beim nächsten Start von Claude Code solltet ihr den Peon hören.

Für die Audio-Wiedergabe unter Linux nutzt peon-ping automatisch pw-play (PipeWire), paplay (PulseAudio), ffplay oder mpv — je nachdem, was verfügbar ist. Desktop-Notifications laufen über notify-send.

Konfiguration

Die Konfiguration liegt in ~/.claude/hooks/peon-ping/config.json. Die wichtigsten Optionen:

{
  "volume": 0.5,
  "enabled": true,
  "desktop_notifications": true,
  "default_pack": "peon",
  "pack_rotation": ["peon", "sc_kerrigan"],
  "pack_rotation_mode": "random"
}

volume regelt die Lautstärke (0.0 bis 1.0), desktop_notifications schaltet die visuellen Overlay-Benachrichtigungen ein oder aus, und pack_rotation lässt euch mehrere Sound-Packs im Wechsel abspielen — entweder zufällig oder reihum (round-robin). Man kann sogar Packs an bestimmte Projektverzeichnisse binden — GLaDOS für die Arbeit, Peon fürs Hobby.

Per CLI geht das Meiste auch schnell zwischendurch:

peon volume 0.3          # Leiser
peon pause               # Stummschalten
peon resume              # Wieder an
peon status              # Aktueller Zustand

Wer Claude Code nutzt, bekommt außerdem Slash-Commands: /peon-ping-toggle zum Stummschalten, /peon-ping-config für interaktive Einstellungen und /peon-ping-use <pack> zum Wechseln des Sound-Packs in der laufenden Session.

Sound Packs

Und hier wird es lustig. Auf openpeon.com gibt es über 164 Sound-Packs. Der Warcraft-Peon ist der Default, aber es gibt so ziemlich alles: GLaDOS aus Portal, Kerrigan aus StarCraft, den TF2 Engineer, Duke Nukem, Sheogorath aus Elder Scrolls, den Dude aus The Big Lebowski — sogar ein cleanes Chimes-Pack ohne Sprachlinien, falls man es dezenter mag.

Packs installieren und wechseln geht über die CLI:

peon packs list --registry      # Verfügbare Packs anzeigen
peon packs install glados       # GLaDOS installieren
peon packs use glados           # GLaDOS aktivieren
peon packs install --all        # Alle installieren (wenn man sich nicht entscheiden kann)

Die Packs basieren auf der offenen CESP-Spezifikation (Coding Event Sound Pack) — wer eigene Sounds mitbringen will, kann sich relativ einfach ein eigenes Pack bauen.

Fazit

peon-ping ist klein, kostenlos, Open Source (MIT) und löst ein echtes Problem. Kein Terminal-Babysitting mehr, keine verpassten Rückfragen. Und ja — es macht einfach Spaß, wenn der Peon einem bestätigt, dass die Arbeit erledigt ist. „Work complete.“

Nochmal Danke an den Bekannten für den Tipp. Manchmal sind es die kleinen Tools, die den größten Unterschied machen.

Links:

GitHub: github.com/PeonPing/peon-ping
Sound Packs: openpeon.com
Website: peonping.com

Nutzt ihr AI-Coding-Agents im Alltag? Wie haltet ihr es mit Benachrichtigungen — oder sitzt ihr auch und starrt auf den Output? Schreibt mir gerne, ich bin gespannt.

NEXT Biometrics NB-2020-U Fingerabdruckleser unter Linux zum Laufen gebracht

In meinem Fujitsu Notebook steckt ein Fingerabdruckleser. Ein NEXT Biometrics NB-2020-U, USB ID 298d:2020. Unter Windows funktioniert er, unter Linux nicht. Kein Treiber, kein Support, nichts. Das Gerät taucht in lsusb auf, wird aber von keinem Treiber erkannt. Im libfprint Wiki steht es auf der Liste der nicht unterstützten Geräte. Dort steht es schon eine Weile.

Das hat mich gestört.

Picture of NB-2020-U

libfprint kennt den NB-1010-U. Das ist ein externer USB Fingerabdruckleser von NEXT Biometrics, der seit einiger Zeit einen funktionierenden Treiber hat. Der NB-2020-U ist die eingebettete Variante desselben Sensors, gedacht für den Einbau in Notebooks. Wenn man sich Teardown Reports ansieht, etwa von System Plus Consulting oder Yole Group, dann stellt man fest: Beide Geräte verwenden den identischen Sensor Die. Gleiche Technik, anderes Gehäuse.

Das war der erste Anhaltspunkt. Wenn die Hardware gleich ist, sollte auch das USB Protokoll gleich sein. Und wenn das Protokoll gleich ist, sollte der vorhandene Treiber funktionieren.

Bevor ich aber einfach auf Verdacht losprogrammiert habe, wollte ich es absichern. Ich habe NEXT Biometrics direkt angeschrieben. Kevin Hung, Director FAE bei NEXT Biometrics, hatte mir bereits 2022 auf eine Anfrage zu Linux Treibern geantwortet. Damals war sein Vorschlag, über Fujitsu zu gehen. Das führte ins Leere. Diesmal habe ich konkret angeboten, selbst einen libfprint Treiber zu schreiben, und um das SDK gebeten.

Kevin hat mir daraufhin das NBBiometrics ANF SDK 3.0.0.1384 zugeschickt. Ein komplettes SDK mit Headern, Bibliotheken, Beispielcode und Dokumentation. Das war sehr hilfreich, denn die Header bestätigen einiges. Das SDK nutzt eine einzige Shared Library libNBBiometrics.so für alle Gerätetypen. Der NB-1010-U hat den internen Gerätetyp 200, der NB-2020-U den Typ 202. Beide verwenden dasselbe Scanformat: 180×256 Pixel bei 385 DPI. Die USB Vendor ID ist bei beiden 0x298d, nur die Product ID unterscheidet sich: 0x1010 beim einen, 0x2020 beim anderen.

Wichtig: Das SDK ist proprietär. Für den eigentlichen Treiber habe ich keinen Code daraus verwendet. libfprint akzeptiert nur sauberen, eigenständig entwickelten Code. Das SDK diente ausschließlich als Referenz, um die Protokollkompatibilität zu bestätigen.

Also habe ich es einfach ausprobiert. Den bestehenden nb1010.c Treiber genommen, die USB Product ID 0x2020 zur id_table hinzugefügt und gebaut. Dann auf dem Fujitsu Notebook getestet.

Es funktionierte sofort.

Geräteerkennung, USB Interface Claim, die State Machine für die Fingererkennung, alles lief auf Anhieb. fprintd-enroll hat Fingerabdrücke aufgenommen, fprintd-verify hat sie korrekt verifiziert. Der bestehende Treibercode brauchte keinerlei Anpassungen. Null. Nur die PID in der Tabelle und den Gerätenamen.

Ein Blick auf die USB Deskriptoren bestätigt das Bild. Der NB-2020-U hat exakt dasselbe Endpoint Layout wie der NB-1010-U: Bulk OUT auf Endpoint 0x02, Bulk IN auf Endpoint 0x83. Dazu kommt ein Interrupt Endpoint auf 0x81, den der Treiber nicht verwendet. Die Kommunikation läuft identisch ab.

Der Patch selbst ist entsprechend klein. Drei Dateien, drei Zeilen rein, drei Zeilen raus:

  1. libfprint/drivers/nb1010.c: Die neue PID 0x2020 wird in die id_table eingetragen und der full_name auf "NextBiometrics NB-1010-U/NB-2020-U" erweitert.
  2. data/autosuspend.hwdb: Der Eintrag 298d:2020 wird von der Liste der nicht unterstützten Geräte in die Sektion des nb1010 Treibers verschoben.
  3. libfprint/fprint-list-udev-hwdb.c: Der Eintrag wird aus der Allowlist der nicht unterstützten Geräte entfernt, da er jetzt vom Treiber abgedeckt wird.

Den Merge Request habe ich bei libfprint upstream eingereicht: MR !569. Die CI Pipeline läuft durch, alle 124 Tests bestehen. Jetzt heißt es warten auf das Review durch die Maintainer.

Für alle, die denselben Fingerabdruckleser in ihrem Notebook haben: Sobald der Patch gemergt und in einer neuen libfprint Version enthalten ist, funktioniert der Sensor out of the box. Enrollment und Verifikation über fprintd laufen sauber. Wer nicht warten möchte, kann den Patch auch jetzt schon selbst auf ein aktuelles libfprint anwenden.

Im selben Fujitsu Notebook meiner Tochter steckt ein NB-2033-U, ein weiterer Fingerabdruckleser aus der gleichen Familie. Der verwendet allerdings ein komplett anderes Protokoll und ließ sich nicht einfach mit dem nb1010 Treiber ansprechen. Den habe ich per Reverse Engineering geknackt.

Ist mein Netzwerk kompromittiert? Warum das kaum jemand merkt

Ich habe ja bereits etwas zum Thema IoT-Geräte geschrieben und warum diese oft deutlich schneller gehijackt werden, als man vielleicht erwartet.

Aber woher weiß man nun als normaler Anwender, ob zu Hause oder im eigenen Netzwerk etwas sein Unwesen treibt?
Nun ja; das ist leider überhaupt nicht so einfach.

Symbolische Darstellung eines kompromittierten Netzwerks mit Warnhinweisen, IoT-Kamera und verdächtigem Datenverkehr.

Klar, man kann sich ganz tolle IPS oder IDS aufbauen. Es gibt dafür auch Open-Source-Systeme; Snort fällt mir da als einer der älteren Vertreter als erstes ein.

Aber das alles ist nichts für den normalen Anwender oder den Privathaushalt. Dann gibt es noch ganz furchtbar viele Schlangenölanbieter mit ihrer „Sicherheitssoftware“ für Windows, Android und Co. Klar, man kann dort Firewall, Virenscanner usw. installieren. Aber hilft das wirklich? Jein, würde ich dazu sagen.

Ist man auf einem aktuellen Patchstand, sollten zumindest die bekannten Löcher geschlossen sein. Dann bleiben fast nur noch Zero-Day-Lücken Ein Virenfilter kennt diese in der Regel auch nicht und lässt so etwas dann schlicht durch.

Eine Firewall-Lösung kann zumindest erkennen, ob plötzlich ungewöhnlicher Traffic unterwegs ist oder ob versehentlich gestartete Dienste nach außen offen stehen. Nur steht und fällt das Ganze oft genau in dem Moment, in dem der Anwender nach einer Entscheidung gefragt wird.

Sicherheitssoftware muss naturgemäß sehr tief im Betriebssystem eingebettet werden. Hat diese Sicherheitssoftware dann selbst Sicherheitslücken, was deutlich häufiger vorkommt, als man zunächst glauben möchte, öffnet man im Zweifel die eigene Infrastruktur über genau die Software, die das eigentlich verhindern soll. Vertraut mir da bitte einfach, wenn ich sage, dass ich das schon sehr oft gesehen habe. Zudem installiert sich so eine Sicherheitssoftware oft nicht einfach auf einer Netzwerkkamera.

Der beste Schutz sind, meiner Meinung nach, noch immer gepflegte Systeme, gute Zugangsdaten und das nötige Misstrauen. Wie kam ich jetzt darauf? Ach richtig; wie findet man eigentlich heraus, ob es überhaupt ein Problem gibt?

Klar, man kann abwarten. Irgendwann merkt man es sicher; spätestens dann, wenn die Polizei mit einer Hausdurchsuchung vor der Tür steht und wissen möchte, was man denn da so alles im Internet verteilt oder angreift.

Eine wirklich gute Lösung habe ich da leider auch nicht. Am ehesten noch Dienste wie GreyNoise (https://check.labs.greynoise.io/). Dort kann man beispielsweise gegen AbuseDB prüfen, ob die eigene IPv4-Adresse irgendwo im Internet „auffällig“ geworden ist; etwa durch Portscans, Spam-Versand oder Malware-Traffic. Ebenfalls kann man hin und wieder bei Have I Been Pwned (https://haveibeenpwned.com/) vorbei schauen, um zu prüfen, ob die eignen Zugangsdaten irgendwo gefunden wurden.

Im Allgemeinen ist aber auch das nur ein Indiz. IP-Adressen wechseln; vor allem bei privaten Anschlüssen. Die eigene IP muss erst auffallen, gemeldet werden und so weiter.

Aber hey; vielleicht hat ja noch jemand einen besseren Tipp?

Fragen? Einfach melden.

Postfix MTA-STS Resolver für FreeBSD mit Logfile einrichten

Ich habe heute auch mal den postfix-mta-sts-resolver auf meinem privaten System zugeschaltet. Einfach um es mal zu „probieren“.

Tut einfach und wie beschrieben, ist so aber sicher nicht für größeren und produktiven Betrieb gedacht. So wie der resolver kommt schreibt er alle Meldungen leider nur in die Konsole, es gibt keinen File-Logger. Ich ähm will/brauch den aber!

Also habe ich einen Fork erstellt und ihn überredet in eine Datei zu loggen und direkt noch ein sehr rudimentäres rc.d init script beigelegt: https://github.com/Kernel-Error/postfix-mta-sts-resolver

Wer es also ebenfalls mal probieren möchte, viel Spaß.

Der mta-sts-daemon loggt nun per default in /var/log/mta-sts.log. Config über yml ist ebenfalls nun drin genau wie die Konfiguration per Startparameter. Das rc.d script für FreeBSD könnte sicher schöner sein und hätte gerne im default den Benutzer mta-sts im System. Wir wollen es ja nicht als Root laufen lassen, hm?

Das einzelne Programm mta-sts-query greift auf den gleichen Logger zu, gibt damit also nichts mehr in der Konsole aus sondern auch im Logfile. Vielleicht passe ich dieses noch an, wenn dann mache ich auch einen pull request. Sonst gehe ich mal davon aus, dass es eh bald im postifx ist *daumen-drück*


Update

Habe ich jetzt gemacht. Pullrequest wurde angenommen und das neue Release ist auch schon gemacht. Jetzt also mit Logfile und rc.d script für FreeBSD.

Fragen? Dann fragen.

Siehe auch: MTA-STS einrichten

Fragen? Einfach melden.

systemd und ntp

Man ist das hässlich… Da sitze ich hier an einem Sabayon System und bekomme keine saubere Uhrzeit. Zwar sollte ntpd.service beim Start die Uhrzeit abgleichen.. Der Dienst verkackt aber seinen Starten, weil er „noch“ kein Netzwerk hat. Dabei ist sogar hinterlegt dass es er erst nach dem Netzwerkmanager startet, denn noch scheint der Netzwerkmanager so schnell keine Verbindung zu bekommen. Der initiale Abgleich vom ntpd.service schlägt daher fehlt, der Dienst bleibt aus und es probiert es auch später nicht mehr. Grütze..

$ systemctl --failed
UNIT            LOAD   ACTIVE SUB    DESCRIPTION
ntpdate.service loaded failed failed Set time via NTP using ntpdate

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

1 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

Ich lasse jetzt mal das Bughunting und setzte einfach auf chrony. Nur für Zeitsync ist das ok für mich!

$ equo search chrony
╠  @@ Suche...
╠      @@ Paket: net-misc/chrony-1.29.1 Branch: 5, [sabayonlinux.org] 
╠          Verfügbar:      Version: 1.29.1 ~ tag: NoTag ~ Version: 0
╠          Installiert:    Version: Nicht installiert ~ tag: n/a ~ Version: n/a
╠          Slot:           0
╠          Homepage:       http://chrony.tuxfamily.org/ 
╠          Beschreibung:   NTP client and server programs 
╠          Lizenz:         GPL-2
╠   Schlüsselwörter:  chrony
╠   Gefunden:         1 Eintrag

Gefunde und dann  installieren….

$ equo install chrony
╠  @@ Berechne Abhängigkeiten...
╠  ## [N] [sabayonlinux.org] dev-libs/libedit-20130712.3.1|0
╠  ## [N] [sabayonlinux.org] net-misc/chrony-1.29.1|0
╠  @@ Pakete die installiert/aktualisiert/entfernt werden müssen: 2
╠  @@ Pakete die entfernt werden müssen: 0
╠  @@ Download Größe: 413.1kB
╠  @@ Benutzter Festplattenspeicher: 715.6kB
╠  @@ Du brauchst zumindest: 1.5MB freien Speicherplatz
╠  ::: >>>  (1/1) 2 Pakete
╠    ## downloaden: 2 Pakete
╠    ## ( mirror #1 ) [dev-libs:libedit-20130712.3.1.3556f679066ec7d787573f08ac74ef24922243b2~0.tbz2] @ http://na.mirror.garr.it
╠    ## ( mirror #1 ) [net-misc:chrony-1.29.1.98ee02f66d56c49e1fdc4d713b2cea5ff23d775e~0.tbz2] @ http://na.mirror.garr.it
╠   ## Sammeldownload: 2 Artikel
╠    # [1] na.mirror.garr.it => dev-libs:libedit-20130712.3.1.3556f679066ec7d787573f08ac74ef24922243b2~0.tbz2
╠    # [2] na.mirror.garr.it => net-misc:chrony-1.29.1.98ee02f66d56c49e1fdc4d713b2cea5ff23d775e~0.tbz2
╠    ## Überprüfe Paketprüfsumme...
╠    ## Überprüfe Paketprüfsumme...
╠       : [net-misc:chrony-1.29.1.98ee02f66d56c49e1fdc4d713b2cea5ff23d775e~0.tbz2] GPG validated
╠       : [dev-libs:libedit-20130712.3.1.3556f679066ec7d787573f08ac74ef24922243b2~0.tbz2] GPG validated
╠       : [net-misc:chrony-1.29.1.98ee02f66d56c49e1fdc4d713b2cea5ff23d775e~0.tbz2] SHA1 validated
╠       : SHA256 deaktiviert
╠       : [dev-libs:libedit-20130712.3.1.3556f679066ec7d787573f08ac74ef24922243b2~0.tbz2] SHA1 validated
╠       : SHA512 deaktiviert
╠       : SHA256 deaktiviert
╠       : SHA512 deaktiviert
╠    ## ( mirror #1 ) [dev-libs:libedit-20130712.3.1.3556f679066ec7d787573f08ac74ef24922243b2~0.tbz2] erfolgreich @ http://na.mirror.garr.it
╠    ## ( mirror #1 ) [net-misc:chrony-1.29.1.98ee02f66d56c49e1fdc4d713b2cea5ff23d775e~0.tbz2] erfolgreich @ http://na.mirror.garr.it
╠    ##  angehäufte Transferrate: 658.3kB/Sekunde
╠  +++ >>>  (1/2) dev-libs/libedit-20130712.3.1
╠    ## Entpacke: dev-libs:libedit-20130712.3.1.3556f679066ec7d787573f08ac74ef24922243b2~0.tbz2
╠    ## Installiere Paket: dev-libs/libedit-20130712.3.1
╠    ## [BSD replacement for libreadline.]
╠    ## Updating installed packages repository: dev-libs/libedit-20130712.3.1
>>> Regenerating /etc/ld.so.cache...
╠    ## Aufräumen: dev-libs/libedit-20130712.3.1
╠  +++ >>>  (2/2) net-misc/chrony-1.29.1
╠    ## Entpacke: net-misc:chrony-1.29.1.98ee02f66d56c49e1fdc4d713b2cea5ff23d775e~0.tbz2
╠    ## Installiere Paket: net-misc/chrony-1.29.1
╠    ## [NTP client and server programs]
╠    ## Updating installed packages repository: net-misc/chrony-1.29.1
╠    ## Aufräumen: net-misc/chrony-1.29.1
╠  @@ Installation vollständig.
╠  @@ No configuration files to update.

Beim Boot soll er in Zukunft gestartet werden!

$ systemctl enable chronyd.service
ln -s '/usr/lib64/systemd/system/chronyd.service' '/etc/systemd/system/multi-user.target.wants/chronyd.service'

Och ja, am besten sollte der Dienst direkt gestartet werde…

$ systemctl start chronyd.service

Bevor ich es vergesse, den hässlichen ntpd.service will ich beim Start nicht mehr sehen!

$ systemctl disable ntpd.service

Fragen? Einfach melden.

Solaris NFS

Veraltet: OpenIndiana und Solaris werden kaum noch eingesetzt. NFS funktioniert unter FreeBSD und Linux identisch und ist dort besser dokumentiert.

Der OpenSolaris fork Openindiana und NFS zu Linux

Es gibt leider ein kleines Problem zwischen den Lizenzen unter welchen Linux und Opensolaris herausgegeben werden. Diese sind nämlich inkompatibel. Das bedeutet man kann nicht einfach Code welcher unter der CDDL erstellt wurde in den GPL Linux Kernel packen und umgekehrt. Dieses merkt man, wie ich, sehr schnell beim einfachen Versuche seine lang genutzte externe ext4 formatierte USB Festplatte in mein Opensolaris zu mounten….. Es gibt zwar Mittel und Wege sein ext2 / ext3 read only zu mounten aber bei ext4 ist hängen im Schacht :-/ In Zeiten von GB-Netzwerken geht das ja bei kleineren Datenmengen dank NFS noch. Solaris Linux NFS mount Pahhh da boote ich ganz cool meine Linux-Schüssel, hänge die USB-Platte ein und passe meine exports für einen ganz einfachen und schnellen Share an:
$ cat /etc/exports
/festpladde (ro)
Dann noch schnell dem NFS Server auf der Linuxschüssel sagen das er die exports neu einliest:
$ exportfs -ra
Und noch mal gegenchecken ob der Export auch sauber in der Liste steht:
$ showmount -e
/festpladde *
Perfekt nun sollte jeder Rechner einfach die Daten mounten können, denke ich! Auf meinem Solaris gebe ich schnell in der Konsole den mount Befehl ein und:
$ mount 192.168.1.88:/festpladde /mnt
No such file or directory
No such file or directory????? Ich prüfe alle Einstellungen noch 3 mal nach…. Alles richtig! Alles richtig? Ja im groben schon. Solaris versucht die Linux Kiste per NFSv4 anzusprechen. Dieses unterstützen zwar beide Maschinen, es kann denn noch Probleme damit geben. Schaltet man aber bewusst auf NFSv3 zurück klappt es (darauf soll mal einer kommen.).
$ mount -o vers=3 192.168.1.88:/festpladde /mnt
Ganz blöde Falle, oder? Hat man häufiger Datenaustausch per NFS zu Linux Maschinen könnte man Solaris dazu bringen per default immer NFSv3 zu nutzen:
$ sharectl set -p client_versmax=3 nfs
Will man es später ändern reicht es natürlich die 3 gegen eine 4 zu ersetzten, schlau was?

Fragen? Einfach melden.

« Ältere Beiträge

© 2026 -=Kernel-Error=-RSS

Theme von Anders NorénHoch ↑