From fa63c306fdebe587ebb082807bf2815ca183fb76 Mon Sep 17 00:00:00 2001 From: Orne Brocaar Date: Tue, 15 Apr 2025 10:15:39 +0100 Subject: [PATCH] Add default ADR example in JS. --- examples/adr_plugins/default.js | 145 ++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 examples/adr_plugins/default.js diff --git a/examples/adr_plugins/default.js b/examples/adr_plugins/default.js new file mode 100644 index 00000000..bba1d7da --- /dev/null +++ b/examples/adr_plugins/default.js @@ -0,0 +1,145 @@ +export function name() { + return "JS example for default ADR algorithm"; +} + +export function id() { + return "js_example_default"; +} + +export function handle(req) { + let resp = { + dr: req.dr, + txPowerIndex: req.txPowerIndex, + nbTrans: req.nbTrans, + }; + + if (!req.adr) { + return resp; + } + + if (req.dr > req.maxDr) { + resp.dr = req.maxDr; + } + + // Set the new Nb Trans. + resp.nbTrans = getNbTrans(req.nbTrans, getPacketLossPercentage(req)); + + // Calculate the number of steps. + let snrMax = getMaxSnr(req); + let snrMargin = snrMax - req.requiredSnrForDr - req.installationMargin; + let nStep = Math.floor(snrMargin / 3); + + // In case of negative steps the ADR algorithm will increase the TxPower + // if possible. To avoid up / down / up / down TxPower changes, wait until + // we have at least the required number of uplink history elements. + if (nStep < 0 && getHistoryCount(req) != requiredHistoryCount()) { + return resp; + } + + let [desiredTxPowerIndex, desiredDr] = getIdealTxPowerIndexAndDr( + nStep, + resp.txPowerIndex, + resp.dr, + req.maxTxPowerIndex, + req.maxDr, + ); + + resp.dr = desiredDr; + resp.txPowerIndex = desiredTxPowerIndex; + + return resp; +} + +function getIdealTxPowerIndexAndDr(nbStep, txPowerIndex, dr, maxTxPowerIndex, maxDr) { + while (nbStep !== 0) { + if (nbStep > 0) { + if (dr < maxDr) { + // Increase the DR. + dr++; + } else if (txPowerIndex < maxTxPowerIndex) { + // Decrease the Tx Power. + txPowerIndex++; + } + nbStep--; + } else { + // Incease the TxPower. + if (txPowerIndex > 0) { + txPowerIndex--; + } + nbStep++; + } + } + + return [txPowerIndex, dr]; +} + +function requiredHistoryCount() { + return 20; +} + +function getHistoryCount(req) { + let count = 0; + for (let uh of req.uplinkHistory) { + if (uh.txPowerIndex === req.txPowerIndex) { + count++; + } + } + + return count; +} + +function getMaxSnr(req) { + let maxSnr = -999.0; + + for (let uh of req.uplinkHistory) { + if (uh.maxSnr > maxSnr) { + maxSnr = uh.maxSnr; + } + } + + return maxSnr; +} + +function getNbTrans(currentNbTrans, pktLossRate) { + const pktLossTable = [ + [1, 1, 2], + [1, 2, 3], + [2, 3, 3], + [3, 3, 3], + ]; + + if (currentNbTrans < 1) { + currentNbTrans = 1; + } + if (currentNbTrans > 3) { + currentNbTrans = 3; + } + + const nbTransIndex = currentNbTrans - 1; + + if (pktLossRate < 5.0) { + return pktLossTable[0][nbTransIndex]; + } else if (pktLossRate < 10.0) { + return pktLossTable[1][nbTransIndex]; + } else if (pktLossRate < 30.0) { + return pktLossTable[2][nbTransIndex]; + } + + return pktLossTable[3][nbTransIndex]; +} + +function getPacketLossPercentage(req) { + if (req.uplinkHistory.length < requiredHistoryCount()) { + return 0.0; + } + + let lostPackets = 0; + let previousFCnt = req.uplinkHistory[0].fCnt; + + for (let uh of req.uplinkHistory.slice(1)) { + lostPackets += uh.fCnt - previousFCnt - 1; + previousFCnt = uh.fCnt; + } + + return lostPackets / req.uplinkHistory.length * 100.0; +}