<commit_before><!DOCTYPE HTML>
<html class="no-js" lang="">
<!--
Web panel for speed test
========================

On the transmission modem:

    mtu = phy[2].MTU;
    100.times {
      phy << new TxFrameReq(type:2, data: new byte[mtu]);
      receive(TxFrameNtf);
    }

-->
<head>
  <meta charset="utf-8">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <title>Unet</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="/img/unet.ico">
  <link rel="stylesheet" href="/css/vendor/vendor.css">
  <link rel="stylesheet" href="/css/vendor/app-orange.css">
  <link rel="stylesheet" href="/css/vendor/font.css">
  <link rel="stylesheet" href="/css/vendor/sweetalert.min.css">
  <link rel="stylesheet" href="/css/style.css">
  <script src="/js/vendor/sweetalert/sweetalert.min.js"></script>
  <script src="/js/vendor/fetch/fetch.umd.js"></script>
  <script src="/js/vendor/vendor/vendor.js" ></script>
  <script type='module' src='/js/nodeInfo.js'></script>
  <script type='module'>
    import { Gateway, Performative, MessageClass } from '../fjage/fjage.js';
    import '/js/nodeInfo.js';

    setTimeout(() => {
      if (document.querySelector('#logo').src.endsWith('subnero.png')) {
        document.querySelector('#logo').src = '/modem/img/subnero.png'
      }
    },1000)

    const avgtime = 10000;

    var gw = new Gateway();
    gw.addMessageListener(listener);

    var TxFrameReq = MessageClass('org.arl.unet.phy.TxFrameReq');
    var TxFrameNtf = MessageClass('org.arl.unet.phy.TxFrameNtf');
    var TxFrameStartNtf = MessageClass('org.arl.unet.phy.TxFrameStartNtf');
    var RxFrameStartNtf = MessageClass('org.arl.unet.phy.RxFrameStartNtf');
    var RxFrameNtf = MessageClass('org.arl.unet.phy.RxFrameNtf');
    var BadFrameNtf = MessageClass('org.arl.unet.phy.BadFrameNtf');

    var phy = gw.agent('phy');
    gw.subscribe(phy);

    function updateBar(name, value, str = null, min = 0, max = 100) {
      let elem = document.getElementById(name);
      let x = Math.max(Math.min(Math.round(100*(value-min)/(max-min)), 100), 0);
      elem.style = 'width:'+String(x)+'%';
      if (str === null) str = String(x)+' %';
      elem.innerText = str;
    }

    var rxdb = [];
    var detdb = [];
    var rssidb = [];
    var qualdb = [];

    function rx(bits = 0) {
      let t = Date.now();
      rxdb.push([t, bits]);
      let i = 0;
      while (i < rxdb.length && rxdb[i][0] < t-avgtime) i++;
      while (i < rxdb.length && rxdb[i][1] != 0) i++;
      if (i > 0) rxdb.splice(0, i);
      if (rxdb.length == 0) return 0;
      let total = 0;
      for (i = 0; i < rxdb.length; i++)
        total += rxdb[i][1];
      return 1000*total/(t-rxdb[0][0]);
    }

    function det(d) {
      let t = Date.now();
      detdb.push([t, d]);
      let i = 0;
      while (i < detdb.length && detdb[i][0] < t-avgtime) i++;
      if (i > 0) detdb.splice(0, i);
      if (detdb.length == 0) return 0;
      let maxd = 0;
      for (i = 0; i < detdb.length; i++)
        maxd = Math.max(maxd, detdb[i][1]);
      return maxd;
    }

    function qual(q = null) {
      let t = Date.now();
      qualdb.push([t, q]);
      let i = 0;
      while (i < qualdb.length && qualdb[i][0] < t-avgtime) i++;
      if (i > 0) qualdb.splice(0, i);
      if (qualdb.length == 0) return 0;
      let total = 0;
      let n = 0;
      for (i = 0; i < qualdb.length; i++)
        if (qualdb[i][1] !== null) {
          total += qualdb[i][1];
          n++;
        }
      return n > 0 ? total/n : 0;
    }

    function rssi(v) {
      let t = Date.now();
      rssidb.push([t, v]);
      let i = 0;
      while (i < rssidb.length && rssidb[i][0] < t-avgtime) i++;
      if (i > 0) rssidb.splice(0, i);
      if (rssidb.length == 0) return 0;
      let total = 0;
      for (i = 0; i < rssidb.length; i++)
        total += rssidb[i][1];
      return total/rssidb.length;
    }

    function listener(msg) {
      if (msg instanceof RxFrameStartNtf) {
        rx();
        updateBar('detbar', Math.round(100*det(msg.detector)));
      }
      if (msg instanceof BadFrameNtf) {
        let v = rssi(msg.rssi);
        updateBar('rssibar', v, String(Math.round(v))+' dB', -100, 0);
        updateBar('qualbar', qual());
        let datarate = rx();
        updateBar('speedbar', datarate, String(Math.round(datarate))+' bps', 0, 10000);
      }
      if (msg instanceof RxFrameNtf) {
        let v = rssi(msg.rssi);
        updateBar('rssibar', v, String(Math.round(v))+' dB', -100, 0);
        let p = 1.0*msg.errors/msg.bits;
        let entropy = p == 0 ? 0 : -p*Math.log2(p) + -(1-p)*Math.log2(1-p);
        let q = qual(Math.round(100*(1-entropy)));
        updateBar('qualbar', q);
        let type = msg.type;
        let datarate = rx(8*msg.data.length);
        updateBar('speedbar', datarate, String(Math.round(datarate))+' bps', 0, 10000);
      }
    }
  </script>
