Wie ein Programm über die 9-polige PC-Buchse einer Philips ErgoLine D340 an einer Sopho iS3000 Anrufe erkennt, annimmt, wählt und auslöst. Genug, um einen eigenen TAPI- oder SIP-Daemon zu bauen.
Die D340 bleibt als „Leitungsmodem“ an der Anlage. Sie erledigt den gesamten Dialog mit der Sopho (UPN, LAPD, Philips-TMP). Ein PC spricht nur mit der Firmware des Telefons: über eine serielle Leitung mit einem kleinen Binärprotokoll aus Rahmen. Das Telefon meldet Zustände (klingelt, verbunden, ausgelöst …) mit Rufnummern; der PC erteilt Aufträge (anmelden, wählen, annehmen, auflegen), die das Telefon quittiert.
| Punkt | Wert | Status |
|---|---|---|
| Freischaltung | Am Telefon: Merkmale → Optionen → „TAPI: Sprache über Telefon“ = Ein (oder „… über Zusatzgerät“ für die Audio-Buchse). Sind beide aus, reagiert die Schnittstelle auf nichts. Die Einträge erscheinen nur, wenn die Anlage TAPI für die Nebenstelle erlaubt. | bestätigt |
| Stecker | DB9-Buchse hinten am Telefon (Telefon = DCE), 1:1-Kabel. Pin 2 Telefon sendet, Pin 3 Telefon empfängt, Pin 5 Masse. Keine Steuerleitungen. | bestätigt |
| Pegel | RS-232, Ruhepegel −5 V auf beiden Datenleitungen | bestätigt |
| Rate | 1200 Baud, fest (Wartungstest 63, Bitmessung 833 µs je Bit) | bestätigt |
| Format | 8 Datenbits, ungerade Parität, 1 Stoppbit (8O1). Senden und Empfangen damit am Gerät erprobt, ohne Xon/Xoff. Der Treiber schaltet zusätzlich Xon/Xoff (11/13) ein; nötig ist das nicht. | bestätigt |
Beide Richtungen verwenden dasselbe Format: ein Byte Klasse, ein Byte Länge, dann genau so viele Bytes Nutzdaten. Mehrere Rahmen folgen lückenlos aufeinander. bestätigt Treiber
| Klasse | Richtung | Bedeutung | Treibername | Status |
|---|---|---|---|---|
| 01 | PC → Telefon | Auftrag | – | bestätigt |
| 02 | Telefon → PC | Meldung | L2_REQ_PHONE | bestätigt |
| 03 | Telefon → PC | Auftrag abgelehnt | L2_REJ_PHONE | Treiber |
| 04 | Telefon → PC | Auftrag quittiert, immer 04 00, nach 100–150 ms | L2_ACK_PHONE | bestätigt |
| 05 | Telefon → PC | Fehler / nicht verstanden (05 00) | L2_ERR_PHONE | bestätigt |
Zerlegen: Puffer sammeln; solange mindestens zwei Bytes da sind, Länge L = puffer[1] lesen und warten,
bis L + 2 Bytes vorliegen. Der Treiber liest L vorzeichenbehaftet (höchstens 127). Es gibt kein Startzeichen,
nach dem man synchronisieren könnte: Nach einem Fehler den Puffer verwerfen und auf die nächste Lücke warten.
def feed(puffer, neu):
puffer += neu
while len(puffer) >= 2 and len(puffer) >= puffer[1] + 2:
klasse, laenge = puffer[0], puffer[1]
yield klasse, bytes(puffer[2:2 + laenge])
del puffer[:2 + laenge]
Nutzdaten einer Meldung (Klasse 02): Byte 0 = Typ, Byte 1 = Leitung (bisher immer
01), danach typabhängig. Namen wie im Treiber (L3_STATUS…).
| Typ | Name | Bedeutung, Inhalt | Status |
|---|---|---|---|
| 01 | READY | kommt nur 50 ms nach der Quittung auf „Anmelden“, Nutzdaten 01 01 02 00;
vermutlich Bereitmeldung (vermutet). Der Treiber wertet sie nicht aus (Parser-Zweig default);
ein Daemon kann sie als „angemeldet“ werten oder ignorieren. | bestätigt |
| 30 | RINGING | Anruf kommt an; IE 6c Anrufernummer | bestätigt |
| 36 | DIALTONE | Wählton; beim Wählen am Telefon erst bei Wahlende gemeldet, ohne Wahl alle 10 s wiederholt | bestätigt |
| 19 | MORE_INFO | gewählte Nummer als Block; IE 70 Ziel | bestätigt |
| 3e | PROCEEDING | Verbindungsaufbau läuft, Gegenseite wird gerufen | bestätigt |
| 31 | CONNECTED | verbunden (ein- und abgehend) | bestätigt |
| 32 | DISCONNECTED | Gespräch getrennt; IE 08 Ursache (leer = eigene Seite) | bestätigt |
| 39 | RELEASED | Leitung frei, zurück in Ruhe | bestätigt |
| 3b / 3a | FACILITY ein / aus | Merkmal an/aus, Kennung in Byte 2 (Tabelle unten) | bestätigt |
| 33 | IDLE | Ruhe | Treiber |
| 34 / 35 | HOLD / UNHOLD | gehalten / zurückgeholt | Treiber |
| 37 / 38 | BUSY / CAMPONBUSY | besetzt / Anklopfen bei besetzt | Treiber |
| 3c | FACILITYREJECTED | Merkmal abgelehnt | Treiber |
| 3d | ERROR | Fehler | Treiber |
| 3f / 40 | CALLWAITING act / deact | Anklopfen beginnt / endet | Treiber |
| 41 | USERTOUSER | User-to-User-Information (IE 7e) | Treiber |
| 44 | NOHOLD | Halten nicht möglich | Treiber |
| Kennung | Merkmal | Status |
|---|---|---|
| 0a | Hörer: ein = abgehoben, aus = aufgelegt | bestätigt |
| 30 | DTMF-Töne möglich (während eines Gesprächs) | bestätigt |
| 01 | Umleitung | Treiber |
| 16 / 17 | wartenden Anruf anzeigen / annehmen | Treiber |
| 1a | Rückruf (ARB) | Treiber |
| 1d | Aufschalten | Treiber |
| 1f | Konferenz vorbereiten | Treiber |
| 4f | X-Eingang statt Mikrofon: Sprache von der Audio-Buchse statt der Mikrofone; nur im Gespräch (sonst 3c 01 4f abgelehnt), endet mit dem Gespräch | bestätigt |
| 4b / 4e | Wechsel Benutzermodus / Special mode des Telefons (je 3a des einen, 3b des anderen) | vermutet |
Meldung 3c 01 kk (FACILITY_REJECTED): das Telefon hat ein Merkmal abgelehnt, z. B. 4f per Funktionstaste im Ruhezustand. bestätigt
Hinter Typ und Leitung folgen Elemente nach dem Muster von ISDN (Q.931): Kennung, Länge, Inhalt. Ein Byte mit gesetztem Bit 8 steht allein (bisher nur 98, Bedeutung offen).
| IE | Inhalt | Status |
|---|---|---|
| 6c | Anrufernummer als ASCII-Ziffern | bestätigt |
| 70 | Zielnummer als ASCII-Ziffern (im Auftrag des PCs mit vorangestelltem Typ-Oktett 81) | bestätigt / Treiber |
| 08 | Ursache; 08 00 = keine, 08 01 8f = Gegenseite hat ausgelöst | bestätigt |
| 7e | User-to-User-Information | Treiber |
Amtsholung. Externe Nummern stehen mit der Amtsholung der Anlage davor, hier 01. Aus 0101700000000 wird für SIP die Nummer 01700000000; zum Zurückrufen wählt man wieder mit 01. Interne Nebenstellen kommen ohne Vorwahl. Die Amtsholung ist anlagenabhängig und gehört in die Konfiguration des Daemons.
Aufträge haben Klasse 01; Byte 0 ist der Typ, Byte 1 ist 00. Alle Rahmen stammen aus dem Philips-Treiber. Anmelden, Keepalive, Annehmen und Auflegen sind am Gerät erprobt (2026-10-01); die übrigen noch nicht.
| Auftrag | Rahmen | Wann | Status |
|---|---|---|---|
| Anmelden | 01 02 01 00 | einmal nach dem Öffnen der Schnittstelle; Antwort ACK, dann Meldung Typ 01 | bestätigt |
| Keepalive | 01 02 00 00 | nach 15 s ohne Empfang | bestätigt |
| Leitung belegen | 01 02 11 00 | vor dem Wählen, nur im Ruhezustand; Telefon hebt ab (Freisprechen), meldet Hörer ab, aber keinen Wählton | bestätigt |
| Wählen | 01 L 19 00 98 70 n+1 81 Ziffern… | nach dem Belegen; Telefon bestätigt mit MORE_INFO (19, Ziel); als Nachwahl/DTMF im Gespräch laut Treiber | bestätigt (Nachwahl: Treiber) |
| Annehmen | 01 02 14 00 | während RINGING; das Telefon hebt ab (Freisprechen bei „Sprache über Telefon“) | bestätigt |
| Auflegen | 01 02 13 00 | bei genau einem Gespräch; danach DISCONNECTED, RELEASED, Hörer aus | bestätigt |
| Merkmal | 01 03 26 00 kk | 16/17 Anklopfen anzeigen/annehmen, c3 Reconnect bei zwei Gesprächen (Treiber); 4f X-Eingang statt Mikrofon im Gespräch → ACK, dann 3b 01 4f (am Gerät, nicht im Treiber) | Treiber · 4f bestätigt |
| weitere | 15, 18, 1b, 1c, 1d, 21–24, 27, 25 | Halten, Übergabe, Konferenz, Rückruf, User-to-User | Treiber |
Wählen im Detail. Bei n Ziffern ist L = n + 6: Typ 19, Leitung 00,
das Einzelbyte 98, dann IE 70 mit Länge n + 1, Typ-Oktett
81 und den Ziffern als ASCII.
Wahl „123“ 01 09 19 00 98 70 04 81 31 32 33
Wahl extern „01 0170 0000000“
01 13 19 00 98 70 0e 81 30 31 30 31 37 30 30 30 30 30 30 30 30
Im Treiber nicht unterstützt (Rückgabe LINEERR_OPERATIONUNAVAIL): Umleiten eines klingelnden Anrufs,
Blind Transfer, Accept.
logs/test_20261001_190905_watchdog_ohne_keepalive.log,
logs/test_20261001_191319_watchdog_mit_keepalive.log)Links stehen Handlungen am Telefon, Pfeile sind Rahmen. Achtung: Im Freisprechbetrieb beendet die Lautsprecher-Taste am Telefon das Gespräch (Ursache leer). Schwarze Pfeile: Meldungen des Telefons. Farbige Pfeile: Aufträge des PCs. Gestrichelt: erwartet, am Gerät noch nicht gesehen.
serial_20260930_163534.log, alle Rahmen bestätigt.logs/test_20261001_130201_pi_angenommen_verpasst.log).logs/test_20261001_085744_annehmen_auflegen.log).logs/test_20261001_150042_waehlen_extern.log). Nach dem Belegen meldet das Telefon nur „Hörer ab“, keinen Wählton; der Anruf entsteht erst mit MORE_INFO.Die Rahmen tragen keine Anrufkennung; das Byte „Leitung“ ist immer 01. Der Philips-Treiber
führt deshalb selbst eine Anruftabelle (31 Plätze) und ordnet jede Meldung dem Anruf zu, der gerade in einem passenden
Zustand ist. Die Zustände sind die TAPI-Werte LINECALLSTATE_*; im Diagramm oben: RUHE = IDLE,
KLINGELT = OFFERING, WÄHLTON = DIALTONE, WAHL = DIALING, RUFT = PROCEEDING/RINGBACK, VERBUNDEN = CONNECTED,
AUSGELÖST = DISCONNECTED.
Je Meldung setzt der Parser einen Ereigniscode, eine Übergangstabelle (0x100069eb) bildet
„alter Zustand × Code“ auf den neuen Zustand ab, eine zweite Funktion (0x1000b70b) setzt den Modus
(Wählton-Art, Besetzt-Art, Auslöseursache als LINEDISCONNECTMODE).
| Zustand | erlaubte Übergänge (zusätzlich immer: Auslösung → DISCONNECTED) |
|---|---|
| neu | Angebot → OFFERING · Wählton → DIALTONE · weitere Codes setzen den Zustand direkt |
| OFFERING | Accept → ACCEPTED → CONNECTED (bei Annahme: erst Accept, dann Connect) |
| DIALTONE | Wahl → DIALING |
| DIALING | Proceeding → PROCEEDING · besetzt → BUSY |
| PROCEEDING | Ringback → RINGBACK (folgt unmittelbar) · besetzt → BUSY · Konferenz → CONFERENCED |
| RINGBACK, BUSY | Connect → CONNECTED |
| CONNECTED | Halten → ONHOLD · Halten für Übergabe → ONHOLDPENDTRANSFER · Halten für Konferenz → ONHOLDPENDCONF · Konferenz → CONFERENCED |
| ONHOLD, ONHOLDPENDTRANSFER | Connect → CONNECTED |
| DISCONNECTED | Freigabe (RELEASED) → IDLE, Platz in der Tabelle wird frei |
Für einen Daemon heißt das: eine eigene Anruftabelle führen, jede Meldung über den aktuellen Zustand zuordnen, Aufträge nur bei erfüllter Vorbedingung senden und Modus bzw. Ursache mitführen (für SIP-Statuscodes und Statistik).
| Ereignis | Daemon tut | SIP-Seite |
|---|---|---|
| 30 RINGING mit Nummer | Nummer normalisieren (Amtsholung weg), Anruf anlegen | INVITE, From = Anrufernummer |
| SIP 200 OK vom Softphone | Auftrag Annehmen 01 02 14 00, Audio durchschalten | ACK |
| INVITE vom Softphone | Belegen 01 02 11 00, dann Wählen (Amtsholung davor bei extern) | 100 Trying |
| 3e PROCEEDING | – | 180 Ringing |
| 31 CONNECTED | Audio durchschalten | 200 OK (abgehend) |
| BYE vom Softphone | Auftrag Auflegen 01 02 13 00 | 200 OK |
| 32 DISCONNECTED | Audio trennen | BYE, bzw. CANCEL, solange noch nicht verbunden |
| 39 RELEASED | Anruf löschen, zurück in Ruhe | – |
| 3b/3a … 0a Hörer ab/auf | nur Anzeige (Mensch am Telefon) | optional Presence/BLF |
Aufbau, der sich im Test bewährt hat (Referenz: gateway/ergoline/ im Repository, Python 3 + pyserial):
/dev/serial/by-id/… öffnen, 1200 Baud, 8O1. Xon/Xoff zunächst aus lassen, weil
11 und 13 auch als Auftragstypen vorkommen.from ergoline.link import ErgoLink
from ergoline import protocol as p
with ErgoLink("/dev/serial/by-id/usb-FTDI_…-if00-port0") as link:
q = link.sende(p.anmelden()) # erwartet Klasse 04
while True:
zeit, r = link.rahmen.get()
if r.klasse != p.MELDUNG:
continue
typ = p.MELDUNGSTYP.get(r.typ)
if typ == "RINGING":
ie = dict(p.ies(r.daten[2:]))
extern, nummer = p.extern(p.rufnummer(ie[0x6C]))
sip_invite(von=nummer) # eigener SIP-Stack, z. B. baresip ctrl_tcp
elif typ == "DISCONNECTED":
sip_bye()
def sip_angenommen(): link.sende(p.annehmen())
def sip_beendet(): link.sende(p.auflegen())
def sip_waehlen(nr): link.sende(p.belegen()); link.sende(p.waehlen(nr))
Werkzeug zum Ausprobieren: tools/ergo.py decode|listen|anmelden|keepalive; gesprächsrelevante
Aufträge nur mit --freigabe.
Der Philips-Treiber durchläuft beim Öffnen zusätzlich einen Service-Modus mit 9600 Baud. Für den Betrieb ist das vermutlich nicht nötig vermutet; die Folge ist hier nur zur Vollständigkeit festgehalten. Treiber
RQV:0\r → Quittung →
RQQ:1\r → Einzelbyte 02. Die Antwort kommt als Textzeile.Ein Hayes-AT-Protokoll gibt es an dieser Buchse nicht. Der ältere Octophon-Treiber (AT$CAL …) gehört zu einem
anderen Gerät bzw. einer anderen Firmware und ist inkompatibel.
Die Anlage ist nicht rücksetzbar, eine gesperrte Nebenstelle ließe sich nicht selbst reparieren. Deshalb:
nur dokumentierte Aufträge senden, nichts raten; Wählen nur zu bekannten Testnummern; am Telefon nie das Service-Menü
(set TEI, reset data) und nie die Wartungscodes 31–34 benutzen, die den Speicher löschen.
logs/serial_20260930_163534.log (alle Meldungen), logs/bitbang_20260930_1633*/1634*/1635* (Rate, Fehlerantwort). Übersicht: logs/INDEX.md.Ergoline.tsp:
2b5b2b3e2e3ff51a2ca666b7bc874e9e9d81551a3f67c5357ea8ea297f50b282.
Wichtige Stellen: Parser 0x100172b9, Rahmen-Assembler 0x1000dbe9, Aufträge 0x10014b0c (Wählen),
0x10015d57 (Annehmen), 0x100168ce (Auflegen), Initialisierung 0x10007afc, Portmodi 0x100132c2/0x1001332e.docs/protocol.md, docs/hardware.md, docs/sackgassen.md.