zephyr/samples/net/cellular_modem/server/te_udp_receive.py
Bjarki Arge Andreasen c0c9d6f7d6 samples/net: Add cellular modem sample
This commit adds a sample application which demonstrates how
to use the new driver and modules. The sample uses power
management to turn on the modem, uses network management
to wait for L4 connected, then uses DNS to get the IP
of the server running the python script found in the
server folder, which echoes back data recevied to it.
A packet containing psudo random data is then sent to
the server, which the echoes it back. To validate the
capability of the driver to restart the modem, the
modem is restarted, and the packet is sent again.

The server is hosted by linode, and uses the domain
name test-endpoint.com

Signed-off-by: Bjarki Arge Andreasen <baa@trackunit.com>
2023-08-30 13:48:51 +02:00

108 lines
3.1 KiB
Python
Executable File

# Copyright (c) 2023, Bjarki Arge Andreasen
# SPDX-License-Identifier: Apache-2.0
import socket
import threading
import select
import time
import copy
class TEUDPReceiveSession():
def __init__(self, address, timeout = 1):
self.address = address
self.last_packet_received_at = time.monotonic()
self.timeout = timeout
self.packets_received = 0
self.packets_dropped = 0
def get_address(self):
return self.address
def on_packet_received(self, data):
if self._validate_packet_(data):
self.packets_received += 1
else:
self.packets_dropped += 1
self.last_packet_received_at = time.monotonic()
def update(self):
if (time.monotonic() - self.last_packet_received_at) > self.timeout:
return (self.packets_received, self.packets_dropped)
return None
def _validate_packet_(self, data: bytes) -> bool:
prng_state = 1234
for b in data:
prng_state = ((1103515245 * prng_state) + 12345) % (1 << 31)
if prng_state & 0xFF != b:
return False
return True
class TEUDPReceive():
def __init__(self):
self.running = True
self.thread = threading.Thread(target=self._target_)
self.sessions = []
def start(self):
self.thread.start()
def stop(self):
self.running = False
self.thread.join(1)
def _target_(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setblocking(False)
sock.bind(('0.0.0.0', 7781))
while self.running:
try:
ready_to_read, _, _ = select.select([sock], [sock], [], 0.5)
if not ready_to_read:
self._update_sessions_(sock)
continue
data, address = sock.recvfrom(4096)
print(f'udp received {len(data)} bytes -> {address[0]}:{address[1]}')
session = self._get_session_by_address_(address)
session.on_packet_received(data)
except Exception as e:
print(e)
break
sock.close()
def _get_session_by_address_(self, address) -> TEUDPReceiveSession:
# Search for existing session
for session in self.sessions:
if session.get_address() == address:
return session
# Create and return new session
print(f'Created session for {address[0]}:{address[1]}')
self.sessions.append(TEUDPReceiveSession(address, 2))
return self.sessions[-1]
def _update_sessions_(self, sock):
sessions = copy.copy(self.sessions)
for session in sessions:
result = session.update()
if result is None:
continue
response = bytes([result[0], result[1]])
print(f'Sending result {response} to address {session.get_address()}')
sock.sendto(response, session.get_address())
print(f'Removing session for address {session.get_address()}')
self.sessions.remove(session)