From 7180ffb3f74f095dcede5b389ce975909d87cace Mon Sep 17 00:00:00 2001 From: Vasily Evseenko Date: Tue, 28 May 2024 23:24:20 +0300 Subject: [PATCH] Show RF path temperature for 8812eu --- wfb_ng/cli.py | 16 +++++++++-- wfb_ng/conf/master.cfg | 8 ++++-- wfb_ng/server.py | 64 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 80 insertions(+), 8 deletions(-) diff --git a/wfb_ng/cli.py b/wfb_ng/cli.py index f36d81d..8d2ed1d 100644 --- a/wfb_ng/cli.py +++ b/wfb_ng/cli.py @@ -193,6 +193,7 @@ class AntennaStat(Int32StringReceiver): p = attrs['packets'] latency_d = attrs['latency'] tx_id = attrs['id'] + rf_temperature = attrs['rf_temperature'] window = self.factory.windows.get(tx_id) if window is None: @@ -218,12 +219,23 @@ class AntennaStat(Int32StringReceiver): human_rate(p['injected_bytes'][0]))) if latency_d: - addstr_markup(window, 2, 20, '{[ANT] pkt/s} {Injection} [us]') + addstr_markup(window, 2, 20, '{[ANT] pkt/s} {\u00b0C} {Injection} [us]') for y, (k, v) in enumerate(sorted(latency_d.items()), 3): k = int(k) # json doesn't support int keys injected, dropped, lat_min, lat_avg, lat_max = v + + # Show max temperature from all RF paths + temp = max((_v for _k, _v in rf_temperature.items() if (_k >> 8) == (k >> 8)), default=None) + if temp is not None: + if temp >= settings.common.temp_overheat_warning: + temp = '{%d}' % (temp,) + else: + temp = str(temp) + else: + temp = ' (--)' + if y < ymax: - addstr_markup(window, y, 21, '{%02x}(XX) %4d %4d < {%4d} < %4d' % (k >> 8, injected, lat_min, lat_avg, lat_max)) + addstr_markup(window, y, 21, '{%02x}(XX) %4d %3s %4d < {%4d} < %4d' % (k >> 8, injected, temp, lat_min, lat_avg, lat_max)) else: addstr_noerr(window, 2, 20, '[No data]', curses.A_REVERSE) diff --git a/wfb_ng/conf/master.cfg b/wfb_ng/conf/master.cfg index a4f4c9f..e922248 100644 --- a/wfb_ng/conf/master.cfg +++ b/wfb_ng/conf/master.cfg @@ -27,8 +27,12 @@ wifi_channel = 165 # radio channel @5825 MHz, range: 5815-5835 MHz, width # {'wlan0': 161, 'wlan1': 165} wifi_region = 'BO' # Set CRDA region -wifi_txpower = None # Some cards don't support tx power settings -#wifi_txpower = 58 # Doesn't affect 8812au drivers, use module parameter instead +wifi_txpower = None # Leave None to use default power settings from driver. + # 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 + +temp_measurement_interval = 10 # [s] (8812eu only) Internal RF path temp measurement. +temp_overheat_warning = 60 # [*C] (8812eu only) Overheat warning threshold. ## Stream allocation scheme: diff --git a/wfb_ng/server.py b/wfb_ng/server.py index 886574c..db0fe3d 100644 --- a/wfb_ng/server.py +++ b/wfb_ng/server.py @@ -27,7 +27,7 @@ import hashlib 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 +from twisted.internet import reactor, defer, main as ti_main, threads, task from twisted.internet.protocol import ProcessProtocol, Protocol, Factory from twisted.protocols.basic import LineReceiver, Int32StringReceiver from twisted.internet.serialport import SerialPort @@ -83,6 +83,7 @@ class StatsAndSelectorFactory(Factory): """ def __init__(self, profile, wlans, link_domain): + self.wlans = tuple(wlans) self.ant_sel_cb_list = [] self.rssi_cb_l = [] @@ -96,6 +97,46 @@ class StatsAndSelectorFactory(Factory): # CLI title self.cli_title = 'WFB-ng_%s @%s %s [%s]' % (settings.common.version, profile, ', '.join(wlans), link_domain) + # RF module temperature by rf_path + self.rf_temperature = {} + + self.lc = task.LoopingCall(self.read_temperature) + self.lc.start(settings.common.temp_measurement_interval, now=True) + + def _cleanup(self): + self.lc.stop() + + def read_temperature(self): + def _read_temperature(): + res = {} + for idx, wlan in enumerate(self.wlans): + fname = '/proc/net/rtl88x2eu/%s/thermal_state' % (wlan,) + try: + with open(fname) as fd: + for line in fd: + line = line.strip() + if not line: + continue + + d = {} + for f in line.split(','): + k, v = f.split(':', 1) + d[k.strip()] = int(v.strip()) + + ant_id = (idx << 8) + d['rf_path'] + res[ant_id] = d['temperature'] + except FileNotFoundError: + pass + except Exception as v: + reactor.callFromThread(log.err, v, 'Unable to parse %s:' % (fname,)) + return res + + def _got_temp(temp_d): + self.rf_temperature = temp_d + + return threads.deferToThread(_read_temperature).addCallback(_got_temp) + + def add_ant_sel_cb(self, ant_sel_cb): self.ant_sel_cb_list.append(ant_sel_cb) ant_sel_cb(self.tx_sel) @@ -208,7 +249,10 @@ class StatsAndSelectorFactory(Factory): # Send stats to CLI sessions for s in self.ui_sessions: - s.send_stats(dict(type='tx', id=tx_id, packets=packet_stats, latency=ant_latency)) + s.send_stats(dict(type='tx', id=tx_id, + packets=packet_stats, + latency=ant_latency, + rf_temperature=self.rf_temperature)) @@ -506,21 +550,33 @@ def init(profiles, wlans): yield init_wlans(max_bw, wlans) dl = [] + sockets = [] + ant_sel_l = [] + + def _cleanup(x): + for s in sockets: + s.stopListening() + + for f in ant_sel_l: + f._cleanup() + + return x for profile, service_list in services: # Domain wide antenna selector profile_cfg = getattr(settings, profile) ant_sel_f = StatsAndSelectorFactory(profile, wlans, profile_cfg.link_domain) + ant_sel_l.append(ant_sel_f) link_id = int.from_bytes(hashlib.sha1(profile_cfg.link_domain.encode('utf-8')).digest()[:3], 'big') if profile_cfg.stats_port: - reactor.listenTCP(profile_cfg.stats_port, ant_sel_f) + sockets.append(reactor.listenTCP(profile_cfg.stats_port, ant_sel_f)) for service_name, service_type, srv_cfg in service_list: log.msg('Starting %s/%s@%s on %s' % (profile, service_name, profile_cfg.link_domain, ', '.join(wlans))) dl.append(defer.maybeDeferred(type_map[service_type], service_name, srv_cfg, wlans, link_id, ant_sel_f)) - yield defer.gatherResults(dl, consumeErrors=True).addErrback(lambda f: f.trap(defer.FirstError) and f.value.subFailure) + yield defer.gatherResults(dl, consumeErrors=True).addBoth(_cleanup).addErrback(lambda f: f.trap(defer.FirstError) and f.value.subFailure) def init_udp_direct_tx(service_name, cfg, wlans, link_id, ant_sel_f):