</head>

<body>
  <!--[if lte IE 9]>
        <p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="https://browsehappy.com/">upgrade your browser</a> to improve your experience and security.</p>
    <![endif]-->
  <div class="main-wrapper">
    <div class="app header-fixed footer-fixed sidebar-fixed full-screen" id="app">
      <article class="content dashboard-page">
        <div class="section">
          <div class="row sameheight-container">
            <div class="col col-12 col-sm-12 col-md-12 col-xl-12" id="output">
              <h1>Speed Test</h1><br>
              Signal strength: <div class="progress" style="width:50%"><div id="rssibar" class="progress-bar progress-bar-info" role="progressbar" style="width:0%"></div></div><br>
              Signal fidelity: <div class="progress" style="width:50%"><div id="detbar" class="progress-bar progress-bar-danger" role="progressbar" style="width:0%"></div></div><br>
              Communication quality: <div class="progress" style="width:50%"><div id="qualbar" class="progress-bar progress-bar-warning" role="progressbar" style="width:0%"></div></div><br>
              Throughput: <div class="progress" style="width:50%"><div id="speedbar" class="progress-bar progress-bar-success" role="progressbar" style="width:0%"></div></div><br>
            </div>
          </div>
        </div>
      </article>
    </div>
  </div>
</body>
</html><commit_msg>feat(dashboards): improved speedtest with noise measurements, logarithmic throughput scale, linear signal strength averaging and transmit button<commit_after><!DOCTYPE HTML>
<html class="no-js" lang="">
<head>
  <meta charset="utf-8">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <title>Unet Speedtest</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="/img/unet.ico">
  <link rel="stylesheet" href="/css/vendor/vendor.css">
  <link rel="stylesheet" href="/css/vendor/app-orange.css">
  <link rel="stylesheet" href="/css/vendor/font.css">
  <link rel="stylesheet" href="/css/vendor/sweetalert.min.css">
  <link rel="stylesheet" href="/css/style.css">
  <script src="/js/vendor/sweetalert/sweetalert.min.js"></script>
  <script src="/js/vendor/fetch/fetch.umd.js"></script>
  <script src="/js/vendor/vendor/vendor.js" ></script>
  <script type='module' src='/js/nodeInfo.js'></script>
  <script type='module'>
    import { Gateway, Performative, MessageClass } from '../fjage/fjage.js';
    import '/js/nodeInfo.js';

    setTimeout(() => {
      if (document.querySelector('#logo').src.endsWith('subnero.png')) {
        document.querySelector('#logo').src = '/modem/img/subnero.png'
      }
    },1000)

    const avgtime = 10000;

    var gw = new Gateway();
    gw.addMessageListener(listener);

    var ParameterReq = MessageClass('org.arl.unet.ParameterReq');
    var ParameterRsp = MessageClass('org.arl.unet.ParameterRsp');
    var TxFrameReq = MessageClass('org.arl.unet.phy.TxFrameReq');
    var TxFrameNtf = MessageClass('org.arl.unet.phy.TxFrameNtf');
    var TxFrameStartNtf = MessageClass('org.arl.unet.phy.TxFrameStartNtf');
    var RxFrameStartNtf = MessageClass('org.arl.unet.phy.RxFrameStartNtf');
    var RxFrameNtf = MessageClass('org.arl.unet.phy.RxFrameNtf');
    var BadFrameNtf = MessageClass('org.arl.unet.phy.BadFrameNtf');

    var phy = gw.agent('phy');
    gw.subscribe(phy);

    function updateBar(name, value, str = null, min = 0, max = 100) {
      let elem = document.getElementById(name);
      let x = Math.max(Math.min(Math.round(100*(value-min)/(max-min)), 100), 0);
      elem.style = 'width:'+String(x)+'%';
      if (str === null) str = String(x)+' %';
      elem.innerText = str;
    }

    var rxdb = [];
    var detdb = [];
    var rssidb = [];
    var qualdb = [];

    function rx(bits = 0) {
      let t = Date.now();
      rxdb.push([t, bits]);
      let i = 0;
      while (i < rxdb.length && rxdb[i][0] < t-avgtime) i++;
      while (i < rxdb.length && rxdb[i][1] != 0) i++;
      if (i > 0) rxdb.splice(0, i);
      if (rxdb.length == 0) return 0;
      let total = 0;
      for (i = 0; i < rxdb.length; i++)
        total += rxdb[i][1];
      return 1000*total/(t-rxdb[0][0]);
    }

    function det(d) {
      let t = Date.now();
      detdb.push([t, d]);
      let i = 0;
      while (i < detdb.length && detdb[i][0] < t-avgtime) i++;
      if (i > 0) detdb.splice(0, i);
      if (detdb.length == 0) return 0;
      let maxd = 0;
      for (i = 0; i < detdb.length; i++)
        maxd = Math.max(maxd, detdb[i][1]);
      return maxd;
    }

    function qual(q = null) {
      let t = Date.now();
      qualdb.push([t, q]);
      let i = 0;
      while (i < qualdb.length && qualdb[i][0] < t-avgtime) i++;
      if (i > 0) qualdb.splice(0, i);
      if (qualdb.length == 0) return 0;
      let total = 0;
      let n = 0;
      for (i = 0; i < qualdb.length; i++)
        if (qualdb[i][1] !== null) {
          total += qualdb[i][1];
          n++;
        }
      return n > 0 ? total/n : 0;
    }

    function rssi(v) {
      let t = Date.now();
      rssidb.push([t, v]);
      let i = 0;
      while (i < rssidb.length && rssidb[i][0] < t-avgtime) i++;
      if (i > 0) rssidb.splice(0, i);
      if (rssidb.length == 0) return 0;
      let total = 0;
      for (i = 0; i < rssidb.length; i++)
        total += Math.pow(10, rssidb[i][1]/10);
      return 10*Math.log10(total/rssidb.length);
    }

    var txcnt = 0;
    var mtu = 0;

    function tx(type = 2) {
      let req = new TxFrameReq();
      req.perf = Performative.REQUEST;
      req.recipient = phy;
      req.type = type;
      let data = [];
      data.length = mtu;
      data.fill(0);
      req.data = data;
      gw.request(req, 1000).then((rsp) => {
        if (rsp === null || rsp.perf != Performative.AGREE) {
          startTx.innerText = 'Start';
        } else {
          txcnt++;
          document.getElementById('tx-cnt').innerText = String(txcnt);
        }
      })
    }

    var noisedb = [];
    var last = 0;

    function noise() {
      if (Date.now()-last < 20000) {
        noisedb.splice(1, noisedb.length-1);
        document.getElementById('noisebar').classList.add('bg-info');
        return;
      } else {
        document.getElementById('noisebar').classList.remove('bg-info');
      }
      let req = new ParameterReq();
      req.perf = Performative.REQUEST;
      req.recipient = phy;
      req.index = -1;
      req.param = 'noise';
      gw.request(req, 1000).then((rsp) => {
        if (rsp.perf == Performative.INFORM) {
          noisedb.push(rsp.value);
          if (noisedb.length > 3) noisedb.splice(0, 1);
          let v = noisedb[0];
          updateBar('noisebar', v, String(Math.round(v))+' dB', -100, 0);
        }
      })
    }

    setInterval(() => {
      noise();
    }, 2000);

    function listener(msg) {
      if (msg instanceof RxFrameStartNtf) {
        rx();
        updateBar('detbar', Math.round(100*det(msg.detector)));
      }
      if (msg instanceof BadFrameNtf) {
        last = Date.now();
        let v = rssi(msg.rssi);
        updateBar('rssibar', v, String(Math.round(v))+' dB', -100, 0);
        updateBar('qualbar', qual());
        let datarate = rx();
        updateBar('speedbar', Math.round(Math.log10(datarate)*10), String(Math.round(datarate))+' bps', 0, 50);
      }
      if (msg instanceof RxFrameNtf) {
        last = Date.now();
        let v = rssi(msg.rssi);
        updateBar('rssibar', v, String(Math.round(v))+' dB', -100, 0);
        let p = msg.bits > 0 ? 1.0*msg.errors/msg.bits : 0;
        let entropy = p == 0 ? 0 : -p*Math.log2(p) + -(1-p)*Math.log2(1-p);
        let q = qual(Math.round(100*(1-entropy)));
        updateBar('qualbar', q);
        let type = msg.type;
        let datarate = rx(8*msg.data.length);
        updateBar('speedbar', Math.round(Math.log10(datarate)*10), String(Math.round(datarate))+' bps', 0, 50);
      }
      if (msg instanceof TxFrameNtf) {
        last = Date.now();
        if (startTx.innerText != 'Start') tx();
      }
    }

    var startTx = document.getElementById('start-tx');

    startTx.onclick = function() {
      if (startTx.innerText == 'Start') {
        let req = new ParameterReq();
        req.perf = Performative.REQUEST;
        req.recipient = phy;
        req.index = 2;
        req.param = 'MTU';
        gw.request(req, 1000).then((rsp) => {
          if (rsp.perf == Performative.INFORM) {
            mtu = rsp.value;
            startTx.innerText = 'Stop';
            txcnt = 0;
            document.getElementById('tx-cnt').innerText = String(txcnt);
            tx();
          }
        })
      } else {
        startTx.innerText = 'Start';
      }
    }
  </script>
