From 576ff2669af0800cad97c8c7a15159e9a990e95d Mon Sep 17 00:00:00 2001 From: Vasily Evseenko Date: Sun, 23 Dec 2018 15:20:12 +0300 Subject: [PATCH] Set BW, GI, STBC and MCS index in runtime for each stream separately. --- src/tx.cpp | 65 +++++++++++++++++++++++++++++++++++++-- src/wifibroadcast.hpp | 12 ++++++-- telemetry/conf/local.cfg | 18 +++++++++++ telemetry/conf/master.cfg | 17 +++++++++- telemetry/server.py | 30 ++++++++++++++---- 5 files changed, 129 insertions(+), 13 deletions(-) diff --git a/src/tx.cpp b/src/tx.cpp index 9571fce6..cca89b10 100644 --- a/src/tx.cpp +++ b/src/tx.cpp @@ -282,9 +282,15 @@ int main(int argc, char * const *argv) int opt; uint8_t k=8, n=12, radio_port=1; int udp_port=5600; + + int bandwidth = 40; + int short_gi = 1; + int stbc = 1; + int mcs_index = 1; + string keypair = "tx.key"; - while ((opt = getopt(argc, argv, "K:k:n:u:r:p:")) != -1) { + while ((opt = getopt(argc, argv, "K:k:n:u:r:p:B:G:S:M:")) != -1) { switch (opt) { case 'K': keypair = optarg; @@ -301,11 +307,24 @@ int main(int argc, char * const *argv) case 'p': radio_port = atoi(optarg); break; + case 'B': + bandwidth = atoi(optarg); + break; + case 'G': + short_gi = (optarg[0] == 's' || optarg[0] == 'S') ? 1 : 0; + break; + case 'S': + stbc = atoi(optarg); + break; + case 'M': + mcs_index = atoi(optarg); + break; default: /* '?' */ show_usage: - fprintf(stderr, "Usage: %s [-K tx_key] [-k RS_K] [-n RS_N] [-u udp_port] [-p radio_port] interface1 [interface2] ...\n", + fprintf(stderr, "Usage: %s [-K tx_key] [-k RS_K] [-n RS_N] [-u udp_port] [-p radio_port] [-B bandwidth] [-G guard_interval] [-S stbc] [-M mcs_index] interface1 [interface2] ...\n", argv[0]); - fprintf(stderr, "Default: K='%s', k=%d, n=%d, udp_port=%d, radio_port=%d\n", keypair.c_str(), k, n, udp_port, radio_port); + fprintf(stderr, "Default: K='%s', k=%d, n=%d, udp_port=%d, radio_port=%d bandwidth=%d guard_interval=%s stbc=%d mcs_index=%d\n", + keypair.c_str(), k, n, udp_port, radio_port, bandwidth, short_gi ? "short" : "long", stbc, mcs_index); fprintf(stderr, "Radio MTU: %lu\n", (unsigned long)MAX_PAYLOAD_SIZE); fprintf(stderr, "WFB version " WFB_VERSION "\n"); exit(1); @@ -316,6 +335,46 @@ int main(int argc, char * const *argv) goto show_usage; } + // Set flags in radiotap header + { + uint8_t flags = 0; + switch(bandwidth) { + case 20: + flags |= IEEE80211_RADIOTAP_MCS_BW_20; + break; + case 40: + flags |= IEEE80211_RADIOTAP_MCS_BW_40; + break; + default: + fprintf(stderr, "Unsupported bandwidth: %d\n", bandwidth); + exit(1); + } + + if(short_gi) + { + flags |= IEEE80211_RADIOTAP_MCS_SGI; + } + + switch(stbc) { + case 0: + break; + case 1: + flags |= (IEEE80211_RADIOTAP_MCS_STBC_1 << IEEE80211_RADIOTAP_MCS_STBC_SHIFT); + break; + case 2: + flags |= (IEEE80211_RADIOTAP_MCS_STBC_2 << IEEE80211_RADIOTAP_MCS_STBC_SHIFT); + break; + case 3: + flags |= (IEEE80211_RADIOTAP_MCS_STBC_3 << IEEE80211_RADIOTAP_MCS_STBC_SHIFT); + break; + default: + fprintf(stderr, "Unsupported STBC type: %d\n", stbc); + exit(1); + } + + radiotap_header[MCS_FLAGS_OFF] = flags; + radiotap_header[MCS_IDX_OFF] = mcs_index; + } try { vector tx_fd; diff --git a/src/wifibroadcast.hpp b/src/wifibroadcast.hpp index a4bf762f..3ab024e9 100644 --- a/src/wifibroadcast.hpp +++ b/src/wifibroadcast.hpp @@ -65,16 +65,22 @@ extern string string_format(const char *format, ...); #define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5 #define MCS_KNOWN (IEEE80211_RADIOTAP_MCS_HAVE_MCS | IEEE80211_RADIOTAP_MCS_HAVE_BW | IEEE80211_RADIOTAP_MCS_HAVE_GI | IEEE80211_RADIOTAP_MCS_HAVE_STBC) // | IEEE80211_RADIOTAP_MCS_HAVE_FMT) -#define MCS_FLAGS (IEEE80211_RADIOTAP_MCS_BW_40 | IEEE80211_RADIOTAP_MCS_SGI | (IEEE80211_RADIOTAP_MCS_STBC_1 << IEEE80211_RADIOTAP_MCS_STBC_SHIFT) ) // | IEEE80211_RADIOTAP_MCS_FMT_GF) -static const uint8_t radiotap_header[] __attribute__((unused)) = { +// Default is MCS#1 -- QPSK 1/2 40MHz SGI -- 30 Mbit/s +// MCS_FLAGS = (IEEE80211_RADIOTAP_MCS_BW_40 | IEEE80211_RADIOTAP_MCS_SGI | (IEEE80211_RADIOTAP_MCS_STBC_1 << IEEE80211_RADIOTAP_MCS_STBC_SHIFT) ) // | IEEE80211_RADIOTAP_MCS_FMT_GF) + +static uint8_t radiotap_header[] __attribute__((unused)) = { 0x00, 0x00, // <-- radiotap version 0x0d, 0x00, // <- radiotap header length 0x00, 0x80, 0x08, 0x00, // <-- radiotap present flags: RADIOTAP_TX_FLAGS + RADIOTAP_MCS 0x08, 0x00, // RADIOTAP_F_TX_NOACK - MCS_KNOWN , MCS_FLAGS, 0x01 // MCS default is #1 -- QPSK 1/2 40MHz SGI -- 30 Mbit/s + MCS_KNOWN , 0x00, 0x00 // bitmap, flags, mcs_index }; +// offset of MCS_FLAGS and MCS index +#define MCS_FLAGS_OFF 11 +#define MCS_IDX_OFF 12 + //the last byte of the mac address is recycled as a port number #define SRC_MAC_LASTBYTE 15 #define DST_MAC_LASTBYTE 21 diff --git a/telemetry/conf/local.cfg b/telemetry/conf/local.cfg index e402da66..c6876f4b 100644 --- a/telemetry/conf/local.cfg +++ b/telemetry/conf/local.cfg @@ -4,3 +4,21 @@ bin_dir = '.' [common] #debug=True + +# [drone_video] +# bandwidth = 20 # bandwidth 20 or 40 MHz +# 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_mavlink] +# bandwidth = 20 # bandwidth 20 or 40 MHz +# 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_mavlink] +# bandwidth = 20 # bandwidth 20 or 40 MHz +# short_gi = False # use short GI or not +# stbc = 1 # stbc streams: 1, 2, 3 or 0 if unused +# mcs_index = 1 # mcs index diff --git a/telemetry/conf/master.cfg b/telemetry/conf/master.cfg index 0d195823..a463dc48 100644 --- a/telemetry/conf/master.cfg +++ b/telemetry/conf/master.cfg @@ -22,6 +22,11 @@ port_tx = 14601 # udp port range (from port_tx to port_tx + number of wlans) listen = None # udp port for incoming connection, conflicts with 'connect' connect = 14550 # udp port for outgoing connection, conflicts with 'listen' inject_rssi = True # inject RADIO_STATUS packets +# Radiotap flags for TX: +bandwidth = 40 # bandwidth 20 or 40 MHz +short_gi = True # 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 @@ -40,10 +45,20 @@ port_tx = 14701 listen = None connect = 14560 inject_rssi = True # inject RADIO_STATUS packets +# Radiotap flags for TX: +bandwidth = 40 # bandwidth 20 or 40 MHz +short_gi = True # 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 \ No newline at end of file +connect = None +# Radiotap flags for TX: +bandwidth = 40 # bandwidth 20 or 40 MHz +short_gi = True # use short GI or not +stbc = 1 # stbc streams: 1, 2, 3 or 0 if unused +mcs_index = 1 # mcs index diff --git a/telemetry/server.py b/telemetry/server.py index 54d32c44..1a457121 100644 --- a/telemetry/server.py +++ b/telemetry/server.py @@ -237,7 +237,8 @@ def processEnded(self, status): self.df.errback(status) def start(self): - df = defer.maybeDeferred(reactor.spawnProcess, self, self.cmd[0], self.cmd, env=None, childFDs={0: "w", 1: "r", 2: "r"}) + df = defer.maybeDeferred(reactor.spawnProcess, self, self.cmd[0], self.cmd, env=None, + childFDs={0: "w", 1: "r", 2: "r"}) return df.addCallback(lambda _: self.df) @@ -249,8 +250,15 @@ def init(profile, wlans): def init_mavlink(profile, wlans): cfg = getattr(settings, '%s_mavlink' % (profile,)) - cmd_rx = ('%s -p %d -u %d -K %s' % (os.path.join(settings.path.bin_dir, 'wfb_rx'), cfg.stream_rx, cfg.port_rx, os.path.join(settings.path.conf_dir, cfg.keypair))).split() + wlans - cmd_tx = ('%s -p %d -u %d -K %s' % (os.path.join(settings.path.bin_dir, 'wfb_tx'), cfg.stream_tx, cfg.port_tx, os.path.join(settings.path.conf_dir, cfg.keypair))).split() + wlans + + cmd_rx = ('%s -p %d -u %d -K %s' % \ + (os.path.join(settings.path.bin_dir, 'wfb_rx'), cfg.stream_rx, + cfg.port_rx, os.path.join(settings.path.conf_dir, cfg.keypair))).split() + wlans + + cmd_tx = ('%s -p %d -u %d -K %s -B %d -G %s -S %d -M %d' % \ + (os.path.join(settings.path.bin_dir, 'wfb_tx'), + 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: connect = None @@ -259,7 +267,8 @@ def init_mavlink(profile, wlans): connect = ('127.0.0.1', cfg.connect) listen = 0 - p_in = UDPProxyProtocol(connect, agg_max_size=settings.common.radio_mtu, agg_timeout=settings.common.mavlink_agg_timeout, inject_rssi=cfg.inject_rssi) + 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 @@ -289,13 +298,22 @@ def init_video(profile, wlans): if cfg.listen: # 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 %s' % (os.path.join(settings.path.bin_dir, 'wfb_tx'), cfg.stream, cfg.listen, os.path.join(settings.path.conf_dir, cfg.keypair), wlans[0])).split() + 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), + cfg.bandwidth, "short" if cfg.short_gi else "long", cfg.stbc, cfg.mcs_index, + wlans[0])).split() + df = TXProtocol(cmd, 'video tx').start() else: 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, os.path.join(settings.path.conf_dir, cfg.keypair))).split() + wlans + + cmd = ('%s -p %d -u %d -K %s' % \ + (os.path.join(settings.path.bin_dir, 'wfb_rx'), cfg.stream, cfg.connect, + os.path.join(settings.path.conf_dir, cfg.keypair))).split() + wlans + df = RXProtocol(ant_f, cmd, 'video rx').start() log.msg('Video: %s' % (' '.join(cmd),))