Some years ago I wrote and used successfully a Python script for a Raspberry Pi to receive, unpack and display UDP multicast packets, broadcasted from an X-Plane flight simulator app running on a MS Windows PC.
In this moment I am trying to port this script to CircuitPython V8.0.0.-rc.2 on an Adafruit Feather ESP32-S2 with TFT,
however I am not able to proceed because, TMHO, the core module 'socketpool' lacks attributes I need for my project.
Ref: readthedocs_latest_socketpool
socketpool has (among some others) the following attributes:
'AF_INET', 'AF_INET6', 'EAI_NONAME', 'IPPROTO_TCP', 'SOCK_DGRAM', 'SOCK_RAW', 'SOCK_STREAM', 'TCP_NODELAY', 'gaierror', 'getaddrinfo', 'socket'
My 'wishlist' of attributes to add:
IPPROTO_UDP
SO_REUSEADDR
SOL_SOCKET
IPPROTO_IP
IP_ADD_MEMBERSHIP
INADDR_ANY
inet_aton()
Below an image of BECN packets captured using WireShark:
multicast_udp_packets_captured
The following is a test script to receive, unpack and print to REPL received multicast udp packets.
It fails because of socketpool.SocketPool is lacking the attributes listed above in my 'wishlist':
# code.py -- receive UDP multicast Beacon & Data packets sent from a desktop PC (MS Windows 11 Pro)
# running X-Plane 12 flight simulator which broadcast UDP multicast BECN & Data packets.
# This is a test script for CircuitPython V8.0.0-rc.2 to receive, unpack and display these packets.
# Platform: Adafruit Feather ESP32-S2 with TFT
# 2023-02-08 @PaulskPt Github
#type:ignore
import time, wifi, socketpool, os, struct, binascii
my_debug = True
ip = wifi.radio.ipv4_address
if ip:
s_ip = str(ip)
le_s_ip = len(s_ip)
if s_ip is not None and len(s_ip) > 0 and s_ip != '0.0.0.0':
print("\nWiFi already connected")
else:
wifi.radio.connect(ssid=os.getenv("CIRCUITPY_WIFI_SSID"), password=os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print("IP addr:", wifi.radio.ipv4_address)
try:
pool = socketpool.SocketPool(wifi.radio)
#udp_host = str(wifi.radio.ipv4_address) # LAN IP as a string
MCAST_GRP = "239.255.1.1"
MCAST_PORT = 49707 # a number of your choosing, should be 1024-65000
udp_buffer = bytearray(61) # stores our incoming packet
sock = pool.socket(pool.AF_INET, pool.SOCK_DGRAM, pool.IPPROTO_UDP) # UDP socket
sock.setsockopt(pool.SO_REUSEADDR, 1)
sock.settimeout(5)
sock.bind((MCAST_GRP, MCAST_PORT))
mreq = struct.pack("4sl", sock.inet_aton(MCAST_GRP), pool.INADDR_ANY)
sock.setsockopt(pool.IPPROTO_IP, pool.IP_ADD_MEMBERSHIP, mreq)
print(f"waiting for UDP packets from remote host to multicast group: \'{MCAST_GRP}\', port: {MCAST_PORT}")
except Exception as e:
raise
BeaconData = {}
data = {}
while not BeaconData:
try:
size, sender = sock.recvfrom_into(udp_buffer)
print(f"Received udp packet from {sender[0]}:", udp_buffer)
header = udp_buffer[0:4]
if header == b'BECN':
print("Received a BECN packet")
time.sleep(2)
# * Data
data = udp_buffer[5:21]
# struct becn_struct
# {
# uchar beacon_major_version; // 1 at the time of X-Plane 10.40
# uchar beacon_minor_version; // 1 at the time of X-Plane 10.40
# xint application_host_id; // 1 for X-Plane, 2 for PlaneMaker
# xint version_number; // 104014 for X-Plane 10.40b14 - 113201 for X-Plane 11.32
# uint role; // 1 for master, 2 for extern visual, 3 for iOS
# ushort port; // port number X-Plane is listening on
# xchr computer_name[strDIM]; // the hostname of the computer
# };
beacon_major_version = 0
beacon_minor_version = 0
application_host_id = 0
xplane_version_number = 0
role = 0
port = 0
(
beacon_major_version, # 1 at the time of X-Plane 10.40
beacon_minor_version, # 1 at the time of X-Plane 10.40, 2 at the time of X-Plane 11
application_host_id, # 1 for X-Plane, 2 for PlaneMaker
xplane_version_number, # 104014 for X-Plane 10.40b14 - 113201 for X-Plane 11.32
role, # 1 for master, 2 for extern visual, 3 for IOS
port, # port number X-Plane is listening on
) = struct.unpack("<BBiiIH", data)
if my_debug:
print('beacon_major_version = ', beacon_major_version)
print('beacon_minor_version = ', beacon_minor_version)
print('application_host_id = ', application_host_id)
# Originally beacon_minor_version was checked for a value of 1 but investigation by Paulsk revealed that X-Plane 11 returns a value of 2
computer_name = udp_buffer[21:-1]
if beacon_major_version == 1 \
and beacon_minor_version == 2 \
and application_host_id == 1:
BeaconData["IP"] = sender[0]
BeaconData["Port"] = port
BeaconData["hostname"] = computer_name.decode()
BeaconData["XPlaneVersion"] = xplane_version_number
BeaconData["role"] = role
if my_debug:
print('\nBeacon UDP packet received:')
print('Host IP =', BeaconData["IP"])
print('Port =', BeaconData["Port"])
print('Hostname =', BeaconData["hostname"])
print('X-Plane version =', BeaconData["XPlaneVersion"])
print('Role =', BeaconData["role"])
else:
print('Unknown packet from '+sender[0])
print(str(len(udp_buffer)) + ' bytes')
print(udp_buffer)
print(binascii.hexlify(udp_buffer))
except OSError as e:
if e.errno == 116: # ETIMEDOUT
raise
print("Done!")
Some years ago I wrote and used successfully a Python script for a Raspberry Pi to receive, unpack and display UDP multicast packets, broadcasted from an X-Plane flight simulator app running on a MS Windows PC.
In this moment I am trying to port this script to CircuitPython V8.0.0.-rc.2 on an Adafruit Feather ESP32-S2 with TFT,
however I am not able to proceed because, TMHO, the core module 'socketpool' lacks attributes I need for my project.
Ref: readthedocs_latest_socketpool
socketpool has (among some others) the following attributes:
'AF_INET', 'AF_INET6', 'EAI_NONAME', 'IPPROTO_TCP', 'SOCK_DGRAM', 'SOCK_RAW', 'SOCK_STREAM', 'TCP_NODELAY', 'gaierror', 'getaddrinfo', 'socket'
My 'wishlist' of attributes to add:
IPPROTO_UDP
SO_REUSEADDR
SOL_SOCKET
IPPROTO_IP
IP_ADD_MEMBERSHIP
INADDR_ANY
inet_aton()
Below an image of BECN packets captured using WireShark:
multicast_udp_packets_captured
The following is a test script to receive, unpack and print to REPL received multicast udp packets.
It fails because of socketpool.SocketPool is lacking the attributes listed above in my 'wishlist':