mirror of
https://github.com/svpcom/wfb-ng.git
synced 2025-03-19 04:54:11 -03:00
Change connect/listen field format in config. Move wlan radio init to python
This commit is contained in:
parent
1936713c81
commit
97a1274581
@ -36,7 +36,7 @@ A: Wifibroadcast is not tied to any GPU - it operates with UDP packets. But to g
|
||||
## Theory
|
||||
Wifibroadcast puts the wifi cards into monitor mode. This mode allows to send and receive arbitrary packets without association and waiting for ACK packets.
|
||||
[Analysis of Injection Capabilities and Media Access of IEEE 802.11 Hardware in Monitor Mode](https://github.com/svpcom/wifibroadcast/blob/master/patches/Analysis%20of%20Injection%20Capabilities%20and%20Media%20Access%20of%20IEEE%20802.11%20Hardware%20in%20Monitor%20Mode.pdf)
|
||||
|
||||
[802.11 timings](https://github.com/ewa/802.11-data)
|
||||
Sample usage chain:
|
||||
-------------------
|
||||
```
|
||||
|
BIN
patches/mimo_for_dummies.pdf
Normal file
BIN
patches/mimo_for_dummies.pdf
Normal file
Binary file not shown.
@ -1,24 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [ $# -lt 2 ]
|
||||
then echo "Usage: $0 <profile> <wlan1> [wlan2] ..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROFILE=$1
|
||||
shift 1
|
||||
WLANS=$@
|
||||
CHANNEL5G="149" # Freq: 5805 (5795–5815) BW 40 MHz
|
||||
|
||||
for WLAN in $WLANS
|
||||
do
|
||||
echo "Setting $WLAN to channel $CHANNEL5G"
|
||||
ifconfig $WLAN down
|
||||
iw dev $WLAN set monitor otherbss
|
||||
iw reg set BO
|
||||
ifconfig $WLAN up
|
||||
iw dev $WLAN set channel $CHANNEL5G HT40+
|
||||
done
|
||||
|
||||
exec python -m telemetry.server $PROFILE $WLANS
|
@ -6,7 +6,7 @@ ReloadPropagatedFrom=wifibroadcast.service
|
||||
[Service]
|
||||
Type=simple
|
||||
EnvironmentFile=/etc/default/wifibroadcast
|
||||
ExecStart=/usr/bin/wfb-server.sh %i ${WFB_NICS}
|
||||
ExecStart=/usr/bin/python -m telemetry.server %i ${WFB_NICS}
|
||||
TimeoutStopSec=5s
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
|
1
setup.py
1
setup.py
@ -66,7 +66,6 @@ setup(
|
||||
packages=find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]),
|
||||
zip_safe=False,
|
||||
entry_points={'console_scripts': ['wfb-cli=telemetry.cli:main']},
|
||||
scripts=['scripts/wfb-server.sh'],
|
||||
package_data={'telemetry.conf': ['master.cfg', 'site.cfg']},
|
||||
data_files = [('/usr/bin', ['wfb_tx', 'wfb_rx', 'wfb_keygen']),
|
||||
('/lib/systemd/system', ['scripts/wifibroadcast.service',
|
||||
|
@ -135,7 +135,7 @@ def init(stdscr, profile):
|
||||
i.scrollok(1)
|
||||
|
||||
if cfg_video.stats_port is not None:
|
||||
reactor.connectTCP('127.0.0.1', cfg_video.stats_port, AntennaStatClientFactory(status_win1, cfg_video.listen is not None))
|
||||
reactor.connectTCP('127.0.0.1', cfg_video.stats_port, AntennaStatClientFactory(status_win1, cfg_video.peer.startswith('listen:')))
|
||||
else:
|
||||
status_win1.addstr(0, 0, '[statistics disabled]', curses.A_REVERSE)
|
||||
status_win1.refresh()
|
||||
|
@ -3,6 +3,7 @@ conf_dir = '/etc'
|
||||
bin_dir = '/usr/bin'
|
||||
tmp_dir = '/tmp'
|
||||
|
||||
|
||||
[common]
|
||||
debug = False
|
||||
version = '0.0.1.trunk'
|
||||
@ -11,6 +12,9 @@ commit = None
|
||||
radio_mtu = 1446 # MAX_PAYLOAD_SIZE, don't change if doubt
|
||||
mavlink_agg_timeout = 0.1 # aggragate mavlink packets if less than radio_mtu but no longer than 100ms
|
||||
tx_sel_delta = 3 # hysteresis for antenna selection, [dB]
|
||||
wifi_channel = 165 # radio channel @5825 MHz, range: 5815–5835 MHz, width 20MHz
|
||||
wifi_region = 'BO' # Set CRDA region
|
||||
|
||||
|
||||
[gs_mavlink]
|
||||
keypair = 'gs.key' # keypair generated by wfb-keygen
|
||||
@ -19,21 +23,30 @@ stream_tx = 1 # radio port for mavlink tx
|
||||
stream_rx = 2 # radio port for mavlink rx
|
||||
port_rx = 14600 # udp port for internal use
|
||||
port_tx = 14601 # udp port range (from port_tx to port_tx + number of wlans) for internal use
|
||||
listen = None # udp port for incoming connection, conflicts with 'connect'
|
||||
connect = 14550 # udp port for outgoing connection, conflicts with 'listen'
|
||||
|
||||
peer = 'connect://127.0.0.1:14550' # outgoing connection
|
||||
# peer = 'listen://0.0.0.0:14550' # incoming connection
|
||||
|
||||
inject_rssi = True # inject RADIO_STATUS packets
|
||||
|
||||
# Radio settings for TX and RX
|
||||
bandwidth = 20 # bandwidth 20 or 40 MHz
|
||||
|
||||
# Radiotap flags for TX:
|
||||
bandwidth = 40 # bandwidth 20 or 40 MHz
|
||||
short_gi = True # use short GI or not
|
||||
short_gi = False # use short GI or not
|
||||
stbc = 1 # stbc streams: 1, 2, 3 or 0 if unused
|
||||
mcs_index = 1 # mcs index
|
||||
|
||||
|
||||
[gs_video]
|
||||
keypair = 'gs.key' # keypair generated by wfb-keygen
|
||||
stats_port = 8002 # used by wfb-cli
|
||||
stream = 3 # radio port for video stream
|
||||
listen = None # udp port for video source (drone) or None for GS
|
||||
connect = 5600 # udp port for video sink (GS) or None for drone
|
||||
peer = 'connect://127.0.0.1:5600' # outgoing connection for video sink (GS)
|
||||
|
||||
# Radio settings for RX
|
||||
bandwidth = 20 # bandwidth 20 or 40 MHz
|
||||
|
||||
|
||||
[drone_mavlink]
|
||||
keypair = 'drone.key'
|
||||
@ -42,23 +55,31 @@ stream_tx = 2
|
||||
stream_rx = 1
|
||||
port_rx = 14700
|
||||
port_tx = 14701
|
||||
listen = None
|
||||
connect = 14560
|
||||
|
||||
peer = 'listen://0.0.0.0:14560' # incoming connection
|
||||
#peer = 'connect://127.0.0.1:14560' # outgoing connection
|
||||
|
||||
inject_rssi = True # inject RADIO_STATUS packets
|
||||
|
||||
# Radio settings for TX and RX
|
||||
bandwidth = 20 # bandwidth 20 or 40 MHz
|
||||
|
||||
# Radiotap flags for TX:
|
||||
bandwidth = 40 # bandwidth 20 or 40 MHz
|
||||
short_gi = True # use short GI or not
|
||||
short_gi = False # use short GI or not
|
||||
stbc = 1 # stbc streams: 1, 2, 3 or 0 if unused
|
||||
mcs_index = 1 # mcs index
|
||||
|
||||
|
||||
[drone_video]
|
||||
keypair = 'drone.key'
|
||||
stats_port = None
|
||||
stream = 3
|
||||
listen = 5602
|
||||
connect = None
|
||||
peer = 'listen://0.0.0.0:5602' # listen for video stream (drone)
|
||||
|
||||
# Radio settings for TX and RX
|
||||
bandwidth = 20 # bandwidth 20 or 40 MHz
|
||||
|
||||
# Radiotap flags for TX:
|
||||
bandwidth = 40 # bandwidth 20 or 40 MHz
|
||||
short_gi = True # use short GI or not
|
||||
short_gi = False # use short GI or not
|
||||
stbc = 1 # stbc streams: 1, 2, 3 or 0 if unused
|
||||
mcs_index = 1 # mcs index
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2018 Vasily Evseenko <svpcom@p2ptech.org>
|
||||
# Copyright (C) 2018, 2019 Vasily Evseenko <svpcom@p2ptech.org>
|
||||
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@ -22,10 +22,11 @@ import sys
|
||||
import time
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
||||
from itertools import groupby
|
||||
from twisted.python import log
|
||||
from twisted.internet import reactor, defer
|
||||
from twisted.internet import reactor, defer, utils
|
||||
from twisted.internet.protocol import ProcessProtocol, DatagramProtocol, Protocol, Factory
|
||||
from twisted.protocols.basic import LineReceiver
|
||||
from twisted.internet.error import ReactorNotRunning
|
||||
@ -34,6 +35,36 @@ from telemetry.common import abort_on_crash, exit_status
|
||||
from telemetry.proxy import UDPProxyProtocol
|
||||
from telemetry.conf import settings
|
||||
|
||||
connect_re = re.compile(r'^connect://(?P<addr>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+):(?P<port>[0-9]+)$', re.IGNORECASE)
|
||||
listen_re = re.compile(r'^listen://(?P<addr>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+):(?P<port>[0-9]+)$', re.IGNORECASE)
|
||||
|
||||
|
||||
class ExecError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def call_and_check_rc(cmd, *args):
|
||||
def _check_rc((stdout, stderr, rc)):
|
||||
if rc != 0:
|
||||
err = ExecError('RC %d: %s %s' % (rc, cmd, ' '.join(args)))
|
||||
err.stdout = stdout.strip()
|
||||
err.stderr = stderr.strip()
|
||||
raise err
|
||||
|
||||
log.msg('# %s' % (' '.join((cmd,) + args),))
|
||||
if stdout:
|
||||
log.msg(stdout)
|
||||
|
||||
def _got_signal(f):
|
||||
f.trap(tuple)
|
||||
stdout, stderr, signum = f.value
|
||||
err = ExecError('Got signal %d: %s %s' % (signum, cmd, ' '.join(args)))
|
||||
err.stdout = stdout.strip()
|
||||
err.stderr = stderr.strip()
|
||||
raise err
|
||||
|
||||
return utils.getProcessOutputAndValue(cmd, args, env=os.environ).addCallbacks(_check_rc, _got_signal)
|
||||
|
||||
|
||||
class BadTelemetry(Exception):
|
||||
pass
|
||||
@ -242,10 +273,38 @@ class TXProtocol(ProcessProtocol):
|
||||
return df.addCallback(lambda _: self.df)
|
||||
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def init_wlans(profile, wlans):
|
||||
max_bw = max(getattr(getattr(settings, '%s_mavlink' % profile), 'bandwidth'),
|
||||
getattr(getattr(settings, '%s_video' % profile), 'bandwidth'))
|
||||
|
||||
if max_bw == 20:
|
||||
ht_mode = 'HT20'
|
||||
elif max_bw == 40:
|
||||
ht_mode = 'HT40+'
|
||||
else:
|
||||
raise Exception('Unsupported bandwith %d MHz' % (max_bw,))
|
||||
|
||||
try:
|
||||
yield call_and_check_rc('iw', 'reg', 'set', settings.common.wifi_region)
|
||||
for wlan in wlans:
|
||||
yield call_and_check_rc('ifconfig', wlan, 'down')
|
||||
yield call_and_check_rc('iw', 'dev', wlan, 'set', 'monitor', 'otherbss')
|
||||
yield call_and_check_rc('ifconfig', wlan, 'up')
|
||||
yield call_and_check_rc('iw', 'dev', wlan, 'set', 'channel', str(settings.common.wifi_channel), ht_mode)
|
||||
except ExecError as v:
|
||||
if v.stdout:
|
||||
log.msg(v.stdout, isError=1)
|
||||
if v.stderr:
|
||||
log.msg(v.stderr, isError=1)
|
||||
raise
|
||||
|
||||
def init(profile, wlans):
|
||||
def _init_services(_):
|
||||
return defer.gatherResults([defer.maybeDeferred(init_mavlink, profile, wlans),
|
||||
defer.maybeDeferred(init_video, profile, wlans)])\
|
||||
.addErrback(lambda f: f.trap(defer.FirstError) and f.value.subFailure)
|
||||
return init_wlans(profile, wlans).addCallback(_init_services)
|
||||
|
||||
|
||||
def init_mavlink(profile, wlans):
|
||||
@ -260,19 +319,27 @@ def init_mavlink(profile, wlans):
|
||||
cfg.stream_tx, cfg.port_tx, os.path.join(settings.path.conf_dir, cfg.keypair),
|
||||
cfg.bandwidth, "short" if cfg.short_gi else "long", cfg.stbc, cfg.mcs_index)).split() + wlans
|
||||
|
||||
if cfg.listen:
|
||||
if connect_re.match(cfg.peer):
|
||||
m = connect_re.match(cfg.peer)
|
||||
connect = m.group('addr'), int(m.group('port'))
|
||||
listen = None
|
||||
log.msg('Connect telem stream %d(RX), %d(TX) to %s:%d' % (cfg.stream_rx, cfg.stream_tx, connect[0], connect[1]))
|
||||
elif listen_re.match(cfg.peer):
|
||||
m = listen_re.match(cfg.peer)
|
||||
listen = m.group('addr'), int(m.group('port'))
|
||||
connect = None
|
||||
listen = cfg.listen
|
||||
log.msg('Listen for telem stream %d(RX), %d(TX) on %s:%d' % (cfg.stream_rx, cfg.stream_tx, listen[0], listen[1]))
|
||||
else:
|
||||
connect = ('127.0.0.1', cfg.connect)
|
||||
listen = 0
|
||||
raise Exception('Unsupport peer address: %s' % (cfg.peer,))
|
||||
|
||||
# The first argument is not None only if we initiate mavlink connection
|
||||
p_in = UDPProxyProtocol(connect, agg_max_size=settings.common.radio_mtu,
|
||||
agg_timeout=settings.common.mavlink_agg_timeout, inject_rssi=cfg.inject_rssi)
|
||||
p_tx_l = [UDPProxyProtocol(('127.0.0.1', cfg.port_tx + i)) for i, _ in enumerate(wlans)]
|
||||
p_rx = UDPProxyProtocol()
|
||||
p_rx.peer = p_in
|
||||
sockets = [ reactor.listenUDP(listen, p_in), reactor.listenUDP(cfg.port_rx, p_rx) ]
|
||||
sockets = [ reactor.listenUDP(listen[1] if listen else 0, p_in),
|
||||
reactor.listenUDP(cfg.port_rx, p_rx) ]
|
||||
sockets += [ reactor.listenUDP(0, p_tx) for p_tx in p_tx_l ]
|
||||
|
||||
log.msg('Telem RX: %s' % (' '.join(cmd_rx),))
|
||||
@ -296,33 +363,44 @@ def init_mavlink(profile, wlans):
|
||||
def init_video(profile, wlans):
|
||||
cfg = getattr(settings, '%s_video' % (profile,))
|
||||
|
||||
if cfg.listen:
|
||||
if listen_re.match(cfg.peer):
|
||||
m = listen_re.match(cfg.peer)
|
||||
listen = m.group('addr'), int(m.group('port'))
|
||||
log.msg('Listen for video stream %d on %s:%d' % (cfg.stream, listen[0], listen[1]))
|
||||
|
||||
# We don't use TX diversity for video streaming due to only one transmitter on the vehichle
|
||||
cmd = ('%s -p %d -u %d -K %s -B %d -G %s -S %d -M %d %s' % \
|
||||
(os.path.join(settings.path.bin_dir, 'wfb_tx'), cfg.stream,
|
||||
cfg.listen, os.path.join(settings.path.conf_dir, cfg.keypair),
|
||||
listen[1], os.path.join(settings.path.conf_dir, cfg.keypair),
|
||||
cfg.bandwidth, "short" if cfg.short_gi else "long", cfg.stbc, cfg.mcs_index,
|
||||
wlans[0])).split()
|
||||
|
||||
df = TXProtocol(cmd, 'video tx').start()
|
||||
else:
|
||||
elif connect_re.match(cfg.peer):
|
||||
m = connect_re.match(cfg.peer)
|
||||
connect = m.group('addr'), int(m.group('port'))
|
||||
log.msg('Send video stream %d to %s:%d' % (cfg.stream, connect[0], connect[1]))
|
||||
|
||||
ant_f = AntennaFactory(None, None)
|
||||
if cfg.stats_port:
|
||||
reactor.listenTCP(cfg.stats_port, ant_f)
|
||||
|
||||
cmd = ('%s -p %d -u %d -K %s' % \
|
||||
(os.path.join(settings.path.bin_dir, 'wfb_rx'), cfg.stream, cfg.connect,
|
||||
cmd = ('%s -p %d -c %s -u %d -K %s' % \
|
||||
(os.path.join(settings.path.bin_dir, 'wfb_rx'),
|
||||
cfg.stream, connect[0], connect[1],
|
||||
os.path.join(settings.path.conf_dir, cfg.keypair))).split() + wlans
|
||||
|
||||
df = RXProtocol(ant_f, cmd, 'video rx').start()
|
||||
else:
|
||||
raise Exception('Unsupport peer address: %s' % (cfg.peer,))
|
||||
|
||||
log.msg('Video: %s' % (' '.join(cmd),))
|
||||
return df
|
||||
|
||||
def main():
|
||||
log.startLogging(sys.stdout)
|
||||
|
||||
reactor.callWhenRunning(lambda: defer.maybeDeferred(init, sys.argv[1], sys.argv[2:])\
|
||||
profile, wlans = sys.argv[1], sys.argv[2:]
|
||||
reactor.callWhenRunning(lambda: defer.maybeDeferred(init, profile, wlans)\
|
||||
.addErrback(abort_on_crash))
|
||||
reactor.run()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user