# Fullmo MovingCap CODE - micropython example. # original file name: mcnet.pyi """mcnet Modul-Stub/Schnittstelle für fullmo MovingCap Servoantriebe Das `mcnet` Modul bietet eine PySerial-ähnliche API für Netzwerk-Socket-Kommunikation für MovingCap CODE / Micropython auf MovingCap. Es ermöglicht die Erstellung von TCP-Server, TCP-Client, UDP-Server und UDP-Client/Peer-Sockets zur einfachen Implementierung von benutzerdefinierten Anwendungsprotokollschichten, wie z.B. MODBUS TCP. Die Verwendung einer API ähnlich einer seriellen Kommunikations-API (anstelle einer Python socket/usocket Bibliothek) bietet extrem stabile, sichere und komfortable Kommunikationsfunktionalität, die das eigentliche Skript von Belangen wie Socket-Bindung, Akzeptieren oder Herstellen von Verbindungen, Wiederverbindungsverhalten usw. entlastet. Das Modul bietet eine klassenbasierte Schnittstelle, bei der Sie McNet-Objekte erstellen, die Netzwerkverbindungen repräsentieren. Jede McNet-Instanz verwaltet eine Socket-Verbindung und bietet Methoden zum Lesen und Schreiben von Daten. Verbindungseinstellungsformat: Die an McNet() übergebene Einstellungszeichenfolge definiert den Verbindungstyp und die Parameter: - TCP-Server: "SERVER:port" oder "SERVER:ip:port" Beispiel: McNet("SERVER:10001") - TCP-Server auf Port 10001, alle Schnittstellen Beispiel: McNet("SERVER:192.168.1.100:502") - TCP-Server auf spezifischer IP - TCP-Client: "ip:port" oder "hostname:port" Beispiel: McNet("192.168.1.100:502") - Verbindung zu TCP-Server unter IP:Port Beispiel: McNet("plc.local:502") - Verbindung mit Hostname - UDP-Server: "UDP:port" oder "UDP:ip:port" Beispiel: McNet("UDP:5000") - UDP-Server auf Port 5000 - UDP-Client/Peer: "UDP:ip:port" Beispiel: McNet("UDP:192.168.1.100:5000") - UDP-Kommunikation mit entferntem Host Verwendungsbeispiele: # TCP-Server-Beispiel import mcnet server = mcnet.McNet("SERVER:10001") server.set_line_mode(1, ord("<"), ord(">"), 0, 0, 5000) while True: line = server.readline() if line: print("Empfangen:", line) server.write("OK\\n") # TCP-Client-Beispiel client = mcnet.McNet("192.168.1.100:502") if client.is_connected(): client.write(b"\\x00\\x01\\x00\\x00\\x00\\x06") # MODBUS-Anfrage response = client.read(256) print("Antwort:", response) client.close() """ __author__ = "Oliver Heggelbacher" __email__ = "oliver.heggelbacher@fullmo.de" __version__ = "50.00.08.xx" __date__ = "2025-02-03" class McNet: """Netzwerk-Socket-Kommunikationsklasse mit PySerial-ähnlicher API. Diese Klasse repräsentiert eine Netzwerk-Socket-Verbindung (TCP oder UDP, Client oder Server). Sie bietet eine einfache, Seriell-Port-ähnliche Schnittstelle für Netzwerkkommunikation. """ def __init__(self, settings: str): """Neue Netzwerkverbindung erstellen und öffnen. :param settings: Verbindungseinstellungszeichenfolge, die Socket-Typ und Parameter angibt. Format hängt vom Verbindungstyp ab (siehe Moduldokumentation). :type settings: str :raises OSError: Wenn Socket nicht geöffnet werden kann (z.B. alle Sockets in Verwendung, ungültige Einstellungen) Beispiel: server = McNet("SERVER:10001") # TCP-Server client = McNet("192.168.1.100:502") # TCP-Client """ pass def open(self, settings: str) -> bool: """Netzwerkverbindung öffnen (oder nach Schließen erneut öffnen). :param settings: Verbindungseinstellungszeichenfolge (siehe __init__) :type settings: str :return: True bei Erfolg, False bei Fehlschlag. :rtype: bool """ pass def is_open(self) -> bool: """Prüfen, ob der Socket geöffnet ist. Gibt True zurück, wenn der Socket geöffnet wurde (auch wenn noch nicht verbunden). Für TCP-Clients zeigt dies an, dass der Socket existiert, aber möglicherweise noch verbindet. Für TCP-Server zeigt dies an, dass der Server-Socket lauscht. :return: True wenn Socket geöffnet, False andernfalls. :rtype: bool """ pass def is_connected(self) -> bool: """Prüfen, ob die Verbindung hergestellt und bereit für Datenübertragung ist. Für TCP-Clients: Gibt True zurück, wenn Verbindung zum Server hergestellt ist. Für TCP-Server: Gibt True zurück, wenn ein Client verbunden ist. Für UDP: Gibt normalerweise True zurück, wenn Socket geöffnet ist (UDP ist verbindungslos). :return: True wenn verbunden, False andernfalls. :rtype: bool """ pass def close(self): """Netzwerkverbindung schließen und Socket freigeben. Dies beendet die Verbindung sauber und gibt die Socket-Ressource zur Wiederverwendung durch andere McNet-Instanzen frei. """ pass def write(self, data) -> int: """Daten zur Netzwerkverbindung schreiben. Akzeptiert sowohl String- als auch Bytes-ähnliche Objekte. Strings werden automatisch als UTF-8 kodiert. Die Daten werden über die Netzwerkverbindung gesendet. :param data: Zu sendende Daten. Kann str, bytes, bytearray oder memoryview sein. :type data: str or bytes-like :return: Anzahl geschriebener Bytes, oder negativer Wert bei Fehler. :rtype: int Beispiel: s.write("Hallo\\n") # String senden s.write(b"\\x01\\x02\\x03") # Bytes senden """ pass def read(self, size: int = 0): """Verfügbare Daten von der Netzwerkverbindung lesen. Liest bis zu 'size' Bytes aus dem Empfangspuffer. Wenn size 0 ist oder weggelassen wird, werden alle verfügbaren Daten gelesen. Gibt None zurück, wenn keine Daten verfügbar sind. Der Rückgabetyp hängt von der text_mode-Einstellung ab: - Wenn text_mode True ist: gibt str zurück - Wenn text_mode False ist: gibt bytes zurück :param size: Maximale Anzahl zu lesender Bytes. 0 = alle verfügbaren lesen. :type size: int :return: Gelesene Daten als str oder bytes, oder None wenn keine Daten verfügbar. :rtype: str or bytes or None Beispiel: data = s.read() # Alle verfügbaren lesen data = s.read(100) # Bis zu 100 Bytes lesen """ pass def readline(self): """Datenzeile basierend auf Zeilenmodus-Konfiguration lesen. Diese Methode verwendet die mit set_line_mode() konfigurierten Zeilen-Parsing-Parameter. Sie wartet auf und extrahiert eine vollständige Zeile basierend auf den Start-/End-Markierungen und Timeout-Einstellungen. Die Antwort enthält die Start- und End-Markierungen, falls angegeben. Gibt None zurück, wenn keine vollständige Zeile verfügbar ist oder Timeout abläuft. :return: Zeilendaten als str oder bytes (abhängig von text_mode), oder None. :rtype: str or bytes or None Beispiel: s.set_line_mode(1, ord('<'), ord('>'), 0, 0, 5000) line = s.readline() # Liest Daten zwischen '<' und '>' """ pass def read_until(self, expected: str = "\\n", size: int = 0): """Daten lesen, bis eine bestimmte Sequenz gefunden wird. Liest von der Verbindung, bis die erwartete Byte-Sequenz angetroffen wird, oder bis 'size' Bytes gelesen wurden (wenn size > 0), oder bis keine weiteren Daten verfügbar sind. Die erwartete Sequenz ist in den zurückgegebenen Daten enthalten. :param expected: Byte-Sequenz, bis zu der gelesen werden soll. Kann str oder bytes sein. Standard ist Newline. :type expected: str or bytes :param size: Maximale zu lesende Bytes (0 = kein Limit). :type size: int :return: Gelesene Daten als str oder bytes (abhängig von text_mode), oder None. :rtype: str or bytes or None Beispiel: data = s.read_until("\\r\\n") # Bis CRLF lesen data = s.read_until(b"\\x00", 1024) # Bis Null-Byte lesen, max 1024 Bytes """ pass def set_line_mode(self, text_mode: int, start_marker: int, end_marker: int, min_len: int, max_len: int, timeout: int) -> int: """Zeilen-Parsing-Modus für readline()-Methode konfigurieren. Dies konfiguriert, wie readline() Zeilen aus dem Datenstrom extrahiert. Die Start- und End-Markierungen definieren die Zeilengrenzen, min_len und max_len geben die erwarteten Frame-Längen an, und timeout gibt an, wie lange auf eine vollständige Zeile gewartet werden soll. :param text_mode: Wenn > 0, Daten als str zurückgeben (Textmodus). Wenn 0, als bytes zurückgeben. :type text_mode: int :param start_marker: ASCII-Code des Zeilenanfangs-Markierungszeichens (z.B. ord('<') = 60). :type start_marker: int :param end_marker: ASCII-Code des Zeilenende-Markierungszeichens (z.B. ord('>') = 62). :type end_marker: int :param min_len: Minimale Frame-Länge in Bytes (einschließlich Start-/End-Markierungen). Setzt auf 0 für keine minimale Längenbeschränkung. Bei Binärprotokollen verhindert dies Fehlinterpretation wenn Nutzdaten Markierungsbytes enthalten (Frame-Grenzen-Mehrdeutigkeit). :type min_len: int :param max_len: Maximale Frame-Länge in Bytes (einschließlich Start-/End-Markierungen). Setzt auf 0 für keine maximale Längenbeschränkung. Begrenzt die Suchreichweite für End-Markierungen, um Puffer-Überläufe zu vermeiden und Frame-Grenzen zu erzwingen. :type max_len: int :param timeout: Timeout in Millisekunden zum Warten auf vollständige Zeile. :type timeout: int :return: 0 bei Erfolg, negativ bei Fehler. :rtype: int Beispiel: # Textbasiertes Protokoll (variable Länge) s.set_line_mode(1, ord('<'), ord('>'), 0, 0, 5000) # Binärprotokoll mit fester Länge (STX + 6 Datenbytes + ETX = 8 Bytes) s.set_line_mode(0, 0x02, 0x03, 8, 8, 1000) # Binärprotokoll mit variabler Länge (min 5 Bytes, max 256 Bytes) s.set_line_mode(0, 0x02, 0x03, 5, 256, 1000) """ pass def in_waiting(self) -> int: """Anzahl der im Empfangspuffer verfügbaren Bytes abrufen. Gibt die Anzahl der Bytes zurück, die sofort ohne Blockieren gelesen werden können. Nützlich, um vor dem Aufruf von read() zu prüfen, ob Daten verfügbar sind. :return: Anzahl verfügbarer zu lesender Bytes, oder negativer Wert bei Fehler. :rtype: int Beispiel: if s.in_waiting() > 0: data = s.read() """ pass def reset_input_buffer(self): """Eingabe-Empfangspuffer löschen. Verwirft alle derzeit im Empfangspuffer befindlichen Daten. Nützlich zum Resynchronisieren der Kommunikation oder Löschen veralteter Daten. Beispiel: s.reset_input_buffer() # Alle ausstehenden Daten löschen s.write("NEUE_ANFRAGE") """ pass