From 135f70c0d13f4569a206b2cd84d25c8e7981ff69 Mon Sep 17 00:00:00 2001 From: Mark Haslinghuis Date: Fri, 25 Dec 2020 11:18:16 +0100 Subject: [PATCH] Rearrange configuration and motor tab --- locales/en/messages.json | 6 + src/css/tabs/configuration.css | 137 +---- src/css/tabs/motors.css | 356 +++++++++-- src/css/tabs/servos.css | 181 ++++++ src/js/tabs/configuration.js | 596 ++---------------- src/js/tabs/motors.js | 566 ++++++++++++----- src/js/tabs/servos.js | 104 +++- src/tabs/configuration.html | 1043 ++++++++++++-------------------- src/tabs/motors.html | 438 ++++++++++---- src/tabs/servos.html | 69 ++- 10 files changed, 1789 insertions(+), 1707 deletions(-) diff --git a/locales/en/messages.json b/locales/en/messages.json index 68c32cac5d4..0865990a6a6 100644 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -2551,6 +2551,12 @@ "motorsEnableControl": { "message": "I understand the risks, the propellers are removed - enable motor control and arming, and disable Runaway Takeoff Prevention." }, + "motorsDialogSettingsChanged": { + "message": "Configuration changes have been detected.

Motor Test Mode is disabled until the settings have seen saved." + }, + "motorsDialogSettingsChangedOk": { + "message": "OK" + }, "motorOutputReorderDialogClose": { "message": "Cancel" diff --git a/src/css/tabs/configuration.css b/src/css/tabs/configuration.css index 66b83928003..27b1e4dab80 100644 --- a/src/css/tabs/configuration.css +++ b/src/css/tabs/configuration.css @@ -1,24 +1,7 @@ .tab-configuration .ui-grid-col { margin-bottom: 0; } -.tab-configuration .mixerPreview { - max-width: 230px; - background-color: #eeeeee; - text-align: center; - float: left; - border-radius: 5px; - margin-top: 5px; -} -.tab-configuration .mixerPreview img { - width: 90%; - height: 90%; - padding: 5%; -} -.tab-configuration select.batterymetertype { - margin-right: 5px; - float: left; - width: 150px; -} + .tab-configuration input, .tab-configuration select { border: 1px solid var(--subtleAccent); @@ -70,13 +53,6 @@ border-bottom: 1px solid var(--subtleAccent); } -.tab-configuration .mixerList { - width: 100%; - height: 20px; - margin-top: 5px; - font-weight: bold; -} - .tab-configuration .featuresMultiple { border-collapse: collapse; margin-bottom: 5px; @@ -146,45 +122,6 @@ line-height: 20px; } -.tab-configuration .current .checkbox { - margin-top: 0; - float: left; -} - -.tab-configuration .current .checkbox div { - float: left; - width: 66px; -} - -.tab-configuration .current .checkbox div input { - margin: 0; - float: left; -} - -.tab-configuration .disarm .checkbox { - margin-top: 2px; - margin-right: 5px; -} - -.tab-configuration .disarm .checkboxPwm { - margin-top: 2px; - margin-right: 5px; -} - -.tab-configuration .disarm .checkbox div { - margin-bottom: 0; - margin-top: 0; -} - -.tab-configuration .disarm .checkbox div input { - margin: 0; - float: left; -} - -.tab-configuration .disarm .checkbox span { - margin-left: 0; -} - .tab-configuration .freelabel { margin-left: 10px; position: relative; @@ -198,35 +135,12 @@ margin: 0; } -.tab-configuration .disarm .checkbox { - float: left; - padding-left: 0; - margin-top: -5px; - padding-bottom: 5px; - border-bottom: 1px solid var(--subtleAccent); - width: 100%; -} - .tab-configuration .spacer_box { padding-bottom: 10px; float: left; width: calc(100% - 20px); } -.tab-configuration .disarm { - margin-bottom: 5px; - float: left; - border-bottom: 1px solid var(--subtleAccent); - width: 100%; -} - -.tab-configuration .disarmdelay { - margin-top: 5px; - float: left; - width: 100%; - border-bottom: 1px solid var(--subtleAccent); -} - .tab-configuration .number, .tab-configuration .select { @@ -261,15 +175,6 @@ text-overflow: ellipsis; } -.tab-configuration .selectProtocol { - margin-bottom: 5px; - clear: left; - padding-bottom: 5px; - border-bottom: 1px solid var(--subtleAccent); - width: 100%; - float: left; -} - .tab-configuration .number:last-child, .tab-configuration .select:last-child { border-bottom: none; @@ -306,10 +211,6 @@ float: left; } -.tab-configuration .mixer .gui_box, .tab-configuration .motorstop .gui_box { - float: left; -} - .tab-configuration .board .gui_box, .tab-configuration .acc .gui_box { float: left; } @@ -327,23 +228,6 @@ width: 30px; } -.tab-configuration .voltage td:nth-child(2) { - width: 30px; -} - -.tab-configuration .currentmetertype { - float: left; - width: 150px; -} - -.tab-configuration .vbatmonitoring { - margin-top: 5px; -} - -.tab-configuration .currentMonitoring { - margin-top: 5px; -} - .tab-configuration .rssi td:nth-child(2) { width: 30px; } @@ -438,12 +322,6 @@ font-weight: bold; } -.tab-configuration ._3dSettings { - margin-top: 10px; - float: left; - width: 100%; -} - .tab-configuration ._smallAngle { margin-top: 10px; float: left; @@ -461,9 +339,6 @@ .tab-configuration .rssi .gui_box, .tab-configuration .system .gui_box { float: left; } - .tab-configuration .mixer .gui_box, .tab-configuration .motorstop .gui_box { - float: left; - } .tab-configuration .board .gui_box, .tab-configuration .acc .gui_box { float: left; } @@ -475,13 +350,6 @@ } } @media all and (max-width: 575px) { - .tab-configuration .mixerPreview { - max-width: none; - } - .tab-configuration select.escprotocol { - width: 100%; - margin-right: 0; - } .tab-configuration .rssi .gui_box, .tab-configuration .system .gui_box { min-height: auto; } @@ -503,7 +371,4 @@ select.features.rxMode, select.serialRX, .dshotbeacon > td > div.select > div, .dshotbeacon select.dshotBeeperBeaconTone { width: 100%; } - .tab-configuration .mixer .gui_box, .tab-configuration .motorstop .gui_box { - min-height: auto; - } } diff --git a/src/css/tabs/motors.css b/src/css/tabs/motors.css index b13ce99b0b5..63149754b45 100644 --- a/src/css/tabs/motors.css +++ b/src/css/tabs/motors.css @@ -1,3 +1,239 @@ +.tab-motors .ui-grid-col { + margin-bottom: 0; +} +/* +.tab-motors input, +*/ +.tab-motors select { + border: 1px solid var(--subtleAccent); + width: 230px; + height: 20px; + float: left; + margin-right: 15px; + border-radius: 3px; +} + +.tab-motors table { + margin-bottom: 0; + width: 100%; + float: left; +} + +.tab-motors table, .tab-motors table th, .tab-motors table td { + padding: 0; + text-align: left; +} + +.tab-motors table th { + padding: 3px; + border-bottom: 1px solid var(--subtleAccent); +} + +.tab-motors table td { + padding: 5px 3px; + border-bottom: 1px solid var(--subtleAccent); +} + +.tab-motors table tr td:first-child { + text-align: left; + width: 55px; +} + +.tab-motors table thead tr:first-child { + background-color: #ececec; +} + +.tab-motors { + position: relative; +} + +.tab-motors .groupTitle { + padding: 0 0 5px 0; + margin: 0 0 10px 0; + font-size: 16px; + border-bottom: 1px solid var(--subtleAccent); +} + +.tab-motors .mixerList { + float: left ; + width: 29%; +} + +.tab-motors .featuresMultiple { + border-collapse: collapse; + margin-bottom: 5px; + margin-top: -5px; + padding: 0; +} + +.tab-motors dl.features dt { + float: left; + width: 10px; + height: 18px; + line-height: 18px; +} + +.tab-motors dl.features dt input { + margin-top: 2px; +} + +.tab-motors dl.features dd { + margin: 0 0 0 20px; + height: 18px; + line-height: 18px; +} + +.tab-motors .number input { + width: 55px; + padding-left: 3px; + height: 20px; + line-height: 20px; + text-align: left; + border-radius: 3px; + margin-right: 11px; + font-size: 12px; + font-weight: normal; +} + +.tab-motors .number .disabled { + width: 48px; + padding: 0 5px; + background-color: #ececec; +} + +.tab-motors .number span { + margin-left: 0; +} + +.tab-motors .disarm .checkboxPwm { + margin-top: 2px; + margin-right: 5px; +} + +.tab-motors .disarm .checkbox div { + margin-bottom: 0; + margin-top: 0; +} + +.tab-motors .disarm .checkbox div input { + margin: 0; + float: left; +} + +.tab-motors .disarm .checkbox span { + margin-left: 0; +} + +.tab-motors .freelabel { + margin-left: 10px; + position: relative; +} + +.tab-motors span { + margin: 0; +} + +.tab-motors .disarm .checkbox { + float: left; + padding-left: 0; + margin-top: -5px; + margin-right: 5px; + padding-bottom: 5px; + border-bottom: 1px solid var(--subtleAccent); + width: 100%; +} + +.tab-motors .spacer_box { + padding-bottom: 10px; + float: left; + width: calc(100% - 20px); +} + +.tab-motors .disarm { + margin-bottom: 5px; + float: left; + border-bottom: 1px solid var(--subtleAccent); + width: 100%; +} + +.tab-motors .disarmdelay { + margin-top: 5px; + float: left; + width: 100%; + border-bottom: 1px solid var(--subtleAccent); +} + +.tab-motors .number, +.tab-motors .select +{ + margin-bottom: 5px; + clear: left; + padding-bottom: 5px; + border-bottom: 1px solid var(--subtleAccent); + width: 100%; + float: left; +} + +.tab-motors .selectProtocol { + margin-bottom: 5px; + clear: left; + padding-bottom: 5px; + border-bottom: 1px solid var(--subtleAccent); + width: 100%; + float: left; +} + +.tab-motors .number:last-child, +.tab-motors .select:last-child { + border-bottom: none; + padding-bottom: 0; + margin-bottom: 0; +} + +.tab-motors .gui_box_titlebar { + margin-bottom: 0; +} + +.tab-motors .numberspacer { + float: left; + width: 65px; + height: 21px; +} + +.tab-motors thead { + display: none; +} + +.tab-motors .gui_box { + margin-bottom: 10px; + float: left; +} + +.tab-motors .gui_box span { + font-style: normal; + font-weight: normal; + line-height: 19px; + color: #4f4f4f; + font-size: 11px; +} + +.tab-motors .alignicon { + width: 15px; + height: 15px; + float: left; + margin: 3px; +} + +.tab-configuration .mixer .gui_box, .tab-configuration .motorstop .gui_box { + float: left; +} + +.tab-motors ._3dSettings { + margin-top: 10px; + float: left; + width: 100%; +} + .tab-motors .modelAndGraph { float: left; width: 100%; @@ -11,7 +247,7 @@ .tab-motors #graph { float: left; - width: calc(100% - 292px); + width: calc(100% - 160px); } .tab-motors .mixerPreview { @@ -59,11 +295,41 @@ flex-grow: 1; } +.tab-motors #dialog-settings-changed { + width: 400px; + height: 100px; +} + +.tab-motors #dialog-settings-changed-confirmbtn { + margin-right: 0px; + margin-bottom: 0px; + position: absolute; + right: 0px; + bottom: 0px; +} + +.tab-motors #dialog-settings-changed-content-wrapper { + display: flex; + flex-flow: column; + width: 100%; + height: 100%; + position: relative; +} + +.tab-motors #dialog-settings-changed-content { + flex-grow: 1; +} + .tab-motors .mixerPreview img { - width: 120px; - height: 120px; + width: 150px; + height: 150px; margin-top: 18px; - margin-left: 10px; + margin-left: 32px; +} + +.tab-motors .tool-buttons { + float: right; + margin-bottom: -3%; } /*Plot Control*/ @@ -71,7 +337,7 @@ .tab-motors .plot_control { float: right; width: 160px; - height: 197px; + height: 178px; margin: 0; background-color: #ECECEC; border-top-right-radius: 3px; @@ -158,19 +424,21 @@ } .tab-motors .power_info .power_value { - margin-right: 10px; - width: 50px; + margin-right: 2em; + margin-left: 1em; display: inline-block; - text-align: right; + text-align: left; + width: 50px; } /*Motors*/ .tab-motors svg { float: left; - width: calc(100% - 168px); /* - (plot control, margin)*/ + width: calc(100% - 168px); /* (plot control, margin)*/ height: 140px; margin-top: 10px; + margin-bottom: 15px; } .tab-motors .grid .tick { @@ -216,17 +484,11 @@ .tab-motors .motorblock { margin-bottom: 0; background-color: #ECECEC; - /*background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.15));*/ } .tab-motors .left.motors { float: left; - width: calc(60% - 20px); -} - -.tab-motors .right.servos { - float: right; - width: 40%; + width: 100%; } .tab-motors .title { @@ -253,12 +515,6 @@ text-align: center; } -.tab-motors .servos .titles li { - float: right; - width: calc((100% / 8) - 10px); - margin: 0 0 0 10px; -} - .tab-motors .titles .active { color: green; } @@ -302,13 +558,6 @@ color: white; } -.tab-motors .servos .m-block { - float: right; - width: calc((100% / 8) - 10px); - margin: 0 0 0 10px; - border-radius: 3px; -} - .tab-motors .indicator { position: absolute; overflow: hidden; @@ -319,10 +568,15 @@ .tab-motors .motor_testing { margin-top: 5px; + margin-bottom: 0; + padding: 0; + border: 0; + list-style: none; + outline: none; } .tab-motors .motor_testing .left { - width: calc(60% - 20px); + width: 100%; } .tab-motors .motor_testing .sliders input { @@ -369,12 +623,12 @@ .tab-motors .motor_testing .notice { float: right; - width: calc(40% - 24px); padding: 5px; border: 2px solid var(--subtleAccent); border-radius: 3px; background-color: #FFFFFF; font-size: 11px; + margin-top: 10px; } .tab-motors .motor_testing .notice p { @@ -385,27 +639,31 @@ margin-left: 10px; } +.tab-motors .motorDialogButtons { + float: right; +} + @media all and (max-width: 575px) { .tab-motors .modelAndGraph { display: flex; flex-wrap: wrap; } - .tab-motors .mixerPreview { - order: 1; - width: calc(100% - 160px); + .tab-motors select.escprotocol { + width: 100%; + margin-right: 0; } - .tab-motors .mixerPreview img { - width: calc(100% - 20px); + .tab-motors .mixer .gui_box, .tab-motors .motorstop .gui_box { + min-height: auto; } .tab-motors #graph { width: 100%; - order: 3; + order: 2; } .tab-motors .plot_control { - order: 2; + order: 1; } .tab-motors .power_info { - order: 4; + order: 3; width: 100%; margin-top: 10px; } @@ -420,11 +678,6 @@ width: 100%; order: 1; } - .tab-motors .right.servos { - width: 100%; - order: 3; - margin-top: 15px; - } .tab-motors .motor_testing { width: 100%; display: flex; @@ -444,12 +697,6 @@ .tab-motors .motor_testing .left { width: 100%; } - .tab-motors .servos .m-block, .tab-motors .servos .titles li { - width: calc((100% - 70px) / 8); - } - .tab-motors .servos .m-block:last-child, .tab-motors .servos .titles li:last-child { - margin-left: 0; - } .tab-motors .motor_testing .sliders { margin-left: 2px; margin-right: -2px; @@ -467,3 +714,12 @@ font-size: 6px; } } + +@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) { + .tab-motors .gui_box span { + line-height: 17px; + } + .tab-motors .mixer .gui_box, .tab-motors .motorstop .gui_box { + float: left; + } +} diff --git a/src/css/tabs/servos.css b/src/css/tabs/servos.css index 6edfc6ec51a..23b22655495 100644 --- a/src/css/tabs/servos.css +++ b/src/css/tabs/servos.css @@ -188,3 +188,184 @@ min-width: 60px; } } + +/* servos testing bars */ + +.tab-servos table tr td:first-child { + text-align: left; + width: 55px; +} + +.tab-servos { + position: relative; +} +.tab-servos .spacer_box { + padding-bottom: 10px; + float: left; + width: calc(100% - 20px); +} + +.tab-servos .gui_box_titlebar { + margin-bottom: 0; +} + +.tab-servos .gui_box { + margin-bottom: 10px; + float: left; + font-weight: bold; +} + +.tab-servos .gui_box span { + font-style: normal; + font-weight: normal; + line-height: 19px; + color: #4f4f4f; + font-size: 11px; +} + +.tab-servos .spacer { + width: calc(100% - 34px); + margin: 10px; +} + +.tab-servos .servoblock { + margin-bottom: 0; + background-color: #ECECEC; +} + +.tab-servos .right.servos { + float: left; + width: 80%; +} + +.tab-servos .title2 { + padding-bottom: 2px; + text-align: center; + font-size: 12px; + font-weight: 300; +} + +.tab-servos .titles { + height: 20px; +} + +.tab-servos .titles li { + float: left; + width: calc((100% / 9) - 10px); + margin-right: 10px; + text-align: center; +} + +.tab-servos .servos .titles li { + float: right; + width: calc((100% / 8) - 10px); + margin: 0 0 0 10px; +} + +.tab-servos .titles .active { + color: green; +} + +.tab-servos .m-block { + float: left; + width: calc((100% / 9) - 10px); + height: 100px; + margin-right: 10px; + text-align: center; + background-color: #f4f4f4; + border-radius: 3px; + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); +} + +.tab-servos .m-block .meter-bar { + position: relative; + width: 100%; + height: 100px; + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); + background-color: #E0E0E0; + border-radius: 3px; + border: 1px solid #F5F5F5; +} + +.tab-servos .m-block .label { + position: absolute; + width: 100%; + bottom: 45px; + text-align: center; + font-weight: bold; + font-size: 10px; + color: #474747; +} + +.tab-servos .m-block .label.rpm_info { + bottom: 28px; +} + +.tab-servos .m-block .indicator .label { + color: white; +} + +.tab-servos .servos .m-block { + float: right; + width: calc((100% / 8) - 10px); + margin: 0 0 0 10px; + border-radius: 3px; +} + +.tab-servos .indicator { + position: absolute; + overflow: hidden; + width: 100%; + text-align: center; + border-radius: 2px; +} + +@media all and (max-width: 575px) { + + .tab-servos .gui_box { + min-height: auto; + } + + .tab-servos .servoblock { + margin-bottom: 15px; + } + .tab-servos .servoblock > .spacer { + display: flex; + flex-wrap: wrap; + } + .tab-servos .left.motors { + width: 100%; + order: 1; + } + .tab-servos .right.servos { + width: 100%; + order: 3; + margin-top: 15px; + } + .tab-servos .titles li, .tab-servos .m-block { + width: calc((100% - 80px) / 9); + } + .tab-servos .titles li:last-child, .tab-servos .m-block:last-child { + margin-right: 0; + } + .tab-servos .servos .m-block, .tab-servos .servos .titles li { + width: calc((100% - 70px) / 8); + } + .tab-servos .servos .m-block:last-child, .tab-servos .servos .titles li:last-child { + margin-left: 0; + } + + .tab-servos .servo_testing .values li:last-child { + margin-left: 4px; + } + +} + +@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) { + .tab-servos .gui_box span { + line-height: 17px; + } + .tab-servos .gui_box { + float: left; + } +} diff --git a/src/js/tabs/configuration.js b/src/js/tabs/configuration.js index 9aae5aac3c6..d0eed39cfbf 100644 --- a/src/js/tabs/configuration.js +++ b/src/js/tabs/configuration.js @@ -1,31 +1,17 @@ 'use strict'; TABS.configuration = { - SHOW_OLD_BATTERY_CONFIG: false, - previousDshotBidir: null, - previousFilterDynQ: null, - previousFilterDynWidth: null, analyticsChanges: {}, }; TABS.configuration.initialize = function (callback, scrollPosition) { const self = this; - // Update filtering defaults based on API version - const FILTER_DEFAULT = FC.getFilterDefaults(); - if (GUI.active_tab != 'configuration') { GUI.active_tab = 'configuration'; GUI.configuration_loaded = true; } - if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_36)) { - //Show old battery configuration for pre-BF-3.2 - self.SHOW_OLD_BATTERY_CONFIG = true; - } else { - self.SHOW_OLD_BATTERY_CONFIG = false; - } - function load_config() { MSP.send_message(MSPCodes.MSP_FEATURE_CONFIG, false, false, load_beeper_config); } @@ -44,28 +30,15 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } function load_board_alignment_config() { - MSP.send_message(MSPCodes.MSP_BOARD_ALIGNMENT_CONFIG, false, false, load_rc_map); + MSP.send_message(MSPCodes.MSP_BOARD_ALIGNMENT_CONFIG, false, false, load_rx_map); } - function load_rc_map() { - MSP.send_message(MSPCodes.MSP_RX_MAP, false, false, load_mixer_config); - } - - function load_mixer_config() { - MSP.send_message(MSPCodes.MSP_MIXER_CONFIG, false, false, load_rssi_config); + function load_rx_map() { + MSP.send_message(MSPCodes.MSP_RX_MAP, false, false, load_rssi_config); } function load_rssi_config() { - MSP.send_message(MSPCodes.MSP_RSSI_CONFIG, false, false, load_motor_config); - } - - function load_motor_config() { - const nextCallBack = load_gps_config; - if(semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_33)) { - MSP.send_message(MSPCodes.MSP_MOTOR_CONFIG, false, false, nextCallBack); - } else { - nextCallBack(); - } + MSP.send_message(MSPCodes.MSP_RSSI_CONFIG, false, false, load_gps_config); } function load_gps_config() { @@ -91,7 +64,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } function load_arming_config() { - const nextCallBack = load_3d; + const nextCallBack = load_rc_deadband; if (semver.gte(FC.CONFIG.apiVersion, "1.8.0")) { MSP.send_message(MSPCodes.MSP_ARMING_CONFIG, false, false, nextCallBack); } else { @@ -99,17 +72,8 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } } - function load_3d() { - const nextCallBack = load_rc_deadband; - if (semver.gte(FC.CONFIG.apiVersion, "1.14.0")) { - MSP.send_message(MSPCodes.MSP_MOTOR_3D_CONFIG, false, false, nextCallBack); - } else { - nextCallBack(); - } - } - function load_rc_deadband() { - const nextCallBack = esc_protocol; + const nextCallBack = load_sensor_config; if (semver.gte(FC.CONFIG.apiVersion, "1.17.0")) { MSP.send_message(MSPCodes.MSP_RC_DEADBAND, false, false, nextCallBack); } else { @@ -117,16 +81,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } } - function esc_protocol() { - const nextCallBack = sensor_config; - if (semver.gte(FC.CONFIG.apiVersion, "1.16.0")) { - MSP.send_message(MSPCodes.MSP_ADVANCED_CONFIG, false, false, nextCallBack); - } else { - nextCallBack(); - } - } - - function sensor_config() { + function load_sensor_config() { const nextCallBack = load_sensor_alignment; if (semver.gte(FC.CONFIG.apiVersion, "1.16.0")) { MSP.send_message(MSPCodes.MSP_SENSOR_CONFIG, false, false, nextCallBack); @@ -145,12 +100,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } function load_name() { - let nextCallBack = load_rx_config; - - if (self.SHOW_OLD_BATTERY_CONFIG) { - nextCallBack = load_battery; - } - + const nextCallBack = load_rx_config; if (semver.gte(FC.CONFIG.apiVersion, "1.20.0")) { MSP.send_message(MSPCodes.MSP_NAME, false, false, nextCallBack); } else { @@ -158,24 +108,6 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } } - function load_battery() { - const nextCallBack = load_current; - if (semver.gte(FC.CONFIG.flightControllerVersion, "3.1.0")) { - MSP.send_message(MSPCodes.MSP_VOLTAGE_METER_CONFIG, false, false, nextCallBack); - } else { - nextCallBack(); - } - } - - function load_current() { - const nextCallBack = load_rx_config; - if (semver.gte(FC.CONFIG.flightControllerVersion, "3.1.0")) { - MSP.send_message(MSPCodes.MSP_CURRENT_METER_CONFIG, false, false, nextCallBack); - } else { - nextCallBack(); - } - } - function load_rx_config() { const nextCallBack = load_filter_config; if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_31)) { @@ -186,7 +118,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } function load_filter_config() { - const nextCallBack = load_html; + const nextCallBack = load_advanced_config; if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)) { MSP.send_message(MSPCodes.MSP_FILTER_CONFIG, false, false, nextCallBack); } else { @@ -194,6 +126,10 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } } + function load_advanced_config() { + MSP.send_message(MSPCodes.MSP_ADVANCED_CONFIG, false, false, load_html); + } + function load_html() { $('#content').load("./tabs/configuration.html", process_html); } @@ -203,45 +139,6 @@ TABS.configuration.initialize = function (callback, scrollPosition) { function process_html() { self.analyticsChanges = {}; - const mixer_list_e = $('select.mixerList'); - for (let selectIndex = 0; selectIndex < mixerList.length; selectIndex++) { - mixerList.forEach(function (mixerEntry, mixerIndex) { - if (mixerEntry.pos === selectIndex) { - mixer_list_e.append(''); - } - }); - } - - function refreshMixerPreview() { - const imgSrc = CommonUtils.GetMixerImageSrc(FC.MIXER_CONFIG.mixer, FC.MIXER_CONFIG.reverseMotorDir, FC.CONFIG.apiVersion); - $('.mixerPreview img').attr('src', imgSrc); - } - - const reverseMotorSwitch_e = $('#reverseMotorSwitch'); - const reverseMotor_e = $('.reverseMotor'); - - reverseMotorSwitch_e.change(function() { - FC.MIXER_CONFIG.reverseMotorDir = $(this).prop('checked') ? 1 : 0; - refreshMixerPreview(); - }); - reverseMotorSwitch_e.prop('checked', FC.MIXER_CONFIG.reverseMotorDir != 0).change(); - - mixer_list_e.change(function () { - const mixerValue = parseInt($(this).val()); - - let newValue; - if (mixerValue !== FC.MIXER_CONFIG.mixer) { - newValue = $(this).find('option:selected').text(); - } - self.analyticsChanges['Mixer'] = newValue; - - FC.MIXER_CONFIG.mixer = mixerValue; - refreshMixerPreview(); - }); - - // select current mixer configuration - mixer_list_e.val(FC.MIXER_CONFIG.mixer).change(); - const features_e = $('.tab-configuration .features'); FC.FEATURE_CONFIG.features.generateElements(features_e); @@ -256,7 +153,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_37)) { for (let i = 1; i <= 5; i++) { - dshotBeeperBeaconTone.append(''); + dshotBeeperBeaconTone.append(``); } dshotBeeper_e.show(); } else { @@ -304,7 +201,6 @@ TABS.configuration.initialize = function (callback, scrollPosition) { FC.BEEPER_CONFIG.beepers.generateElements(template, destination); } else { beeper_e.hide(); - reverseMotor_e.hide(); } // translate to user-selected language @@ -343,9 +239,9 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } else { for (let i = 0; i < alignments.length; i++) { - orientation_gyro_e.append(''); - orientation_acc_e.append(''); - orientation_mag_e.append(''); + orientation_gyro_e.append(``); + orientation_acc_e.append(``); + orientation_mag_e.append(``); } orientation_gyro_e.val(FC.SENSOR_ALIGNMENT.align_gyro); @@ -406,18 +302,18 @@ TABS.configuration.initialize = function (callback, scrollPosition) { const detected_dual_gyros = (FC.SENSOR_ALIGNMENT.gyro_detection_flags & GYRO_DETECTION_FLAGS.DETECTED_DUAL_GYROS) != 0; if (detected_gyro_1) { - orientation_gyro_to_use_e.append(''); + orientation_gyro_to_use_e.append(``); } if (detected_gyro_2) { - orientation_gyro_to_use_e.append(''); + orientation_gyro_to_use_e.append(``); } if (detected_dual_gyros) { - orientation_gyro_to_use_e.append(''); + orientation_gyro_to_use_e.append(``); } for (let i = 0; i < alignments.length; i++) { - orientation_gyro_1_align_e.append(''); - orientation_gyro_2_align_e.append(''); + orientation_gyro_1_align_e.append(``); + orientation_gyro_2_align_e.append(``); } orientation_gyro_to_use_e.val(FC.SENSOR_ALIGNMENT.gyro_to_use); @@ -455,127 +351,6 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } } - // ESC protocols - const escProtocols = EscProtocols.GetAvailableProtocols(FC.CONFIG.apiVersion); - - const esc_protocol_e = $('select.escprotocol'); - - for (let j = 0; j < escProtocols.length; j++) { - esc_protocol_e.append(``); - } - - $("input[id='unsyncedPWMSwitch']").change(function() { - if ($(this).is(':checked')) { - $('div.unsyncedpwmfreq').show(); - } else { - $('div.unsyncedpwmfreq').hide(); - } - }); - - $('input[id="unsyncedPWMSwitch"]').prop('checked', FC.PID_ADVANCED_CONFIG.use_unsyncedPwm !== 0).change(); - $('input[name="unsyncedpwmfreq"]').val(FC.PID_ADVANCED_CONFIG.motor_pwm_rate); - $('input[name="digitalIdlePercent"]').val(FC.PID_ADVANCED_CONFIG.digitalIdlePercent); - if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)) { - let dshotBidirectional_e = $('input[id="dshotBidir"]'); - dshotBidirectional_e.prop('checked', FC.MOTOR_CONFIG.use_dshot_telemetry).change(); - - self.previousDshotBidir = FC.MOTOR_CONFIG.use_dshot_telemetry; - self.previousFilterDynQ = FC.FILTER_CONFIG.dyn_notch_q; - self.previousFilterDynWidth = FC.FILTER_CONFIG.dyn_notch_width_percent; - - dshotBidirectional_e.change(function () { - let value = $(this).prop('checked'); - - let newValue = undefined; - if (value !== FC.MOTOR_CONFIG.use_dshot_telemetry) { - newValue = value ? 'On' : 'Off'; - } - self.analyticsChanges['BidirectionalDshot'] = newValue; - - FC.MOTOR_CONFIG.use_dshot_telemetry = value; - - FC.FILTER_CONFIG.dyn_notch_width_percent = self.previousFilterDynWidth; - FC.FILTER_CONFIG.dyn_notch_q = self.previousFilterDynQ; - - if (FC.FILTER_CONFIG.gyro_rpm_notch_harmonics !== 0) { // if rpm filter is active - if (value && !self.previousDshotBidir) { - FC.FILTER_CONFIG.dyn_notch_width_percent = FILTER_DEFAULT.dyn_notch_width_percent_rpm; - FC.FILTER_CONFIG.dyn_notch_q = FILTER_DEFAULT.dyn_notch_q_rpm; - } else if (!value && self.previousDshotBidir) { - FC.FILTER_CONFIG.dyn_notch_width_percent = FILTER_DEFAULT.dyn_notch_width_percent; - FC.FILTER_CONFIG.dyn_notch_q = FILTER_DEFAULT.dyn_notch_q; - } - } - - if (FC.FILTER_CONFIG.dyn_notch_width_percent !== self.previousFilterDynWidth) { - showDialogDynFiltersChange(); - } - }); - - $('input[name="motorPoles"]').val(FC.MOTOR_CONFIG.motor_poles); - } - - $('#escProtocolTooltip').toggle(semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_42)); - $('#escProtocolTooltipNoDSHOT1200').toggle(semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)); - - function updateVisibility() { - // Hide unused settings - const protocolName = $('select.escprotocol option:selected').text(); - const protocolConfigured = protocolName !== 'DISABLED'; - let digitalProtocol = false; - switch (protocolName) { - case 'DSHOT150': - case 'DSHOT300': - case 'DSHOT600': - case 'DSHOT1200': - case 'PROSHOT1000': - digitalProtocol = true; - - break; - default: - - break; - } - - const rpmFeaturesVisible = digitalProtocol && ($("input[id='dshotBidir']").is(':checked') || $("input[name='ESC_SENSOR']").is(':checked')); - - $('div.minthrottle').toggle(protocolConfigured && !digitalProtocol); - $('div.maxthrottle').toggle(protocolConfigured && !digitalProtocol); - $('div.mincommand').toggle(protocolConfigured && !digitalProtocol); - $('div.checkboxPwm').toggle(protocolConfigured && !digitalProtocol); - $('div.unsyncedpwmfreq').toggle(protocolConfigured && !digitalProtocol); - - $('div.digitalIdlePercent').toggle(protocolConfigured && digitalProtocol); - $('.escSensor').toggle(protocolConfigured && digitalProtocol); - - $('div.checkboxDshotBidir').toggle(protocolConfigured && semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42) && digitalProtocol); - $('div.motorPoles').toggle(protocolConfigured && rpmFeaturesVisible && semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)); - - $('.escMotorStop').toggle(protocolConfigured); - - $('#escProtocolDisabled').toggle(!protocolConfigured); - - //trigger change unsyncedPWMSwitch to show/hide Motor PWM freq input - $("input[id='unsyncedPWMSwitch']").change(); - } - - esc_protocol_e.val(FC.PID_ADVANCED_CONFIG.fast_pwm_protocol + 1); - esc_protocol_e.change(function () { - const escProtocolValue = parseInt($(this).val()) - 1; - - let newValue = undefined; - if (escProtocolValue !== FC.PID_ADVANCED_CONFIG.fast_pwm_protocol) { - newValue = $(this).find('option:selected').text(); - } - self.analyticsChanges['EscProtocol'] = newValue; - - updateVisibility(); - }).change(); - - //trigger change dshotBidir and ESC_SENSOR to show/hide Motor Poles tab - $("input[id='dshotBidir']").change(updateVisibility).change(); - $("input[name='ESC_SENSOR']").change(updateVisibility).change(); - // Gyro and PID update const gyroUse32kHzElement = $('input[id="gyroUse32kHz"]'); const gyroTextElement = $('input.gyroFrequency'); @@ -600,7 +375,8 @@ TABS.configuration.initialize = function (callback, scrollPosition) { gyroSelectElement.empty(); - const MAX_DENOM = semver.gte(FC.CONFIG.apiVersion, "1.25.0") ? 32 : 8; + const MAX_DENOM = semver.gte(FC.CONFIG.apiVersion, "1.25.0") && semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_41) ? 32 : 8; + for (let denom = 1; denom <= MAX_DENOM; denom++) { addDenomOption(gyroSelectElement, denom, gyroBaseFreq); } @@ -647,7 +423,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { $('.systemconfigNote').html(i18n.getMessage('configurationLoopTimeHelp')); gyroSelectElement.change(function () { - const originalPidDenom = pidSelectElement.val(); + const originalPidDenom = parseInt(pidSelectElement.val()); let pidBaseFreq; if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_43)) { @@ -811,7 +587,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } const serialRXSelectEl = $('select.serialRX'); - FC.getSerialRxTypes().forEach((serialRxType, index) => { + FC.getSerialRxTypes().forEach(function(serialRxType, index) { serialRXSelectEl.append(``); }); @@ -829,9 +605,10 @@ TABS.configuration.initialize = function (callback, scrollPosition) { // select current serial RX type serialRXSelectEl.val(FC.RX_CONFIG.serialrx_provider); + const spiRxTypes = []; if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_31)) { - const spiRxTypes = [ + spiRxTypes.push( 'NRF24_V202_250K', 'NRF24_V202_1M', 'NRF24_SYMA_X', @@ -840,8 +617,8 @@ TABS.configuration.initialize = function (callback, scrollPosition) { 'CX10A', 'NRF24_H8_3D', 'NRF24_INAV', - 'FRSKY_D', - ]; + 'FRSKY_D' + ); if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_37)) { spiRxTypes.push( @@ -875,7 +652,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { const spiRx_e = $('select.spiRx'); for (let i = 0; i < spiRxTypes.length; i++) { - spiRx_e.append(''); + spiRx_e.append(``); } spiRx_e.change(function () { @@ -908,150 +685,12 @@ TABS.configuration.initialize = function (callback, scrollPosition) { $('input[name="roll"]').val(FC.CONFIG.accelerometerTrims[1]); $('input[name="pitch"]').val(FC.CONFIG.accelerometerTrims[0]); - //fill motor disarm params and FC loop time - if(semver.gte(FC.CONFIG.apiVersion, "1.8.0")) { - $('input[name="autodisarmdelay"]').val(FC.ARMING_CONFIG.auto_disarm_delay); - $('input[id="disarmkillswitch"]').prop('checked', FC.ARMING_CONFIG.disarm_kill_switch !== 0); - $('div.disarm').show(); - - $('div.cycles').show(); - } - - if(semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_37) || !isExpertModeEnabled()) { - $('input[id="disarmkillswitch"]').prop('checked', true); - $('div.disarm').hide(); - } - $('._smallAngle').toggle(semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_37)); if(semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_37)) { $('input[id="configurationSmallAngle"]').val(FC.ARMING_CONFIG.small_angle); } - // fill throttle - $('input[name="minthrottle"]').val(FC.MOTOR_CONFIG.minthrottle); - $('input[name="maxthrottle"]').val(FC.MOTOR_CONFIG.maxthrottle); - $('input[name="mincommand"]').val(FC.MOTOR_CONFIG.mincommand); - - // fill battery - if (self.SHOW_OLD_BATTERY_CONFIG) { - if (semver.gte(FC.CONFIG.flightControllerVersion, "3.1.0")) { - const batteryMeterTypes = [ - 'Onboard ADC', - 'ESC Sensor', - ]; - - const batteryMeterType_e = $('select.batterymetertype'); - for (let i = 0; i < batteryMeterTypes.length; i++) { - batteryMeterType_e.append(``); - } - - batteryMeterType_e.change(function () { - FC.MISC.batterymetertype = parseInt($(this).val()); - checkUpdateVbatControls(); - }); - batteryMeterType_e.val(FC.MISC.batterymetertype).change(); - } else { - $('div.batterymetertype').hide(); - } - - if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_41)) { - $('input[name="mincellvoltage"]').prop('step','0.01'); - $('input[name="maxcellvoltage"]').prop('step','0.01'); - $('input[name="warningcellvoltage"]').prop('step','0.01'); - } - - $('input[name="mincellvoltage"]').val(FC.MISC.vbatmincellvoltage); - $('input[name="maxcellvoltage"]').val(FC.MISC.vbatmaxcellvoltage); - $('input[name="warningcellvoltage"]').val(FC.MISC.vbatwarningcellvoltage); - $('input[name="voltagescale"]').val(FC.MISC.vbatscale); - - // fill current - const currentMeterTypes = [ - 'None', - 'Onboard ADC', - 'Virtual', - ]; - - if (semver.gte(FC.CONFIG.flightControllerVersion, "3.1.0")) { - currentMeterTypes.push('ESC Sensor'); - } - - const currentMeterType_e = $('select.currentmetertype'); - for (let i = 0; i < currentMeterTypes.length; i++) { - currentMeterType_e.append(``); - } - - currentMeterType_e.change(function () { - FC.BF_CONFIG.currentmetertype = parseInt($(this).val()); - checkUpdateCurrentControls(); - }); - currentMeterType_e.val(FC.BF_CONFIG.currentmetertype).change(); - - $('input[name="currentscale"]').val(FC.BF_CONFIG.currentscale); - $('input[name="currentoffset"]').val(FC.BF_CONFIG.currentoffset); - $('input[name="multiwiicurrentoutput"]').prop('checked', FC.MISC.multiwiicurrentoutput !== 0); - } else { - $('.oldBatteryConfig').hide(); - } - - function checkUpdateVbatControls() { - if (FC.FEATURE_CONFIG.features.isEnabled('VBAT')) { - $('.vbatmonitoring').show(); - - if (semver.gte(FC.CONFIG.flightControllerVersion, "3.1.0")) { - $('select.batterymetertype').show(); - - if (FC.MISC.batterymetertype !== 0) { - $('.vbatCalibration').hide(); - } - } else { - $('select.batterymetertype').hide(); - } - } else { - $('.vbatmonitoring').hide(); - } - } - - function checkUpdateCurrentControls() { - if (FC.FEATURE_CONFIG.features.isEnabled('CURRENT_METER')) { - $('.currentMonitoring').show(); - - switch(FC.BF_CONFIG.currentmetertype) { - case 0: - $('.currentCalibration').hide(); - $('.currentOutput').hide(); - - break; - case 3: - $('.currentCalibration').hide(); - } - - if (FC.BF_CONFIG.currentmetertype !== 1 && FC.BF_CONFIG.currentmetertype !== 2) { - $('.currentCalibration').hide(); - } - } else { - $('.currentMonitoring').hide(); - } - } - - //fill 3D - if (semver.lt(FC.CONFIG.apiVersion, "1.14.0")) { - $('.tab-configuration ._3d').hide(); - } else { - $('input[name="3ddeadbandlow"]').val(FC.MOTOR_3D_CONFIG.deadband3d_low); - $('input[name="3ddeadbandhigh"]').val(FC.MOTOR_3D_CONFIG.deadband3d_high); - $('input[name="3dneutral"]').val(FC.MOTOR_3D_CONFIG.neutral); - } - // UI hooks - function checkShowDisarmDelay() { - if (FC.FEATURE_CONFIG.features.isEnabled('MOTOR_STOP')) { - $('div.disarmdelay').show(); - } else { - $('div.disarmdelay').hide(); - } - } - function checkShowSerialRxBox() { if (FC.FEATURE_CONFIG.features.isEnabled('RX_SERIAL')) { $('div.serialRXBox').show(); @@ -1076,46 +715,14 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } } - function checkUpdate3dControls() { - if (FC.FEATURE_CONFIG.features.isEnabled('3D')) { - $('._3dSettings').show(); - } else { - $('._3dSettings').hide(); - } - } - $('input.feature', features_e).change(function () { const element = $(this); FC.FEATURE_CONFIG.features.updateData(element); updateTabList(FC.FEATURE_CONFIG.features); - switch (element.attr('name')) { - case 'MOTOR_STOP': - checkShowDisarmDelay(); - break; - - case 'VBAT': - if (self.SHOW_OLD_BATTERY_CONFIG) { - checkUpdateVbatControls(); - } - - break; - case 'CURRENT_METER': - if (self.SHOW_OLD_BATTERY_CONFIG) { - checkUpdateCurrentControls(); - } - break; - case 'GPS': - checkUpdateGpsControls(); - break; - - case '3D': - checkUpdate3dControls(); - break; - - default: - break; + if (element.attr('name') === 'GPS') { + checkUpdateGpsControls(); } }); @@ -1143,18 +750,11 @@ TABS.configuration.initialize = function (callback, scrollPosition) { FC.BEEPER_CONFIG.beepers.updateData(element); }); - checkShowDisarmDelay(); checkShowSerialRxBox(); checkShowSpiRxBox(); checkUpdateGpsControls(); - checkUpdate3dControls(); - if (self.SHOW_OLD_BATTERY_CONFIG) { - checkUpdateVbatControls(); - checkUpdateCurrentControls(); - } - - $('a.save').click(function () { + $('a.save').on('click', function() { // gather data that doesn't have automatic change event bound FC.BOARD_ALIGNMENT_CONFIG.roll = parseInt($('input[name="board_align_roll"]').val()); FC.BOARD_ALIGNMENT_CONFIG.pitch = parseInt($('input[name="board_align_pitch"]').val()); @@ -1163,46 +763,15 @@ TABS.configuration.initialize = function (callback, scrollPosition) { FC.CONFIG.accelerometerTrims[1] = parseInt($('input[name="roll"]').val()); FC.CONFIG.accelerometerTrims[0] = parseInt($('input[name="pitch"]').val()); - // motor disarm - if(semver.gte(FC.CONFIG.apiVersion, "1.8.0")) { - FC.ARMING_CONFIG.auto_disarm_delay = parseInt($('input[name="autodisarmdelay"]').val()); - FC.ARMING_CONFIG.disarm_kill_switch = $('input[id="disarmkillswitch"]').is(':checked') ? 1 : 0; - } + // small angle configuration if(semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_37)) { FC.ARMING_CONFIG.small_angle = parseInt($('input[id="configurationSmallAngle"]').val()); } - FC.MOTOR_CONFIG.minthrottle = parseInt($('input[name="minthrottle"]').val()); - FC.MOTOR_CONFIG.maxthrottle = parseInt($('input[name="maxthrottle"]').val()); - FC.MOTOR_CONFIG.mincommand = parseInt($('input[name="mincommand"]').val()); - if(semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)) { - FC.MOTOR_CONFIG.motor_poles = parseInt($('input[name="motorPoles"]').val()); - } - - if(self.SHOW_OLD_BATTERY_CONFIG) { - FC.MISC.vbatmincellvoltage = parseFloat($('input[name="mincellvoltage"]').val()); - FC.MISC.vbatmaxcellvoltage = parseFloat($('input[name="maxcellvoltage"]').val()); - FC.MISC.vbatwarningcellvoltage = parseFloat($('input[name="warningcellvoltage"]').val()); - FC.MISC.vbatscale = parseInt($('input[name="voltagescale"]').val()); - - FC.BF_CONFIG.currentscale = parseInt($('input[name="currentscale"]').val()); - FC.BF_CONFIG.currentoffset = parseInt($('input[name="currentoffset"]').val()); - FC.MISC.multiwiicurrentoutput = $('input[name="multiwiicurrentoutput"]').is(':checked') ? 1 : 0; - } - - if(semver.gte(FC.CONFIG.apiVersion, "1.14.0")) { - FC.MOTOR_3D_CONFIG.deadband3d_low = parseInt($('input[name="3ddeadbandlow"]').val()); - FC.MOTOR_3D_CONFIG.deadband3d_high = parseInt($('input[name="3ddeadbandhigh"]').val()); - FC.MOTOR_3D_CONFIG.neutral = parseInt($('input[name="3dneutral"]').val()); - } - if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_41)) { FC.SENSOR_ALIGNMENT.gyro_to_use = parseInt(orientation_gyro_to_use_e.val()); } - FC.PID_ADVANCED_CONFIG.fast_pwm_protocol = parseInt(esc_protocol_e.val()-1); - FC.PID_ADVANCED_CONFIG.use_unsyncedPwm = $('input[id="unsyncedPWMSwitch"]').is(':checked') ? 1 : 0; - FC.PID_ADVANCED_CONFIG.motor_pwm_rate = parseInt($('input[name="unsyncedpwmfreq"]').val()); FC.PID_ADVANCED_CONFIG.gyro_sync_denom = parseInt(gyroSelectElement.val()); const value = parseInt(pidSelectElement.val()); @@ -1215,19 +784,26 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } FC.PID_ADVANCED_CONFIG.pid_process_denom = value; - - FC.PID_ADVANCED_CONFIG.digitalIdlePercent = parseFloat($('input[name="digitalIdlePercent"]').val()); if (semver.gte(FC.CONFIG.apiVersion, "1.25.0") && semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_41)) { FC.PID_ADVANCED_CONFIG.gyroUse32kHz = $('input[id="gyroUse32kHz"]').is(':checked') ? 1 : 0; } - if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_31)) { - FC.RX_CONFIG.fpvCamAngleDegrees = parseInt($('input[name="fpvCamAngleDegrees"]').val()); - } + FC.RX_CONFIG.fpvCamAngleDegrees = parseInt($('input[name="fpvCamAngleDegrees"]').val()); analytics.sendChangeEvents(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, self.analyticsChanges); self.analyticsChanges = {}; + // fill some data + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_34)) { + FC.GPS_CONFIG.auto_baud = $('input[name="gps_auto_baud"]').is(':checked') ? 1 : 0; + FC.GPS_CONFIG.auto_config = $('input[name="gps_auto_config"]').is(':checked') ? 1 : 0; + } + + FC.SENSOR_CONFIG.acc_hardware = $('input[id="accHardwareSwitch"]').is(':checked') ? 0 : 1; + FC.SENSOR_CONFIG.baro_hardware = $('input[id="baroHardwareSwitch"]').is(':checked') ? 0 : 1; + FC.SENSOR_CONFIG.mag_hardware = $('input[id="magHardwareSwitch"]').is(':checked') ? 0 : 1; + FC.CONFIG.name = $.trim($('input[name="craftName"]').val()); + function save_serial_config() { const nextCallBack = save_feature_config; mspHelper.sendSerialConfig(nextCallBack); @@ -1248,7 +824,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } function save_misc() { - const nextCallBack = save_mixer_config; + const nextCallBack = save_board_alignment_config; if(semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_33)) { MSP.send_message(MSPCodes.MSP_SET_MISC, mspHelper.crunch(MSPCodes.MSP_SET_MISC), false, nextCallBack); } else { @@ -1256,32 +832,14 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } } - function save_mixer_config() { - const nextCallBack = save_board_alignment_config; - MSP.send_message(MSPCodes.MSP_SET_MIXER_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_MIXER_CONFIG), false, nextCallBack); - } - function save_board_alignment_config() { - const nextCallBack = save_motor_config; + const nextCallBack = save_gps_config; MSP.send_message(MSPCodes.MSP_SET_BOARD_ALIGNMENT_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_BOARD_ALIGNMENT_CONFIG), false, nextCallBack); } - function save_motor_config() { - const nextCallBack = save_gps_config; - if(semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_33)) { - MSP.send_message(MSPCodes.MSP_SET_MOTOR_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_MOTOR_CONFIG), false, nextCallBack); - } else { - nextCallBack(); - } - } function save_gps_config() { - if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_34)) { - FC.GPS_CONFIG.auto_baud = $('input[name="gps_auto_baud"]').is(':checked') ? 1 : 0; - FC.GPS_CONFIG.auto_config = $('input[name="gps_auto_config"]').is(':checked') ? 1 : 0; - } - - const nextCallBack = save_motor_3d_config; + const nextCallBack = save_rc_deadband; if(semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_33)) { MSP.send_message(MSPCodes.MSP_SET_GPS_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_GPS_CONFIG), false, nextCallBack); } else { @@ -1289,28 +847,20 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } } - function save_motor_3d_config() { - const nextCallBack = save_rc_deadband; - MSP.send_message(MSPCodes.MSP_SET_MOTOR_3D_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_MOTOR_3D_CONFIG), false, nextCallBack); - } - function save_rc_deadband() { - const nextCallBack = save_sensor_alignment; - MSP.send_message(MSPCodes.MSP_SET_RC_DEADBAND, mspHelper.crunch(MSPCodes.MSP_SET_RC_DEADBAND), false, nextCallBack); + MSP.send_message(MSPCodes.MSP_SET_RC_DEADBAND, mspHelper.crunch(MSPCodes.MSP_SET_RC_DEADBAND), false, save_sensor_alignment); } function save_sensor_alignment() { - const nextCallBack = save_esc_protocol; - MSP.send_message(MSPCodes.MSP_SET_SENSOR_ALIGNMENT, mspHelper.crunch(MSPCodes.MSP_SET_SENSOR_ALIGNMENT), false, nextCallBack); + MSP.send_message(MSPCodes.MSP_SET_SENSOR_ALIGNMENT, mspHelper.crunch(MSPCodes.MSP_SET_SENSOR_ALIGNMENT), false, save_esc_protocol); } + function save_esc_protocol() { - const nextCallBack = save_acc_trim; - MSP.send_message(MSPCodes.MSP_SET_ADVANCED_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_ADVANCED_CONFIG), false, nextCallBack); + MSP.send_message(MSPCodes.MSP_SET_ADVANCED_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_ADVANCED_CONFIG), false, save_acc_trim); } function save_acc_trim() { - const nextCallBack = save_arming_config; - MSP.send_message(MSPCodes.MSP_SET_ACC_TRIM, mspHelper.crunch(MSPCodes.MSP_SET_ACC_TRIM), false, nextCallBack); + MSP.send_message(MSPCodes.MSP_SET_ACC_TRIM, mspHelper.crunch(MSPCodes.MSP_SET_ACC_TRIM), false, save_arming_config); } function save_arming_config() { @@ -1318,41 +868,11 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } function save_sensor_config() { - FC.SENSOR_CONFIG.acc_hardware = $('input[id="accHardwareSwitch"]').is(':checked') ? 0 : 1; - FC.SENSOR_CONFIG.baro_hardware = $('input[id="baroHardwareSwitch"]').is(':checked') ? 0 : 1; - FC.SENSOR_CONFIG.mag_hardware = $('input[id="magHardwareSwitch"]').is(':checked') ? 0 : 1; - - const nextCallBack = save_name; - MSP.send_message(MSPCodes.MSP_SET_SENSOR_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_SENSOR_CONFIG), false, nextCallBack); + MSP.send_message(MSPCodes.MSP_SET_SENSOR_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_SENSOR_CONFIG), false, save_name); } function save_name() { - let nextCallBack = save_rx_config; - - if(self.SHOW_OLD_BATTERY_CONFIG) { - nextCallBack = save_battery; - } - - FC.CONFIG.name = $.trim($('input[name="craftName"]').val()); - MSP.send_message(MSPCodes.MSP_SET_NAME, mspHelper.crunch(MSPCodes.MSP_SET_NAME), false, nextCallBack); - } - - function save_battery() { - const nextCallBack = save_current; - if (semver.gte(FC.CONFIG.flightControllerVersion, "3.1.0")) { - MSP.send_message(MSPCodes.MSP_SET_VOLTAGE_METER_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_VOLTAGE_METER_CONFIG), false, nextCallBack); - } else { - nextCallBack(); - } - } - - function save_current() { - const nextCallBack = save_rx_config; - if (semver.gte(FC.CONFIG.flightControllerVersion, "3.1.0")) { - MSP.send_message(MSPCodes.MSP_SET_CURRENT_METER_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_CURRENT_METER_CONFIG), false, nextCallBack); - } else { - nextCallBack(); - } + MSP.send_message(MSPCodes.MSP_SET_NAME, mspHelper.crunch(MSPCodes.MSP_SET_NAME), false, save_rx_config); } function save_rx_config() { @@ -1390,7 +910,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { }); // status data pulled via separate timer with static speed - GUI.interval_add('status_pull', function status_pull() { + GUI.interval_add('status_pull', function() { MSP.send_message(MSPCodes.MSP_STATUS); }, 250, true); GUI.content_ready(callback); diff --git a/src/js/tabs/motors.js b/src/js/tabs/motors.js index 4262d17b018..2e9be9e068a 100644 --- a/src/js/tabs/motors.js +++ b/src/js/tabs/motors.js @@ -1,38 +1,46 @@ 'use strict'; TABS.motors = { - feature3DEnabled: false, - escProtocolIsDshot: false, - sensor: "gyro", - sensorGyroRate: 20, - sensorGyroScale: 2000, - sensorAccelRate: 20, - sensorAccelScale: 2, - sensorSelectValues: { - "gyroScale": {"10" : 10, - "25" : 25, - "50" : 50, - "100" : 100, - "200" : 200, - "300" : 300, - "400" : 400, - "500" : 500, - "1000" : 1000, - "2000" : 2000}, - "accelScale": {"0.05" : 0.05, - "0.1" : 0.1, - "0.2" : 0.2, - "0.3" : 0.3, - "0.4" : 0.4, - "0.5" : 0.5, - "1" : 1, - "2" : 2} + previousDshotBidir: null, + previousFilterDynQ: null, + previousFilterDynWidth: null, + analyticsChanges: {}, + isDirty: false, + feature3DEnabled: false, + sensor: "gyro", + sensorGyroRate: 20, + sensorGyroScale: 2000, + sensorAccelRate: 20, + sensorAccelScale: 2, + sensorSelectValues: { + "gyroScale": { + "10" : 10, + "25" : 25, + "50" : 50, + "100" : 100, + "200" : 200, + "300" : 300, + "400" : 400, + "500" : 500, + "1000" : 1000, + "2000" : 2000, }, - // These are translated into proper Dshot values on the flight controller - DSHOT_DISARMED_VALUE: 1000, - DSHOT_MAX_VALUE: 2000, - DSHOT_3D_NEUTRAL: 1500, - numberOfValidOutputs: -1, + "accelScale": { + "0.05" : 0.05, + "0.1" : 0.1, + "0.2" : 0.2, + "0.3" : 0.3, + "0.4" : 0.4, + "0.5" : 0.5, + "1" : 1, + "2" : 2, + }, + }, + // These are translated into proper Dshot values on the flight controller + DSHOT_PROTOCOL_MIN_VALUE: 0, + DSHOT_DISARMED_VALUE: 1000, + DSHOT_MAX_VALUE: 2000, + DSHOT_3D_NEUTRAL: 1500, }; TABS.motors.initialize = function (callback) { @@ -41,59 +49,33 @@ TABS.motors.initialize = function (callback) { self.armed = false; self.escProtocolIsDshot = false; + // Update filtering defaults based on API version + const FILTER_DEFAULT = FC.getFilterDefaults(); + if (GUI.active_tab != 'motors') { GUI.active_tab = 'motors'; } - function get_arm_status() { - MSP.send_message(MSPCodes.MSP_STATUS, false, false, load_feature_config); - } - - function load_feature_config() { - MSP.send_message(MSPCodes.MSP_FEATURE_CONFIG, false, false, load_motor_3d_config); - } - - function load_motor_3d_config() { - MSP.send_message(MSPCodes.MSP_MOTOR_3D_CONFIG, false, false, load_esc_protocol); - } - - function load_esc_protocol() { - MSP.send_message(MSPCodes.MSP_ADVANCED_CONFIG, false, false, load_motor_output_reordering); - } - - function load_motor_output_reordering() { - MSP.send_message(MSPCodes.MSP2_MOTOR_OUTPUT_REORDERING, false, false, load_motor_data); - } - - function load_motor_data() { - MSP.send_message(MSPCodes.MSP_MOTOR, false, false, load_motor_telemetry_data); - } - - function load_motor_telemetry_data() { - if (FC.MOTOR_CONFIG.use_dshot_telemetry || FC.MOTOR_CONFIG.use_esc_sensor) { - MSP.send_message(MSPCodes.MSP_MOTOR_TELEMETRY, false, false, load_mixer_config); - } else { - load_mixer_config(); - } - } - - function load_mixer_config() { - MSP.send_message(MSPCodes.MSP_MIXER_CONFIG, false, false, load_html); - } + Promise + .resolve(true) + .then(() => { return MSP.promise(MSPCodes.MSP_STATUS); }) + .then(() => { return MSP.promise(MSPCodes.MSP_FEATURE_CONFIG); }) + .then(() => { return MSP.promise(MSPCodes.MSP_MIXER_CONFIG); }) + .then(() => { return (FC.MOTOR_CONFIG.use_dshot_telemetry || FC.MOTOR_CONFIG.use_esc_sensor) ? MSP.promise(MSPCodes.MSP_MOTOR_TELEMETRY) : true; }) + .then(() => { return MSP.promise(MSPCodes.MSP_MOTOR_CONFIG); }) + .then(() => { return MSP.promise(MSPCodes.MSP_MOTOR_3D_CONFIG); }) + .then(() => { return MSP.promise(MSPCodes.MSP2_MOTOR_OUTPUT_REORDERING); }) + .then(() => { return MSP.promise(MSPCodes.MSP_ADVANCED_CONFIG); }) + .then(() => { return MSP.promise(MSPCodes.MSP_ARMING_CONFIG); }) + .then(() => { return (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)) ? MSP.promise(MSPCodes.MSP_FILTER_CONFIG) : true; }) + .then(() => { return MSP.promise(MSPCodes.MSP_MIXER_CONFIG); }) + .then(() => { return (semver.gte(FC.CONFIG.apiVersion, "1.8.0")) ? MSP.promise(MSPCodes.MSP_ARMING_CONFIG) : true; }) + .then(() => { load_html(); }); function load_html() { $('#content').load("./tabs/motors.html", process_html); } - // Get information from Betaflight - if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_36)) { - // BF 3.2.0+ - MSP.send_message(MSPCodes.MSP_MOTOR_CONFIG, false, false, get_arm_status); - } else { - // BF 3.1.x or older - MSP.send_message(MSPCodes.MSP_MISC, false, false, get_arm_status); - } - function update_arm_status() { self.armed = bit_check(FC.CONFIG.mode, 0); } @@ -241,8 +223,10 @@ TABS.motors.initialize = function (callback) { update_arm_status(); self.feature3DEnabled = FC.FEATURE_CONFIG.features.isEnabled('3D'); + const motorsEnableTestModeElement = $('#motorsEnableTestMode'); + self.analyticsChanges = {}; - $('#motorsEnableTestMode').prop('checked', false); + motorsEnableTestModeElement.prop('checked', false); if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_42) || !(FC.MOTOR_CONFIG.use_dshot_telemetry || FC.MOTOR_CONFIG.use_esc_sensor)) { $(".motor_testing .telemetry").hide(); @@ -253,6 +237,78 @@ TABS.motors.initialize = function (callback) { } } + function setToolButtons() { + if (self.isDirty) { + // save and reboot button appears after changing settings + $('.tool-buttons').hide(); + $('.save_btn').show(); + } else { + // hide save and reboot until settings are actually changed. + // if done this way we don't have to stop motors because it can't activate after settings changed. + $('.save_btn').hide(); + } + } + + setToolButtons(); + + // Stop motor testing on configuration changes + function disableHandler(e) { + if (e.target !== e.currentTarget) { + self.isDirty = true; + disableMotorTest(); + setToolButtons(); + } + e.stopPropagation(); + } + + // Add EventListener for configuration changes + document.querySelectorAll('.configuration').forEach(elem => elem.addEventListener('change', disableHandler)); + + /* + * MIXER + */ + + const mixerListElement = $('select.mixerList'); + for (let selectIndex = 0; selectIndex < mixerList.length; selectIndex++) { + mixerList.forEach(function (mixerEntry, mixerIndex) { + if (mixerEntry.pos === selectIndex) { + mixerListElement.append(``); + } + }); + } + + function refreshMixerPreview() { + const mixer = FC.MIXER_CONFIG.mixer; + const reverse = FC.MIXER_CONFIG.reverseMotorDir ? "_reversed" : ""; + + $('.mixerPreview img').attr('src', `./resources/motor_order/${mixerList[mixer - 1].image}${reverse}.svg`); + } + + const reverseMotorSwitchElement = $('#reverseMotorSwitch'); + + reverseMotorSwitchElement.change(function() { + FC.MIXER_CONFIG.reverseMotorDir = $(this).prop('checked') ? 1 : 0; + refreshMixerPreview(); + }); + + reverseMotorSwitchElement.prop('checked', FC.MIXER_CONFIG.reverseMotorDir !== 0).change(); + + mixerListElement.change(function () { + const mixerValue = parseInt($(this).val()); + + let newValue; + if (mixerValue !== FC.MIXER_CONFIG.mixer) { + newValue = $(this).find('option:selected').text(); + } + self.analyticsChanges['Mixer'] = newValue; + + FC.MIXER_CONFIG.mixer = mixerValue; + refreshMixerPreview(); + }); + + // select current mixer configuration + mixerListElement.val(FC.MIXER_CONFIG.mixer).change(); + update_model(FC.MIXER_CONFIG.mixer); // Always start with default/empty sensor data array, clean slate all @@ -272,15 +328,15 @@ TABS.motors.initialize = function (callback) { let accelOffsetEstablished = false; // cached elements - const motorVoltage = $('.motors-bat-voltage'), - motor_mah_drawing_e = $('.motors-bat-mah-drawing'), - motor_mah_drawn_e = $('.motors-bat-mah-drawn'); + const motorVoltage = $('.motors-bat-voltage'); + const motorMahDrawingElement = $('.motors-bat-mah-drawing'); + const motorMahDrawnElement = $('.motors-bat-mah-drawn'); const rawDataTextElements = { - x: [], - y: [], - z: [], - rms: [] + x: [], + y: [], + z: [], + rms: [] }; $('.plot_control .x, .plot_control .y, .plot_control .z, .plot_control .rms').each(function () { @@ -373,7 +429,7 @@ TABS.motors.initialize = function (callback) { accelOffset[0] + FC.SENSOR_DATA.accelerometer[0], accelOffset[1] + FC.SENSOR_DATA.accelerometer[1], accelOffset[2] + FC.SENSOR_DATA.accelerometer[2], - ]; + ]; updateGraphHelperSize(accelHelpers); samplesAccel = addSampleToData(accelData, samplesAccel, accelWithOffset); @@ -421,7 +477,6 @@ TABS.motors.initialize = function (callback) { } }); - // set refresh speeds according to configuration saved in storage ConfigStorage.get(['motors_tab_sensor_settings', 'motors_tab_gyro_settings', 'motors_tab_accel_settings'], function (result) { if (result.motors_tab_sensor_settings) { @@ -440,12 +495,11 @@ TABS.motors.initialize = function (callback) { $('.tab-motors .sensor select:first').change(); }); - // Amperage function power_data_pull() { motorVoltage.text(i18n.getMessage('motorsVoltageValue', [FC.ANALOG.voltage])); - motor_mah_drawing_e.text(i18n.getMessage('motorsADrawingValue', [FC.ANALOG.amperage.toFixed(2)])); - motor_mah_drawn_e.text(i18n.getMessage('motorsmAhDrawnValue', [FC.ANALOG.mAhdrawn])); + motorMahDrawingElement.text(i18n.getMessage('motorsADrawingValue', [FC.ANALOG.amperage.toFixed(2)])); + motorMahDrawnElement.text(i18n.getMessage('motorsmAhDrawnValue', [FC.ANALOG.mAhdrawn])); } GUI.interval_add('motors_power_data_pull_slow', power_data_pull, 250, true); // 4 fps @@ -472,42 +526,206 @@ TABS.motors.initialize = function (callback) { neutral3d = (FC.MOTOR_3D_CONFIG.neutral > 1575 || FC.MOTOR_3D_CONFIG.neutral < 1425) ? 1500 : FC.MOTOR_3D_CONFIG.neutral; } - const motorsWrapper = $('.motors .bar-wrapper'), - servos_wrapper = $('.servos .bar-wrapper'); + const motorsWrapper = $('.motors .bar-wrapper'); for (let i = 0; i < 8; i++) { motorsWrapper.append(`\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ `); - - servos_wrapper.append('\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ - '); } $('div.sliders input').prop('min', rangeMin) .prop('max', rangeMax); $('div.values li:not(:last)').text(rangeMin); - // UI hooks + const featuresElement = $('.tab-motors .features'); + FC.FEATURE_CONFIG.features.generateElements(featuresElement); + + /* + * ESC protocol + */ + + const escProtocols = EscProtocols.GetAvailableProtocols(FC.CONFIG.apiVersion); + const escProtocolElement = $('select.escprotocol'); + + for (let j = 0; j < escProtocols.length; j++) { + escProtocolElement.append(``); + } + + const unsyncedPWMSwitchElement = $("input[id='unsyncedPWMSwitch']"); + const divUnsyncedPWMFreq = $('div.unsyncedpwmfreq'); + + unsyncedPWMSwitchElement.on("change", function () { + if ($(this).is(':checked')) { + divUnsyncedPWMFreq.show(); + } else { + divUnsyncedPWMFreq.hide(); + } + }); + + const dshotBidirElement = $('input[id="dshotBidir"]'); + + unsyncedPWMSwitchElement.prop('checked', FC.PID_ADVANCED_CONFIG.use_unsyncedPwm !== 0).trigger("change"); + $('input[name="unsyncedpwmfreq"]').val(FC.PID_ADVANCED_CONFIG.motor_pwm_rate); + $('input[name="digitalIdlePercent"]').val(FC.PID_ADVANCED_CONFIG.digitalIdlePercent); + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)) { + dshotBidirElement.prop('checked', FC.MOTOR_CONFIG.use_dshot_telemetry).trigger("change"); + + self.previousDshotBidir = FC.MOTOR_CONFIG.use_dshot_telemetry; + self.previousFilterDynQ = FC.FILTER_CONFIG.dyn_notch_q; + self.previousFilterDynWidth = FC.FILTER_CONFIG.dyn_notch_width_percent; + + dshotBidirElement.on("change", function () { + const value = $(this).prop('checked'); + const newValue = (value !== FC.MOTOR_CONFIG.use_dshot_telemetry) ? 'On' : 'Off'; + self.analyticsChanges['BidirectionalDshot'] = newValue; + FC.MOTOR_CONFIG.use_dshot_telemetry = value; + + FC.FILTER_CONFIG.dyn_notch_width_percent = self.previousFilterDynWidth; + FC.FILTER_CONFIG.dyn_notch_q = self.previousFilterDynQ; + + if (FC.FILTER_CONFIG.gyro_rpm_notch_harmonics !== 0) { // if rpm filter is active + if (value && !self.previousDshotBidir) { + FC.FILTER_CONFIG.dyn_notch_width_percent = FILTER_DEFAULT.dyn_notch_width_percent_rpm; + FC.FILTER_CONFIG.dyn_notch_q = FILTER_DEFAULT.dyn_notch_q_rpm; + } else if (!value && self.previousDshotBidir) { + FC.FILTER_CONFIG.dyn_notch_width_percent = FILTER_DEFAULT.dyn_notch_width_percent; + FC.FILTER_CONFIG.dyn_notch_q = FILTER_DEFAULT.dyn_notch_q; + } + } + + if (FC.FILTER_CONFIG.dyn_notch_width_percent !== self.previousFilterDynWidth) { + showDialogDynFiltersChange(); + } + }); + + $('input[name="motorPoles"]').val(FC.MOTOR_CONFIG.motor_poles); + } + + $('#escProtocolTooltip').toggle(semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_42)); + $('#escProtocolTooltipNoDSHOT1200').toggle(semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)); + + function updateVisibility() { + // Hide unused settings + const protocolName = $('select.escprotocol option:selected').text(); + const protocolConfigured = protocolName !== 'DISABLED'; + let digitalProtocol = false; + switch (protocolName) { + case 'DSHOT150': + case 'DSHOT300': + case 'DSHOT600': + case 'DSHOT1200': + case 'PROSHOT1000': + digitalProtocol = true; + + break; + default: + } + + const rpmFeaturesVisible = digitalProtocol && dshotBidirElement.is(':checked') || $("input[name='ESC_SENSOR']").is(':checked'); + + $('div.minthrottle').toggle(protocolConfigured && !digitalProtocol); + $('div.maxthrottle').toggle(protocolConfigured && !digitalProtocol); + $('div.mincommand').toggle(protocolConfigured && !digitalProtocol); + $('div.checkboxPwm').toggle(protocolConfigured && !digitalProtocol); + divUnsyncedPWMFreq.toggle(protocolConfigured && !digitalProtocol); + + $('div.digitalIdlePercent').toggle(protocolConfigured && digitalProtocol); + $('.escSensor').toggle(protocolConfigured && digitalProtocol); + + $('div.checkboxDshotBidir').toggle(protocolConfigured && semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42) && digitalProtocol); + $('div.motorPoles').toggle(protocolConfigured && rpmFeaturesVisible && semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)); + + $('.escMotorStop').toggle(protocolConfigured); + + $('#escProtocolDisabled').toggle(!protocolConfigured); + + //trigger change unsyncedPWMSwitch to show/hide Motor PWM freq input + unsyncedPWMSwitchElement.trigger("change"); + } + + escProtocolElement.val(FC.PID_ADVANCED_CONFIG.fast_pwm_protocol + 1); + escProtocolElement.on("change", function () { + const escProtocolValue = parseInt($(this).val()) - 1; + + let newValue = undefined; + if (escProtocolValue !== FC.PID_ADVANCED_CONFIG.fast_pwm_protocol) { + newValue = $(this).find('option:selected').text(); + } + self.analyticsChanges['EscProtocol'] = newValue; + + updateVisibility(); + }).trigger("change"); + + //trigger change dshotBidir and ESC_SENSOR to show/hide Motor Poles tab + dshotBidirElement.change(updateVisibility).trigger("change"); + $("input[name='ESC_SENSOR']").on("change", updateVisibility).trigger("change"); + + // fill throttle + $('input[name="minthrottle"]').val(FC.MOTOR_CONFIG.minthrottle); + $('input[name="maxthrottle"]').val(FC.MOTOR_CONFIG.maxthrottle); + $('input[name="mincommand"]').val(FC.MOTOR_CONFIG.mincommand); + + //fill 3D + $('.tab-motors ._3d').show(); + $('input[name="3ddeadbandlow"]').val(FC.MOTOR_3D_CONFIG.deadband3d_low); + $('input[name="3ddeadbandhigh"]').val(FC.MOTOR_3D_CONFIG.deadband3d_high); + $('input[name="3dneutral"]').val(FC.MOTOR_3D_CONFIG.neutral); + + /* + * UI hooks + */ + + function checkUpdate3dControls() { + if (FC.FEATURE_CONFIG.features.isEnabled('3D')) { + $('._3dSettings').show(); + } else { + $('._3dSettings').hide(); + } + } + + $('input.feature', featuresElement).on("change", function () { + const element = $(this); + + FC.FEATURE_CONFIG.features.updateData(element); + updateTabList(FC.FEATURE_CONFIG.features); + + switch (element.attr('name')) { + case 'MOTOR_STOP': + break; + + case '3D': + checkUpdate3dControls(); + break; + + default: + break; + } + }); + + $(featuresElement).filter('select').change(function () { + const element = $(this); + + FC.FEATURE_CONFIG.features.updateData(element); + updateTabList(FC.FEATURE_CONFIG.features); + + }); + + checkUpdate3dControls(); + + /* + * MOTOR TESTING + */ + function setSlidersDefault() { // change all values to default if (self.feature3DEnabled) { @@ -521,13 +739,15 @@ TABS.motors.initialize = function (callback) { if (isEnabled && !self.armed) { $('div.sliders input').slice(0, self.numberOfValidOutputs).prop('disabled', false); - // unlock master slider + // unlock master slider and hide tool-buttons $('div.sliders input:last').prop('disabled', false); + $('.tool-buttons').hide(); } else { setSlidersDefault(); - // disable sliders / min max + // disable sliders / min max and show tool-buttons $('div.sliders input').prop('disabled', true); + $('.tool-buttons').show(); } $('div.sliders input').trigger('input'); @@ -535,9 +755,25 @@ TABS.motors.initialize = function (callback) { setSlidersDefault(); - $('#motorsEnableTestMode').change(function () { - const enabled = $(this).is(':checked'); + // disables Motor Testing if settings are being changed (must save and reboot). + function disableMotorTest() { + self.isDirty = true; + motorsEnableTestModeElement.trigger("change"); + } + motorsEnableTestModeElement.change(function () { + let enabled = $(this).is(':checked'); + // prevent testing if dirty flag is set. + if (self.isDirty) { + // if enabled or trying to enable - Inform the user to save settings if silent flag is not set + if (enabled) { + const message = i18n.getMessage('motorsDialogSettingsChanged'); + showDialogSettingsChanged(message); + } + enabled = false; + // disable input + motorsEnableTestModeElement.prop('checked', false); + } setSlidersEnabled(enabled); $('div.sliders input').trigger('input'); @@ -596,7 +832,7 @@ TABS.motors.initialize = function (callback) { } if (motorsRunning) { - $('#motorsEnableTestMode').prop('checked', true).change(); + motorsEnableTestModeElement.prop('checked', true).change(); // motors are running adjust sliders to current values @@ -636,16 +872,12 @@ TABS.motors.initialize = function (callback) { function get_motor_telemetry_data() { if (FC.MOTOR_CONFIG.use_dshot_telemetry || FC.MOTOR_CONFIG.use_esc_sensor) { - MSP.send_message(MSPCodes.MSP_MOTOR_TELEMETRY, false, false, get_servo_data); + MSP.send_message(MSPCodes.MSP_MOTOR_TELEMETRY, false, false, update_ui); } else { - get_servo_data(); + update_ui(); } } - function get_servo_data() { - MSP.send_message(MSPCodes.MSP_SERVO, false, false, update_ui); - } - const fullBlockScale = rangeMax - rangeMin; function update_ui() { @@ -681,15 +913,13 @@ TABS.motors.initialize = function (callback) { rpmMotorValue = rpmMotorValue.toString().padStart(MAX_VALUE_SIZE); let telemetryText = i18n.getMessage('motorsRPM', {motorsRpmValue: rpmMotorValue}); - if (FC.MOTOR_CONFIG.use_dshot_telemetry) { let invalidPercent = FC.MOTOR_TELEMETRY_DATA.invalidPercent[i]; - let classError = (invalidPercent > MAX_INVALID_PERCENT) ? "warning" : ""; invalidPercent = (invalidPercent / 100).toFixed(2).toString().padStart(MAX_VALUE_SIZE); - telemetryText += "
"; + telemetryText += `
`; telemetryText += i18n.getMessage('motorsRPMError', {motorsErrorValue: invalidPercent}); telemetryText += ""; } @@ -697,40 +927,71 @@ TABS.motors.initialize = function (callback) { if (FC.MOTOR_CONFIG.use_esc_sensor) { let escTemperature = FC.MOTOR_TELEMETRY_DATA.temperature[i]; + escTemperature = escTemperature.toString().padStart(MAX_VALUE_SIZE); telemetryText += "
"; - escTemperature = escTemperature.toString().padStart(MAX_VALUE_SIZE); telemetryText += i18n.getMessage('motorsESCTemperature', {motorsESCTempValue: escTemperature}); } - $('.motor_testing .telemetry .motor-' + i).html(telemetryText); + $(`.motor_testing .telemetry .motor-${i}`).html(telemetryText); } } - // servo indicators are still using old (not flexible block scale), it will be changed in the future accordingly - for (let i = 0; i < FC.SERVO_DATA.length; i++) { - const data = FC.SERVO_DATA[i] - 1000, - marginTop = blockHeight - (data * (blockHeight / 1000)).clamp(0, blockHeight), - height = (data * (blockHeight / 1000)).clamp(0, blockHeight), - color = parseInt(data * 0.009); - - $(`.servo-${i} .label`, servos_wrapper).text(FC.SERVO_DATA[i]); - $(`.servo-${i} .indicator`, servos_wrapper).css({ - 'margin-top' : `${marginTop}px`, - 'height' : `${height}px`, - 'background-color' : `rgba(255,187,0,1${color})`, - }); - } //keep the following here so at least we get a visual cue of our motor setup update_arm_status(); if (previousArmState != self.armed) { console.log('arm state change detected'); - $('#motorsEnableTestMode').change(); + motorsEnableTestModeElement.change(); } } + $('a.save').on('click', function() { + // gather data that doesn't have automatic change event bound + FC.MOTOR_CONFIG.minthrottle = parseInt($('input[name="minthrottle"]').val()); + FC.MOTOR_CONFIG.maxthrottle = parseInt($('input[name="maxthrottle"]').val()); + FC.MOTOR_CONFIG.mincommand = parseInt($('input[name="mincommand"]').val()); + + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)) { + FC.MOTOR_CONFIG.motor_poles = parseInt($('input[name="motorPoles"]').val()); + } + + FC.MOTOR_3D_CONFIG.deadband3d_low = parseInt($('input[name="3ddeadbandlow"]').val()); + FC.MOTOR_3D_CONFIG.deadband3d_high = parseInt($('input[name="3ddeadbandhigh"]').val()); + FC.MOTOR_3D_CONFIG.neutral = parseInt($('input[name="3dneutral"]').val()); + + FC.PID_ADVANCED_CONFIG.fast_pwm_protocol = parseInt(escProtocolElement.val() - 1); + FC.PID_ADVANCED_CONFIG.use_unsyncedPwm = unsyncedPWMSwitchElement.is(':checked') ? 1 : 0; + FC.PID_ADVANCED_CONFIG.motor_pwm_rate = parseInt($('input[name="unsyncedpwmfreq"]').val()); + FC.PID_ADVANCED_CONFIG.digitalIdlePercent = parseFloat($('input[name="digitalIdlePercent"]').val()); + + if (semver.gte(FC.CONFIG.apiVersion, "1.25.0") && semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_41)) { + FC.PID_ADVANCED_CONFIG.gyroUse32kHz = $('input[id="gyroUse32kHz"]').is(':checked') ? 1 : 0; + } + + Promise + .resolve(true) + .then(() => { return MSP.promise(MSPCodes.MSP_SET_FEATURE_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_FEATURE_CONFIG)); }) + .then(() => { return MSP.promise(MSPCodes.MSP_SET_MIXER_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_MIXER_CONFIG)); }) + .then(() => { return MSP.promise(MSPCodes.MSP_SET_MOTOR_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_MOTOR_CONFIG)); }) + .then(() => { return MSP.promise(MSPCodes.MSP_SET_MOTOR_3D_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_MOTOR_3D_CONFIG)); }) + .then(() => { return MSP.promise(MSPCodes.MSP_SET_ADVANCED_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_ADVANCED_CONFIG)); }) + .then(() => { return MSP.promise(MSPCodes.MSP_SET_ARMING_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_ARMING_CONFIG)); }) + .then(() => { return (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)) ? MSP.promise(MSPCodes.MSP_SET_FILTER_CONFIG, + mspHelper.crunch(MSPCodes.MSP_SET_FILTER_CONFIG)) : true; }) + .then(() => { return MSP.promise(MSPCodes.MSP_EEPROM_WRITE); }) + .then(() => { + GUI.log(i18n.getMessage('configurationEepromSaved')); + MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false); + reinitialiseConnection(self); + }); + + analytics.sendChangeEvents(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, self.analyticsChanges); + self.analyticsChanges = {}; + self.isDirty = false; + }); + // enable Status and Motor data pulling GUI.interval_add('motor_and_status_pull', get_status, 50, true); @@ -750,7 +1011,20 @@ TABS.motors.initialize = function (callback) { GUI.content_ready(callback); } - GUI.content_ready(callback); + GUI.content_ready(callback); + } + + function showDialogSettingsChanged(message) { + const dialogSettingsChanged = $('#dialog-settings-changed')[0]; + + $('#dialog-settings-changed-content').html(message); + + if (!dialogSettingsChanged.hasAttribute('open')) { + dialogSettingsChanged.showModal(); + $('#dialog-settings-changed-confirmbtn').click(function() { + dialogSettingsChanged.close(); + }); + } } function setup_motor_output_reordering_dialog(callbackFunction, zeroThrottleValue) diff --git a/src/js/tabs/servos.js b/src/js/tabs/servos.js index a13d9a69486..9bbc2382fdf 100644 --- a/src/js/tabs/servos.js +++ b/src/js/tabs/servos.js @@ -41,49 +41,45 @@ TABS.servos.initialize = function (callback) { let servoCheckbox = ''; let servoHeader = ''; for (let i = 0; i < FC.RC.active_channels-4; i++) { - servoHeader = servoHeader + '\ - A' + (i+1) + '\ - '; + servoHeader += `A${(i+1)}`; } - servoHeader = servoHeader + ''; + servoHeader += ''; for (let i = 0; i < FC.RC.active_channels; i++) { - servoCheckbox = servoCheckbox + '\ - \ - '; + servoCheckbox += ``; } $('div.tab-servos table.fields tr.main').append(servoHeader); + /* + * function: void process_servos(string, object) + */ + function process_servos(name, obj) { $('div.supported_wrapper').show(); - $('div.tab-servos table.fields').append('\ - \ - ' + name + '\ - \ - \ - \ - ' + servoCheckbox + '\ - \ - \ - \ - '); + const subElement = `${name}`; + element += `${subElement}${FC.SERVO_CONFIG[obj].middle}" />`; + element += `${subElement}${FC.SERVO_CONFIG[obj].min}" />`; + element += `${subElement}${FC.SERVO_CONFIG[obj].max}" />`; + element += `${servoCheckbox}`; + + $('div.tab-servos table.fields').append(element); if (FC.SERVO_CONFIG[obj].indexOfChannelToForward >= 0) { $('div.tab-servos table.fields tr:last td.channel input').eq(FC.SERVO_CONFIG[obj].indexOfChannelToForward).prop('checked', true); } // adding select box and generating options - $('div.tab-servos table.fields tr:last td.direction').append('\ - \ - '); + $('div.tab-servos table.fields tr:last td.direction').append(''); const select = $('div.tab-servos table.fields tr:last td.direction select'); for (let i = 100; i > -101; i--) { - select.append(''); + select.append(``); } // select current rate @@ -101,12 +97,15 @@ TABS.servos.initialize = function (callback) { }); } + /* + * function: void servos_update(boolean) + */ + function servos_update(save_configuration_to_eeprom) { $('div.tab-servos table.fields tr:not(".main")').each(function () { const info = $(this).data('info'); - - const selection = $('.channel input', this); + let channelIndex = parseInt(selection.index(selection.filter(':checked'))); if (channelIndex === -1) { channelIndex = undefined; @@ -145,11 +144,66 @@ TABS.servos.initialize = function (callback) { // drop previous table $('div.tab-servos table.fields tr:not(:first)').remove(); + // let's reflect CLI here to number servo's 1-8 instead of 0-7 for (let servoIndex = 0; servoIndex < 8; servoIndex++) { - process_servos('Servo ' + servoIndex, servoIndex); + process_servos(`Servo ${servoIndex+1}`, servoIndex); + } + + const servosWrapper = $('.servos .bar-wrapper'); + + for (let i = 0; i < 8; i++) { + servosWrapper.append(`\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ + `); + } + + const rangeMin = 1000; + const rangeMax = 2000; + + $('div.values li:not(:last)').text(rangeMin); + + /* + * void test_update(void); + */ + + function test_update() { + + const blockHeight = 100; + const fullBlockScale = rangeMax - rangeMin; + + for (let i = 0; i < FC.SERVO_DATA.length; i++) { + + const servoValue = FC.SERVO_DATA[i]; + const barHeight = servoValue - rangeMin; + const marginTop = blockHeight - (barHeight * (blockHeight / fullBlockScale)).clamp(0, blockHeight); + const height = (barHeight * (blockHeight / fullBlockScale)).clamp(0, blockHeight); + const color = parseInt(barHeight * 0.009); + + $(`.servo-${i} .label`, servosWrapper).text(servoValue); + $(`.servo-${i} .indicator`, servosWrapper).css({ + 'margin-top' : `${marginTop}px`, + 'height' : `${height}px`, + 'background-color' : `rgba(255,187,0,1${color})`, + }); + } + } + + function get_servo_data() { + MSP.send_message(MSPCodes.MSP_SERVO, false, false, test_update); } // UI hooks for dynamically generated elements + GUI.interval_add('servo_data_pull_and_test_update', get_servo_data, 50); + $('table.directions select, table.directions input, table.fields select, table.fields input').change(function () { if ($('div.live input').is(':checked')) { // apply small delay as there seems to be some funky update business going wrong diff --git a/src/tabs/configuration.html b/src/tabs/configuration.html index cce43d6e965..693a17e08ff 100644 --- a/src/tabs/configuration.html +++ b/src/tabs/configuration.html @@ -1,99 +1,134 @@
-
- -
-
-

-
+
+ +
+
+

+
-
-
- -
-
-
-
-
-
-
-
- +
+ +
+ + +
+
+
+
+
+
+
+

-
- +
+ +
+
+
+ + +
-
-
-
-
-
- +
+ + +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
- -
-
-
+ - -
-
-
-
-
-
-
-

+ + +
+
+
+
+
+
+ +
-
-
- +
+
+

- -
-
-
- - - +
-
- - -
+
-
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
+
+
+ + + +
+
+
+
+
+
+
+ + + + + + + + + + + +
+ + +
@@ -105,7 +140,9 @@
-
+
+ +
@@ -118,240 +155,9 @@
-
-
-
- -
-
-
-
-
-
-
-

-
-
- -
-
-
- -
- -
-
- -
-
-
-
- -
- -
-
- -
- - - - -
- - - - -
- -
-
- -
- -
-
-
- -
-
-
- -
-
-
- -
-
- -
-
- -
-
-
-
- - -
-
-
-
-
-
-
-
-
-
- -
- -
-
- -
+ -
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
-
-
- -
-
- -
-
- -
-
-
-
-
-
-
-
-
-
- -
-
- -
-
-
+
@@ -369,405 +175,308 @@
-
-
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-

-
- - -
-
-
-

-
- - -
-
-
-
-
- -
-
-
-
-
-
-
- - - - - - - - - - - -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-

+ + + +
+
+
+
+
+
+
+

+
+ + + + + + + + + + + +
- - - - - - - - - - - -
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - -
-
-
- -
-
- -
-
- + + + +
+
+
+
+
+
+ + + + + + + + + + + +
+
+
+
+

+
+ +
+ + +
+
+ + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+ + +
+
-
+ +
- -
-
-
-
-
-
- - - - - - - - - - - -
-
-
-
-

+
+ + +
+
+
+
+
+
+
+
+
+
+
-
- - +
+
+
-
- - + +
+
+
-
-
- -
- +
+
+
+
-
-
- -
- +
+
-
-
- -
- -
+
+
-
-
- -
- -
+
+
-
- - +
+
+
+ +
+
+ +
+
+
-
-
-
-
-
- -
-
+ + +
-
+
- - - - - - - - - - - -
-
- -
-
- -
-
- -
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - -
-
- -
-
- -
-
- -
-
- -
-
-
- + +
+ +
+
+
+
+
+
+ + + + + + + + + +
-
-
-
-
- -
-
-
-
-
-
-
- - - - - - - - - -
-
-
- -
- -
-
-
-
- -
- -
-
- - - - -
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - -
-
-
-
-
-
-
diff --git a/src/tabs/motors.html b/src/tabs/motors.html index 15414d3d98a..c6a77d50b03 100644 --- a/src/tabs/motors.html +++ b/src/tabs/motors.html @@ -1,119 +1,293 @@ -
+
Motors
-
-
-
- -
- - - - - - - +
+
+
-
-
-
-
- -
-
- -
-
- -
- -
-
-
-
-
- -
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+ +
+ +
+
+
+
+ -
-
-
-
-
- -
-
+ +
+
+
+
+
+
+
+

+
+
+ +
+
+
+ +
+ +
+
+ +
-
-
- X: -
-
- 0 -
-
-
-
- Y: -
-
- 0 -
-
-
-
- Z: -
-
- 0 -
+ + + + + + + +
+
+
+ +
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
-
-
- RMS: -
-
- 0 -
+ + + +
+
+
+
+
+
+ + + + + + + + + + + +
+
+
+ +
+
+ +
+
+ +
+
+
+
-
+
+ +
-
- - - - - -
+
-
-
-
-
+ +
+
+ + +
+
+ + + + + + + + +
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+
+ X: +
+
+ 0 +
+
+
+
+ Y: +
+
+ 0 +
+
+
+
+ Z: +
+
+ 0 +
+
+
+
+ RMS: +
+
+ 0 +
+
+
+
+
+ +
+ + + +
+ +
+
+ +
-
    +
    • 1
    • 2
    • 3
    • @@ -125,21 +299,8 @@
-
-
-
    -
  • 8
  • -
  • 7
  • -
  • 6
  • -
  • 5
  • -
  • 4
  • -
  • 3
  • -
  • 2
  • -
  • 1
  • -
-
-
+
@@ -185,29 +346,54 @@
-
+
+
+ +
+
-
- -
-
+
+
+ + +
+ +
+ +
-
- + +
+ + +
+
+
+ +
-
- -
-
+ +
+
+
+
+ +
- -
-
+ +
+
+
+ +
+
+ +
diff --git a/src/tabs/servos.html b/src/tabs/servos.html index 1db9bbcbd74..cbe24b1d23f 100644 --- a/src/tabs/servos.html +++ b/src/tabs/servos.html @@ -4,33 +4,64 @@
-
-
-
- - - - - - - - - - - -
CH1CH2CH3CH4
+
+
+
+
+ + + + + + + + + + + +
CH1CH2CH3CH4
+
+
+
+ +
-
- +
+

-
-

+ +
+ +
+
+
+
+
+
+
    +
  • 8
  • +
  • 7
  • +
  • 6
  • +
  • 5
  • +
  • 4
  • +
  • 3
  • +
  • 2
  • +
  • 1
  • +
+
+
+
+
+
+
+
+