Xcode Swift Netzwerkkommunikation AT-Befehle

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

Aufgrund der Corona-Krise: Die Veröffentlichung von Stellenangeboten und -gesuchen ist bis 31.12.2020 kostenfrei. Das beinhaltet auch Angebote und Gesuche von und für Freischaffende und Selbstständige.

  • Xcode Swift Netzwerkkommunikation AT-Befehle

    Hallo,

    nachdem ich nun verschiedene Ansätze verfolgt habe ein VoIP-Telefon anzusteuern, habe ich mich letztendlich dazu entschieden die benötigte Funktion (Nummer wählen) in meiner App zu realisieren.

    Der Hersteller dieses Gerätes ist leider wenig entgegenkommend. Andere Hersteller waren wiederum sehr hilfsbereit. Werbung möchte ich hier an dieser Stelle nun nicht betreiben.

    Der Kunde hat sich nun mal für diesen Hersteller entschieden und ich kann mich nun um eine Lösung bemühen. ?(

    Nun gut - Wireshark hat mir hierzu die notwendigen Informationen geliefert. Das besagte VoIP-Telefon lässt sich mittels AT-Befehlen via Netzwerk steuern. Mein Wissen auf diesem Gebiet ist nicht gerade sehr umfangreich :D .

    Tutorials habe ich hierzu in Verbindung mit Swift keine gefunden. Hat jemand Erfahrung auf diesem Gebiet? Evtl. eine kleine DemoApp die er mir zur Verfügung stellen könnte? Kann mir jemand Quellen mitteilen, welche mir hier weiterhelfen könnten.

    Besten Dank mal vorab.
  • Das letzte Mal, das ich mit AT-Befehlen zu tun hatte, habe ich diese per serieller Schnittstelle an ein Wählmodem geschickt ... das ist schon was her.

    Du müsstest etwas genauer sagen, wozu Du Infos suchst: Die Kommunikation über's Netz hat ja mit den Kommandos nichts zu tun. Wird hier direkt ein eigener Netzwerkport angesprochen oder gibt es einen Webservice oder...?

    Die AT-Kommandos selber waren eher stumpf und nur in Grundzügen standardisiert: ATDP - dial pulse, ATDT - dial tone, ATZ - reset, ATH - hang up etc.

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • Hallo Mattes,

    danke mal vorab für Deine Unterstützung.


    Lt. Wireshark funktioniert die Kommunikation wie folgt:

    1. Es wird ein Port x der VoIP-Adresse y geöffnet.
    2. Daraufhin wird mit "Enter PIN" von y geantwortet
    3. Nun muss die Pin übermittelt werden
    4. Dies wird von Y mit "PIN OK" quittiert
    5. Ab hier kann dann mit AT-Befehlen alle weitere Aktionen durchgeführt werden.

    Zur Kommunikation selbst:
    - Wie öffne ich einen Port einer IP-Adresse mit Swift?
    - Wo finde ich die Antwort für eine weitere Auswertung?
    - Wie sende ich nun weiter AT-Befehle an den Port x?
    - Schlussendlich wie schließe ich den geöffneten Port bzw. die Kommunikation mit der IP-Adresse?

    P.S.: Falls es einen AT-Standardbefehlssatz gibt, wo finde ich diesen?
  • Ich hatte 2016 mal etwas in der Richtung gemacht: eine kleine App, die sich mit der
    Fritzbox verbindet und über Anrufe informiert. Dazu musste ich eine TCP-Verbindung
    zur Fritzbox aufbauen. Ich habe damals ytcpsocket verwendet. Mir gefiel, dass es kompakt
    war. ytcpsocket beinhaltet einen C-Wrapper um die Standard-Socket-Implementierung und
    Swift-Klassen. Prinzipiell geht aber sicherlich auch jede andere Library für TCP. Bei
    Alamofire findest du vermutlich sehr viele Projekte, die dies nutzen und somit als Beispiel
    eine Hilfe sein können.

    Ich hatte mir eine Reader-Klasse geschrieben, die mit der folgenden Methode
    die Verbindung aufbaut (noch Swift 3):

    Quellcode

    1. func connect(to server : String, at port : Int)->(Bool,String) {
    2. if isConnected {
    3. let _ = client?.close()
    4. }
    5. client = TCPClient(addr: server, port: port)
    6. return client!.connect(timeout: 1)
    7. }
    Im connect der Library-Klasse TCPClient werden die Parameter Adresse, Port und timeout
    an die entsprechende C-Funktion übergeben. Port ist Int und die Adresse die IP oder
    der Hostname. Je nach konkret verwendete Library sieht das natürlich etwas anders aus,
    wobei auf C-Ebene aber sicher immer das gleiche steht. Zum Schließen gibt es ein close.
    Zum Lesen gibt es recv und zum Senden send. Für die C-Funktion der Sockets gibt es
    manuals, z.B. per "man connect". Da kannst du die Funktionalität nachlesen. Die meisten
    Libraries dürften nur Wrapper sein, die etwas zusätzlichen Komfort und Syntax der jeweiligen
    Sprache bieten. Eine grundlegend andere Funktionsweise dürfte es erst mit Klassen geben,
    die ein spezielles Protokoll implementieren.

    Für die Ansteuerung eine SMS-Gateways hatten Kollegen unter
    itsme.home.xs4all.nl/projects/…hcs-7100-at-commands.html
    sowie nobbi.com/atgsm.html Beschreibungen der Befehle gefunden.
    Allerdings hatte ich auch den Eindruck, dass es eben keinen Standard gibt.
  • Du musst erst mal wissen, ob Du TCP oder UDP machst.

    Grundlagen über das Netzwerkprogrammieren gibt es hier: C von A bis Z. - Ja, das ist C. Aber sollte auch übertragbar nach Swift sein, aber da findest Du sicherlich ein Swift-Packet, das eine schöne Socket-Klasse anbietet.

    In Swift habe ich für eine TCP-Verbindung mal Stream (getStreamsToHost()) genützt. Da war das Tut. Real-Time Communication with Streams eine gute Anleitung dazu.

    Die AT Sachen sind ja schon alt. Dafür findest Du sicherlich zig Beispiele im Internet. Salopp gesagt, das schiebst Du nur bissl (ASCII-encoded) Strings hin und her.
  • Euch allen erst einmal ein großes Dankeschön. :thumbsup:

    Für alle die weitere Informationen benötigen, anbei mal ein Link der mir geholfen hat: developer.apple.com/videos/play/wwdc2018/715/

    Der Connect mit dem VoIP-Telefon funktioniert bereits. Auch erhalte ich die o.g. Aufforderung zur Pin-Übermittlung. Aber .... :rolleyes:

    Werde diesen Thread zu einem späteren Zeitpunkt nochmals aufleben lassen. Muss nun erst einmal alle Informationen verarbeiten.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von OSXDev ()

  • MyMattes schrieb:

    Vielleicht magst Du ein paar Code-Snippets teilen? Nicht, dass ich im Moment so eine Fragestellung habe, aber vielleicht hilft es jemandem in Zukunft ... falls es nicht zu umständlich ist.

    Mattes
    Wie bereits mitgeteilt, Mattes. Wenn ich das Stoffgebiet durchgearbeitet habe, werde ich dieses Thema nochmals reaktivieren. Ein paar Fragen werden sich bestimmt noch ergeben.
  • Nachdem ich mich nun eingehend mit dem Protokoll (Device -> Mac; vice versa) beschäftigt habe, beschreibe ich mal kurz meinen Lösungsweg:

    1. Import Network Framework
    2. Connect mit dem VoIp-Telefon herstellen
    3. Socket mit Portangabe öffnen
    4. Listener() initialisieren und asynchron starten
    - Achtung: Fehlerbehandlung nicht vergessen und ganz wichtig - grundsätzlich immer die Verbindung beenden!
    - Wenn unerwartete Nachrichten empfangen werden, diese für eine weitere Auswertung ins LOG schreiben und Verbindung regelkonform beenden!
    - gesendete Befehle grundsätzlich mit einer CR-Sequence absenden
    - empfangene Nachrichten enden grundsätzlich mit einem Newline
    5. Nachdem das VoIP-Telefon nun empfangsbereit ist, kann mittels ATD<Telefonnummer> der Wahlvorgang eingeleitet werden. Achtung - im Anschluss die Verbindung schliessen!


    AT-Befehle, welche bei mir zum Einsatz kamen:
    - AT+CGSN -> Seriennummer des Gerätes
    - AT^CPPN -> Gerätenamen
    - AT+CGMR -> Firmware Version
    - AT^SACO -> Vorwahlnummern
    - ATH -> Gespräch entgegennehmen
    - ATD<number> -> Telefonnummer wählen

    An dieser Stelle möchte ich nochmals eingehend darauf hinweisen, den Listener() asynchron - also nicht im Main-Thread - zu starten. Das VoIp-Telefon benötigt hin- und wieder extrem lange bis es eine Antwort sendet! Die gesendeten Befehlssequenzen müssen vom Datentyp Data sein! Nicht versuchen diese als String zu übermitteln.

    Hinweis: Ob diese Vorgehensweise Allgemeingültigkeit besitzt und somit bei anderen Hersteller/Geräten zum Einsatz gebracht werden kann, konnte ich nicht zu 100% testen.

    Zum Network Framework selbst; ich kann an diese Stelle mitteilen, dass sich die Handhabung wirklich einfach gestaltet. Sehr geholfen hat mir das Tutorial von Apple (Link s.o.).

    Quellcode

    1. Verbindung initialisieren:
    2. ...
    3. init(host: String, port: UInt16)
    4. {
    5. self.host = NWEndpoint.Host(host)
    6. self.port = NWEndpoint.Port(rawValue: port)!
    7. let voipConnection = NWConnection(host: self.host, port: self.port, using: .tcp)
    8. }
    9. ...
    10. Verarbeitung der empfangenen Daten:
    11. ...
    12. voipConnection(minimumIncompleteLength: 1, maximumLength: 65536) { (data, _, isComplete, error) in
    13. if let data = data, !data.isEmpty
    14. {
    15. let message = String(data: data, encoding: .utf8)
    16. // remove after test
    17. print("\n message: ", message as Any)
    18. switch message
    19. {
    20. case "Enter PIN>\n":
    21. // Antwort senden
    22. case "BAD PIN\n":
    23. // Verbindung beenden
    24. case "PIN OK\n":
    25. // weitere Aktionen mittels AT-Befehlen durchführen
    26. // Verbindung beenden
    27. ...
    28. default:
    29. print("\nSTOPP\n")
    30. // Verbindung beenden
    31. }
    32. }
    33. ...
    Alles anzeigen

    Viel Spaß.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von OSXDev ()

  • manoh schrieb:

    Wenn das obere und untere voipConnection das selbe ist, eine Instanz von NWConnection, dann sieht das untere für mich jetzt komisch aus. Fehlt da nicht noch die Methode?
    Sind die wesentlichen Auszüge des Codes. Bin sicher, dass der Rest keine große Herausforderung darstellt. Habe es in zwei Methoden realisiert, da es sonst schwierig mit dem Aufruf wird - Stichwort asynchroner Thread.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von OSXDev ()