</head>

<body>
  <!--[if lte IE 9]>
      <p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="https://browsehappy.com/">upgrade your browser</a> to improve your experience and security.</p>
  <![endif]-->
  <div class="main-wrapper">
    <div class="app header-fixed footer-fixed sidebar-fixed full-screen" id="app">
      <article class="content dashboard-page d-flex flex-column">
        <div class="row sameheight-container flex-grow-1">
          <div class="col col-6">
            <h1>Speed Test</h1><hr>
            <h2>Reception</h2><br>
            <span data-toggle="tooltip" title="Ambient noise level (dB full scale)">Noise level:</span>
            <div class="progress" style="width:50%"><div id="noisebar" class="progress-bar" role="progressbar" style="width:0%"></div></div><br>
            <span data-toggle="tooltip" title="Received signal strength (dB full scale)">Signal strength:</span>
            <div class="progress" style="width:50%"><div id="rssibar" class="progress-bar" role="progressbar" style="width:0%"></div></div><br>
            <span data-toggle="tooltip" title="Signal fidelity measures how well the received premable matches a transmitted preamble after passing through the channel">Signal fidelity:</span>
            <div class="progress" style="width:50%"><div id="detbar" class="progress-bar" role="progressbar" style="width:0%"></div></div><br>
            <span data-toggle="tooltip" title="Communication quality measures the mutual information between transmitted and received bits, and is estimated from bit error rate (BER) measurements before error correction">Communication quality:</span>
            <div class="progress" style="width:50%"><div id="qualbar" class="progress-bar" role="progressbar" style="width:0%"></div></div><br>
            <span data-toggle="tooltip" title="Throughput is the average number of bits of user data transmitted through the channel per unit time">Throughput:</span>
            <div class="progress" style="width:50%"><div id="speedbar" class="progress-bar" role="progressbar" style="width:0%"></div></div><hr>
            <h2>Transmission</h2><br>
            <button type="button" class="btn btn-primary" data-toggle="button" aria-pressed="false" id="start-tx">Start</button><br>
            TX count: <span id="tx-cnt">0</span>
          </div><div class="col col-6">
            <iframe src="/fjage/shell/index.html" class="terminal shell-frame"></iframe>
          </div>
        </div>
      </article>
    </div>
  </div>
</body>
</html>
{'fraction_non_alphanumeric': 0.18317802844531633, 'fraction_numerical': 0.019556154977930357, 'mean_word_length': 2.646177916852928, 'pattern_counts': {'":': 0, '<': 203, '<?xml version=': 0, '>': 192, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2233762', 'n_tokens_mistral': 5881, 'n_tokens_neox': 5556, 'n_words': 1224}