Skip to content

Commit

Permalink
Add support for rx-only cards
Browse files Browse the repository at this point in the history
  • Loading branch information
svpcom committed Sep 26, 2024
1 parent 340e699 commit b9ba1b6
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 23 deletions.
2 changes: 1 addition & 1 deletion wfb_ng/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def get_allocator(node):
iw dev {{ wlan }} set monitor otherbss
ip link set {{ wlan }} up
iw dev {{ wlan }} set channel {{ channel[wlan] }} {{ ht_mode }}
{% if txpower[wlan] != None %}
{% if txpower[wlan] not in (None, 'off') %}
iw dev {{ wlan }} set txpower fixed {{ txpower[wlan] }}
{% endif %}
{% endfor %}
Expand Down
3 changes: 2 additions & 1 deletion wfb_ng/conf/master.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ wifi_channel = 165 # radio channel @5825 MHz, range: 5815-5835 MHz, width

wifi_region = 'BO' # Set CRDA region
wifi_txpower = None # Leave None to use default power settings from driver.
# There is a special value 'off' for RX only cards.
# For 8812au set to -dBm * 100. I.e for 30dBm set to -3000
# For 8812eu set to dBm * 100. I.e for 30dBm set to 3000
# Also you can set own txpower for each wifi card, for example:
# {'wlan0': -100, 'wlan1': 100}
# {'wlan0': -100, 'wlan1': 100, 'wlan2': 'off'}


