Example: 12-Protocol/network_transport.py
"""
Network Transport Example for OpenMV Protocol (UDP)
This example shows how to create a network transport channel using UDP.
The camera connects to a network, sets its mDNS hostname (reachable at
<hostname>.local), and listens for UDP datagrams on a known port.
The IDE (or any client) sends datagrams to <hostname>.local:<port> and
communicates using the OpenMV protocol over UDP.
The transport implements the physical layer interface required by the protocol:
- read(): Read from UDP socket
- write(): Buffer data for the next datagram
- is_active(): Check if a client address is known
- size(): Peek at available bytes without consuming
- flush(): Send buffered writes as a single UDP datagram
"""
import time
import errno
import network
import socket
import protocol
from machine import LED
LED_B = LED("LED_BLUE")
SSID = ""
KEY = ""
HOST = ""
PORT = 5555
HOSTNAME = "openmv"
class NetworkTransport:
"""UDP-based network transport for OpenMV Protocol"""
def __init__(self, host="", port=5555, max_payload=4096):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
self.sock.bind((host, port))
self.sock.setblocking(False)
self.client = None
self.txbuf = bytearray(max_payload + 14)
self.txlen = 0
self.rxbuf = bytearray(max_payload + 14)
self.rxlen = 0
self.rxpos = 0
LED_B.off()
def is_active(self):
return self.client is not None or self.size() > 0
def size(self):
avail = self.rxlen - self.rxpos
if avail > 0:
return avail
try:
data, addr = self.sock.recvfrom(len(self.rxbuf))
except OSError as e:
if e.args[0] != errno.EAGAIN:
self.client = None
return 0
if not data:
return 0
n = len(data)
self.rxpos = 0
self.rxlen = n
self.rxbuf[:n] = data
self.client = addr
return n
def read(self, offset, size):
avail = self.rxlen - self.rxpos
if avail <= 0:
return None
n = min(size, avail)
end = self.rxpos + n
data = self.rxbuf[self.rxpos:end]
self.rxpos = end
return data
def write(self, offset, data):
if self.client is None:
return -1
n = len(data)
self.txbuf[self.txlen:self.txlen + n] = data
self.txlen += n
return n
def flush(self):
if self.client is None or self.txlen == 0:
return 0
mv = memoryview(self.txbuf)
try:
self.sock.sendto(mv[:self.txlen], self.client)
except OSError as e:
self.txlen = 0
if e.args[0] != errno.EAGAIN:
self.client = None
return -1
self.txlen = 0
return 0
if __name__ == "__main__":
MAX_PAYLOAD = 1400
network.hostname(HOSTNAME)
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, KEY)
wlan.config(pm=wlan.PM_NONE)
while not wlan.isconnected():
time.sleep_ms(100)
LED_B.toggle()
LED_B.off()
protocol.init(
crc=True,
seq=True,
ack=False,
events=True,
max_payload=MAX_PAYLOAD,
rtx_retries=3,
rtx_timeout_ms=100,
lock_interval_ms=10,
poll_ms=10,
)
protocol.register(
name="network",
flags=protocol.CHANNEL_FLAG_PHYSICAL,
backend=NetworkTransport(host=HOST, port=PORT, max_payload=MAX_PAYLOAD),
)