From 671ec3680c214a9aec389814607968d4acc86224 Mon Sep 17 00:00:00 2001 From: Vasily Evseenko Date: Sat, 10 Aug 2024 18:38:43 +0300 Subject: [PATCH] Update TX card selection logic 1. Now only cards with near-maximum RX packet counter will be used in RSSI filtering. 2. Python code cleanup --- .pylintrc | 2 ++ Makefile | 4 ++++ wfb_ng/conf/master.cfg | 6 ++++- wfb_ng/latency_test.py | 3 +-- wfb_ng/mavlink_protocol.py | 6 ++--- wfb_ng/proxy.py | 3 --- wfb_ng/server.py | 49 ++++++++++++++++++++++++++------------ wfb_ng/tuntap.py | 6 ++--- 8 files changed, 52 insertions(+), 27 deletions(-) create mode 100644 .pylintrc diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 00000000..f1cadfe6 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,2 @@ +[TYPECHECK] +ignored-classes=Section diff --git a/Makefile b/Makefile index 622afa20..ca2c8eef 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,10 @@ bdist: all_bin check: cppcheck --std=c++11 --library=std --library=posix --library=gnu --inline-suppr --template=gcc --enable=all --suppress=cstyleCast --suppress=missingOverride --suppress=missingIncludeSystem src/ + +pylint: + pylint --disable=R,C wfb_ng/*.py + clean: rm -rf env wfb_rx wfb_tx wfb_tx_cmd wfb_keygen dist deb_dist build wfb_ng.egg-info wfb-ng-*.tar.gz _trial_temp *~ src/*.o diff --git a/wfb_ng/conf/master.cfg b/wfb_ng/conf/master.cfg index 21326aad..a37401cd 100644 --- a/wfb_ng/conf/master.cfg +++ b/wfb_ng/conf/master.cfg @@ -22,7 +22,11 @@ radio_mtu = 1445 # Used for mavlink aggregation and for tunnel packets tunnel_agg_timeout= 0.005 # aggragate tuntap packets if less than radio_mtu but no longer than 5ms mavlink_agg_timeout = 0.1 # aggragate mavlink packets if less than radio_mtu but no longer than 100ms mavlink_err_rate = True # If true then inject RX error rate else absolute values -tx_sel_delta = 3 # hysteresis for antenna selection, [dB] + +tx_sel_rssi_delta = 3 # hysteresis for antenna selection by RSSI, [dB] +tx_sel_counter_abs_delta = 3 # hysteresis for antenna selection by RX packet counter +tx_sel_counter_rel_delta = 0.1 # default is max(3 packets or 10% of packets from the best antenna) + tx_rcv_buf_size = 2097152 # UDP SO_RCVBUF. Set 0 to use net.core.rmem_default. Increase in case of non-cbr data stream # This should not be greater than net.core.rmem_max diff --git a/wfb_ng/latency_test.py b/wfb_ng/latency_test.py index c2d9d2ab..d1c4b1b9 100755 --- a/wfb_ng/latency_test.py +++ b/wfb_ng/latency_test.py @@ -19,13 +19,12 @@ # import sys -import time import struct import os from twisted.python import log from twisted.internet import reactor, defer, task from twisted.internet.protocol import DatagramProtocol -from twisted.trial import unittest + from .common import df_sleep, abort_on_crash, exit_status diff --git a/wfb_ng/mavlink_protocol.py b/wfb_ng/mavlink_protocol.py index 2c61f71e..a91f7680 100644 --- a/wfb_ng/mavlink_protocol.py +++ b/wfb_ng/mavlink_protocol.py @@ -21,13 +21,13 @@ import struct import time -from . import call_and_check_rc, ExecError +from . import call_and_check_rc from .mavlink import MAV_MODE_FLAG_SAFETY_ARMED, MAVLINK_MSG_ID_HEARTBEAT, mavlink_map from zope.interface import implementer from twisted.python import log -from twisted.internet import reactor, defer, utils, interfaces -from twisted.internet.protocol import Protocol, DatagramProtocol, Factory +from twisted.internet import defer, interfaces +from twisted.internet.protocol import Protocol, Factory def unpack_mavlink(msg_id, mbuf): diff --git a/wfb_ng/proxy.py b/wfb_ng/proxy.py index a2de1a11..b145b970 100644 --- a/wfb_ng/proxy.py +++ b/wfb_ng/proxy.py @@ -18,9 +18,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # -import struct -import os - from contextlib import closing from twisted.python import log from twisted.internet import reactor, defer diff --git a/wfb_ng/server.py b/wfb_ng/server.py index a88e3ace..ba0ff1e0 100644 --- a/wfb_ng/server.py +++ b/wfb_ng/server.py @@ -27,12 +27,10 @@ import struct import gzip -from base64 import b85encode from itertools import groupby from twisted.python import log, failure -from twisted.python.logfile import LogFile from twisted.internet import reactor, defer, main as ti_main, threads, task -from twisted.internet.protocol import ProcessProtocol, Protocol, Factory +from twisted.internet.protocol import ProcessProtocol, Factory from twisted.protocols.basic import LineReceiver, Int32StringReceiver from twisted.internet.serialport import SerialPort @@ -114,7 +112,9 @@ def __init__(self, profile, wlans, link_domain, logger): # Select antenna #0 by default self.tx_sel = 0 - self.tx_sel_delta = settings.common.tx_sel_delta + self.tx_sel_rssi_delta = settings.common.tx_sel_rssi_delta + self.tx_sel_counter_rel_delta = settings.common.tx_sel_counter_rel_delta + self.tx_sel_counter_abs_delta = settings.common.tx_sel_counter_abs_delta # tcp sockets for UI self.ui_sessions = [] @@ -212,34 +212,53 @@ def _stats_agg_by_freq(self, ant_stats): snr_min, snr_avg, snr_max) in stats_agg.items()) def select_tx_antenna(self, stats_agg): - wlan_rssi = {} + wlan_rssi_and_pkts = {} + max_pkts = 0 - for k, grp in groupby(sorted(((ant_id >> 8) & 0xff, rssi_avg) \ + for k, grp in groupby(sorted(((ant_id >> 8) & 0xff, pkt_s, rssi_avg) \ for ant_id, (pkt_s, rssi_min, rssi_avg, rssi_max, snr_min, snr_avg, snr_max) in stats_agg.items()), lambda x: x[0]): - # Select max average rssi [dBm] from all wlan's antennas - wlan_rssi[k] = max(rssi for _, rssi in grp) - if not wlan_rssi: + grp = list(grp) + # Use max average rssi [dBm] from all wlan's antennas + # Use max packet counter per antenna from all wlan's antennas + rssi = max(rssi for _, pkt_s, rssi in grp) + pkts = max(pkt_s for _, pkt_s, rssi in grp) + max_pkts = max(pkts, max_pkts) + wlan_rssi_and_pkts[k] = (rssi, pkts) + + if not wlan_rssi_and_pkts: + return + + # Select antennas with near-maximum RX packet counters only + tx_sel_counter_thr = max_pkts - max(self.tx_sel_counter_abs_delta, max_pkts * self.tx_sel_counter_rel_delta) + ants_with_max_pkts = set(idx for idx, (rssi, pkt_s) in wlan_rssi_and_pkts.items() if pkt_s >= tx_sel_counter_thr) + + if not ants_with_max_pkts: return - cur_ant_rssi = wlan_rssi.get(self.tx_sel, -1000) - max_rssi, max_rssi_ant = max((rssi, idx) for idx, rssi in wlan_rssi.items()) + new_max_rssi, new_tx_ant = max((rssi, idx) for idx, (rssi, pkt_s) in wlan_rssi_and_pkts.items() if idx in ants_with_max_pkts) + cur_max_rssi = wlan_rssi_and_pkts.get(self.tx_sel, (-1000, 0))[0] + + if new_tx_ant == self.tx_sel: + return - if max_rssi <= cur_ant_rssi + self.tx_sel_delta: + if self.tx_sel in ants_with_max_pkts and new_max_rssi - cur_max_rssi < self.tx_sel_rssi_delta: + # Already selected antenna with near-maximum RX packets counter + # and other antennas doesn't have significally large RSSI return - log.msg('Switch TX antenna from %d to %d' % (self.tx_sel, max_rssi_ant)) + log.msg('Switch TX antenna #%d -> #%d, RSSI %d -> %d[dB]' % (self.tx_sel, new_tx_ant, cur_max_rssi, new_max_rssi)) for ant_sel_cb in self.ant_sel_cb_list: try: - ant_sel_cb(max_rssi_ant) + ant_sel_cb(new_tx_ant) except Exception: log.err() - self.tx_sel = max_rssi_ant + self.tx_sel = new_tx_ant def process_new_session(self, rx_id, session): if self.logger is not None: diff --git a/wfb_ng/tuntap.py b/wfb_ng/tuntap.py index 29f056b0..f16f63d2 100644 --- a/wfb_ng/tuntap.py +++ b/wfb_ng/tuntap.py @@ -19,19 +19,19 @@ # import os -from . import mavlink import fcntl import struct from collections import deque from twisted.python import log, failure -from twisted.internet import reactor, defer, abstract, main, task +from twisted.internet import defer, abstract, main, task from twisted.internet.protocol import Protocol, connectionDone from pyroute2 import IPRoute from contextlib import closing -from .conf import settings + from .proxy import ProxyProtocol + class TUNTAPTransport(abstract.FileDescriptor): TUN = 0x0001 TAP = 0x0002