temp_measurement_interval = 10 # [s] (8812eu only) Internal RF path temp measurement.
Expand Down
7 changes: 6 additions & 1 deletion wfb_ng/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,9 @@ class StatsAndSelectorFactory(Factory):
Aggregate RX stats and select TX antenna
"""

def __init__(self, logger, cli_title=None, rf_temp_meter=None, is_cluster=False):
def __init__(self, logger, cli_title=None, rf_temp_meter=None, is_cluster=False, rx_only_wlan_ids=None):
self.is_cluster = is_cluster
self.rx_only_wlan_ids = rx_only_wlan_ids or set()
self.ant_sel_cb_list = []
self.rssi_cb_l = []
self.cur_stats = {}
Expand Down Expand Up @@ -188,6 +189,10 @@ def select_tx_antenna(self, stats_agg):
snr_min, snr_avg, snr_max) in stats_agg.items()),
lambda x: x[0]):

# Skip RX only cards in TX voting
if wlan_id in self.rx_only_wlan_ids:
continue

grp = list(grp)
# Use max average rssi [dBm] from all wlan's antennas
# Use max packet counter per antenna from all wlan's antennas
Expand Down
38 changes: 31 additions & 7 deletions wfb_ng/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import msgpack
import os
import time
import socket
import struct
import gzip
import argparse
Expand Down Expand Up @@ -88,13 +89,13 @@ def init_wlans(max_bw, wlans):

yield call_and_check_rc('iw', 'dev', wlan, 'set', 'channel', str(channel), ht_mode)

txpower = settings.common.wifi_txpower

# You can set own tx power for each card
if isinstance(settings.common.wifi_txpower, dict):
txpower = settings.common.wifi_txpower[wlan]
else:
txpower = settings.common.wifi_txpower
if isinstance(txpower, dict):
txpower = txpower[wlan]

if txpower is not None:
if txpower not in (None, 'off'):
yield call_and_check_rc('iw', 'dev', wlan, 'set', 'txpower', 'fixed', str(txpower))

except ExecError as v:
Expand All @@ -119,8 +120,21 @@ def init(profiles, wlans, cluster_mode):
def _ssh_exited(x, node):
raise Exception('Connection to %s closed, aborting' % (node,))

rx_only_wlan_ids = set()

if is_cluster:
services, cluster_nodes = parse_cluster_services(profiles)
for node in cluster_nodes:
node_ipv4_addr = struct.unpack("!L", socket.inet_aton(node))[0]
txpower = search_attr('wifi_txpower',
settings.cluster.nodes[node],
settings.common.__dict__)

for idx, wlan in enumerate(settings.cluster.nodes[node]['wlans']):
if (txpower[wlan] if isinstance(txpower, dict) else txpower) == 'off':
rx_only_wlan_ids.add((node_ipv4_addr << 24) | idx)


if cluster_mode == 'ssh':
for node, setup_script in gen_cluster_scripts(cluster_nodes, ssh_mode=True).items():
ssh_user = search_attr('ssh_user',
Expand Down Expand Up @@ -153,6 +167,13 @@ def _ssh_exited(x, node):
max_bw = max(cfg.bandwidth for _, tmp in services for _, _, cfg in tmp)
yield init_wlans(max_bw, wlans)

txpower = settings.common.wifi_txpower

for idx, wlan in enumerate(wlans):
if (txpower[wlan] if isinstance(txpower, dict) else txpower) == 'off':
rx_only_wlan_ids.add(idx)


sockets = []
cleanup_l = []

Expand All @@ -171,6 +192,9 @@ def _cleanup(x):
else:
rf_temp_meter = None

if rx_only_wlan_ids:
log.msg('RX-only wlan ids: %s' % (', '.join(map(hex, rx_only_wlan_ids))))

for profile, service_list in services:
# Domain wide antenna selector
profile_cfg = getattr(settings, profile)
Expand All @@ -192,7 +216,7 @@ def _cleanup(x):
'cluster' if is_cluster else ', '.join(wlans),
profile_cfg.link_domain)

ant_sel_f = StatsAndSelectorFactory(logger, cli_title, rf_temp_meter, is_cluster)
ant_sel_f = StatsAndSelectorFactory(logger, cli_title, rf_temp_meter, is_cluster, rx_only_wlan_ids)
cleanup_l.append(ant_sel_f)

link_id = hash_link_domain(profile_cfg.link_domain)
Expand All @@ -204,7 +228,7 @@ def _cleanup(x):
log.msg('Starting %s/%s@%s' % (profile, service_name, profile_cfg.link_domain))
dl.append(defer.maybeDeferred(type_map[service_type], service_name, srv_cfg,
srv_cfg.udp_peers_auto if is_cluster else wlans,
link_id, ant_sel_f, is_cluster))
link_id, ant_sel_f, is_cluster, rx_only_wlan_ids))

yield defer.gatherResults(dl, consumeErrors=True).addBoth(_cleanup).addErrback(lambda f: f.trap(defer.FirstError) and f.value.subFailure)

Expand Down
29 changes: 16 additions & 13 deletions wfb_ng/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ def parse_services(profile_name, udp_port_allocator):


@defer.inlineCallbacks
def init_udp_direct_tx(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster):
def init_udp_direct_tx(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster, rx_only_wlan_ids):
# Direct udp doesn't support TX diversity - only first card will be used.
# But if mirror mode is enabled it will use all cards.

if not cfg.mirror and (len(wlans) > 1 or ',' in wlans[0]):
raise Exception("udp_direct_tx doesn't supports diversity but multiple cards selected. Use udp_proxy for such case.")
if not cfg.mirror and (len(wlans) > 1 or ',' in wlans[0] or rx_only_wlan_ids):
raise Exception("udp_direct_tx doesn't supports diversity and/or rx-only wlans. Use udp_proxy for such case.")

if not listen_re.match(cfg.peer):
raise Exception('%s: unsupported peer address: %s' % (service_name, cfg.peer))
Expand Down Expand Up @@ -130,7 +130,7 @@ def init_udp_direct_tx(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster)
yield df


def init_udp_direct_rx(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster):
def init_udp_direct_rx(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster, rx_only_wlan_ids):
if not connect_re.match(cfg.peer):
raise Exception('%s: unsupported peer address: %s' % (service_name, cfg.peer))

Expand All @@ -156,7 +156,7 @@ def init_udp_direct_rx(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster)


@defer.inlineCallbacks
def init_mavlink(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster):
def init_mavlink(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster, rx_only_wlan_ids):
listen = None
connect = None
serial = None
Expand Down Expand Up @@ -281,7 +281,7 @@ def init_mavlink(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster):

log.msg('%s use wfb_tx ports %s, control_port %d' % (service_name, tx_ports, control_port))

p_tx_map = dict((wlan_id, UDPProxyProtocol(('127.0.0.1', port))) for wlan_id, port in tx_ports.items())
p_tx_map = dict((wlan_id, UDPProxyProtocol(('127.0.0.1', port))) for wlan_id, port in tx_ports.items() if wlan_id not in rx_only_wlan_ids)

if serial:
serial_port = SerialPort(p_in, os.path.join('/dev', serial[0]), reactor, baudrate=serial[1])
Expand All @@ -298,7 +298,8 @@ def ant_sel_cb(wlan_id):
if wlan_id is not None \
else list(p_tx_map.values())[0]

ant_sel_f.add_ant_sel_cb(ant_sel_cb)
if p_tx_map:
ant_sel_f.add_ant_sel_cb(ant_sel_cb)

# Report RSSI to OSD
ant_sel_f.add_rssi_cb(p_in.send_rssi)
Expand All @@ -320,7 +321,7 @@ def _cleanup(x):


@defer.inlineCallbacks
def init_tunnel(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster):
def init_tunnel(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster, rx_only_wlan_ids):
p_in = TUNTAPProtocol(mtu=settings.common.radio_mtu,
agg_timeout=settings.common.tunnel_agg_timeout)

Expand Down Expand Up @@ -383,7 +384,7 @@ def init_tunnel(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster):
control_port = yield control_port_df

log.msg('%s use wfb_tx ports %s, control_port %d' % (service_name, tx_ports, control_port))
p_tx_map = dict((wlan_id, UDPProxyProtocol(('127.0.0.1', port))) for wlan_id, port in tx_ports.items())
p_tx_map = dict((wlan_id, UDPProxyProtocol(('127.0.0.1', port))) for wlan_id, port in tx_ports.items() if wlan_id not in rx_only_wlan_ids)

tun_ep = TUNTAPTransport(reactor, p_in, cfg.ifname, cfg.ifaddr, mtu=settings.common.radio_mtu, default_route=cfg.default_route)
sockets += [ reactor.listenUDP(0, p_tx) for p_tx in p_tx_map.values() ]
Expand All @@ -402,7 +403,8 @@ def ant_sel_cb(wlan_id):
else:
p_in.all_peers = list(p_tx_map.values())

ant_sel_f.add_ant_sel_cb(ant_sel_cb)
if p_tx_map:
ant_sel_f.add_ant_sel_cb(ant_sel_cb)

dl.append(RXProtocol(ant_sel_f, cmd_rx, '%s rx' % (service_name,)).start())

Expand All @@ -417,7 +419,7 @@ def _cleanup(x):


@defer.inlineCallbacks
def init_udp_proxy(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster):
def init_udp_proxy(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster, rx_only_wlan_ids):
listen = None
connect = None

Expand Down Expand Up @@ -500,15 +502,16 @@ def init_udp_proxy(service_name, cfg, wlans, link_id, ant_sel_f, is_cluster):

log.msg('%s use wfb_tx ports %s, control_port %d' % (service_name, tx_ports, control_port))

p_tx_map = dict((wlan_id, UDPProxyProtocol(('127.0.0.1', port))) for wlan_id, port in tx_ports.items())
p_tx_map = dict((wlan_id, UDPProxyProtocol(('127.0.0.1', port))) for wlan_id, port in tx_ports.items() if wlan_id not in rx_only_wlan_ids)
sockets += [ reactor.listenUDP(0, p_tx) for p_tx in p_tx_map.values() ]

def ant_sel_cb(wlan_id):
p_in.peer = p_tx_map[wlan_id] \
if wlan_id is not None \
else list(p_tx_map.values())[0]

ant_sel_f.add_ant_sel_cb(ant_sel_cb)
if p_tx_map:
ant_sel_f.add_ant_sel_cb(ant_sel_cb)

def _cleanup(x):
for s in sockets:
Expand Down

0 comments on commit b9ba1b6

Please sign in to comment.