diff --git a/html/scan.js b/html/scan.js index 4ee678be..6f80ae54 100644 --- a/html/scan.js +++ b/html/scan.js @@ -7,6 +7,7 @@ function _(el) { function init() { initAat(); initMavLink(); + initBleTrainer(); // sends XMLHttpRequest, so do it last initOptions(); @@ -47,6 +48,55 @@ function initMavLink() { xmlhttp.open('GET', '/mavlink', true); xmlhttp.send(); } + +function initBleTrainer() { + const form = _('bt_form'); + if (!form) + return; + form.addEventListener('submit', (e) => { e.preventDefault(); btSubmit(false); }); + _('bt_forget').addEventListener('click', (e) => { e.preventDefault(); btSubmit(true); }); + _('bt_source').addEventListener('change', () => btToggleBleSettings(_('bt_source').value)); +} + +// Posts the FrSky BLE Trainer form (or a Forget request) and updates the page +// in place, so no manual reload is needed. +function btSubmit(clearPeer) { + const body = clearPeer ? new URLSearchParams({ forget: 1 }) + : new URLSearchParams(new FormData(_('bt_form'))); + const xmlhttp = new XMLHttpRequest(); + xmlhttp.onreadystatechange = function () { + if (this.readyState != 4) + return; + if (this.status == 200) { + if (clearPeer) { + _('bt_status').textContent = 'Not paired'; + _('bt_mac').textContent = '-'; + } + cuteAlert({ + type: 'success', + title: 'Bluetooth Trainer', + message: 'Bluetooth trainer settings saved' + }); + } else { + cuteAlert({ + type: 'error', + title: 'Bluetooth Trainer', + message: 'An error occurred saving the Bluetooth trainer settings' + }); + } + }; + xmlhttp.open('POST', '/settrainer', true); + xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + xmlhttp.send(body); +} + +// Bluetooth-only fields are hidden when the native source is selected. +function btToggleBleSettings(source) { + const el = _('bt_ble_settings'); + if (el) + el.style.display = (source === 'native') ? 'none' : 'block'; +} + function initOptions() { const xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { @@ -136,6 +186,15 @@ function updateConfig(data) { if (config['head-tracking']) { if (_('httab')) _('httab').style.display = 'table-cell'; } + if (config['trainer']) { + if (_('bttab')) _('bttab').style.display = 'table-cell'; + const bt = config.trainer; + _('bt_status').textContent = bt.paired ? 'Paired' : 'Not paired'; + _('bt_mac').textContent = bt.paired ? bt.mac : '-'; + _('bt_interval').value = bt.interval; + _('bt_source').value = bt.source; + btToggleBleSettings(bt.source); + } if((!data.stm32 || data.stm32==="no") && _('tx_tab')) { mui.tabs.activate('pane-justified-2'); _('tx_tab').style.display = 'none'; diff --git a/html/txbp_index.html b/html/txbp_index.html index 08c78af2..44190928 100644 --- a/html/txbp_index.html +++ b/html/txbp_index.html @@ -26,6 +26,7 @@

ExpressLRS

  • Backpack
  • Network
  • MavLink
  • +
    @@ -146,6 +147,48 @@

    MavLink Statistics

    + +
    +

    FrSky BLE Trainer

    +

    The backpack forwards trainer channels to EdgeTX (as trainer input) from one of + two sources: the native system (ESP-NOW, e.g. a VRX or goggles with IMU) or a + Bluetooth device advertising the FrSky trainer service (e.g. an Arduino-based + HeadTracker). Both respect the radio's HT Enable; use the selector to choose which one + is used.

    +
    +
    + + +
    +
    +

    Bluetooth device

    + + + + + + + + + +
    Status:-
    Paired address:-
    +
    + Connection interval (ms) + +
    +

    The trainer sends one frame per Bluetooth connection event, so a low + interval is what keeps the movement fluid. 8 ms suits a HeadTracker; higher + values only slow the stream down.

    + +

    +
    + +
    +