diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 91e33056..741ea82a 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -672,6 +672,9 @@ "receiverButtonRefresh": { "message": "Refresh" }, + "receiverButtonSticks": { + "message": "Control sticks" + }, "receiverDataRefreshed": { "message": "RC Tuning data refreshed" }, @@ -1146,5 +1149,41 @@ }, "ledStripEepromSaved": { "message": "EEPROM saved" + }, + "controlAxisRoll": { + "message": "Roll" + }, + "controlAxisPitch": { + "message": "Pitch" + }, + "controlAxisYaw": { + "message": "Yaw" + }, + "controlAxisThrottle": { + "message": "Throttle" + }, + "controlAxisAux1": { + "message": "AUX 1" + }, + "controlAxisAux2": { + "message": "AUX 2" + }, + "controlAxisAux3": { + "message": "AUX 3" + }, + "controlAxisAux4": { + "message": "AUX 4" + }, + "controlAxisAux5": { + "message": "AUX 5" + }, + "controlAxisAux6": { + "message": "AUX 6" + }, + "controlAxisAux7": { + "message": "AUX 7" + }, + "controlAxisAux8": { + "message": "AUX 8" } -} +} \ No newline at end of file diff --git a/js/msp.js b/js/msp.js index 49676381..e2232272 100644 --- a/js/msp.js +++ b/js/msp.js @@ -1130,6 +1130,22 @@ MSP.crunch = function (code) { return buffer; }; +/** + * Set raw Rx values over MSP protocol. + * + * Channels is an array of 16-bit unsigned integer channel values to be sent. 8 channels is probably the maximum. + */ +MSP.setRawRx = function(channels) { + var buffer = []; + + for (var i = 0; i < channels.length; i++) { + buffer.push(specificByte(channels[i], 0)); + buffer.push(specificByte(channels[i], 1)); + } + + MSP.send_message(MSP_codes.MSP_SET_RAW_RC, buffer, false); +} + /** * Send a request to read a block of data from the dataflash at the given address and pass that address and a dataview * of the returned data to the given callback (or null for the data if an error occured). diff --git a/tabs/receiver.css b/tabs/receiver.css index fe1a3c4f..9c7c6903 100644 --- a/tabs/receiver.css +++ b/tabs/receiver.css @@ -299,6 +299,7 @@ position: absolute; bottom: 10px; } +.tab-receiver .sticks, .tab-receiver .update, .tab-receiver .refresh { display: block; @@ -317,6 +318,7 @@ border: 1px solid silver; background-color: #ececec; } +.tab-receiver .sticks, .tab-receiver .refresh { margin-right: 10px; } diff --git a/tabs/receiver.html b/tabs/receiver.html index f562050c..f20c8a98 100644 --- a/tabs/receiver.html +++ b/tabs/receiver.html @@ -86,5 +86,6 @@
diff --git a/tabs/receiver.js b/tabs/receiver.js index 0efb5f18..9e08e321 100644 --- a/tabs/receiver.js +++ b/tabs/receiver.js @@ -18,7 +18,12 @@ TABS.receiver.initialize = function (callback) { } function get_rc_map() { - MSP.send_message(MSP_codes.MSP_RX_MAP, false, false, load_html); + MSP.send_message(MSP_codes.MSP_RX_MAP, false, false, load_config); + } + + // Fetch features so we can check if RX_MSP is enabled: + function load_config() { + MSP.send_message(MSP_codes.MSP_BF_CONFIG, false, false, load_html); } function load_html() { @@ -52,7 +57,12 @@ TABS.receiver.initialize = function (callback) { }); // generate bars - var bar_names = ['Roll', 'Pitch', 'Yaw', 'Throttle'], + var bar_names = [ + chrome.i18n.getMessage('controlAxisRoll'), + chrome.i18n.getMessage('controlAxisPitch'), + chrome.i18n.getMessage('controlAxisYaw'), + chrome.i18n.getMessage('controlAxisThrottle') + ], bar_container = $('.tab-receiver .bars'), aux_index = 1; @@ -61,7 +71,7 @@ TABS.receiver.initialize = function (callback) { if (i < bar_names.length) { name = bar_names[i]; } else { - name = 'AUX ' + aux_index++; + name = chrome.i18n.getMessage("controlAxisAux" + (aux_index++)); } bar_container.append('\ @@ -302,6 +312,27 @@ TABS.receiver.initialize = function (callback) { MSP.send_message(MSP_codes.MSP_SET_RC_TUNING, MSP.crunch(MSP_codes.MSP_SET_RC_TUNING), false, save_rc_map); }); + + $("a.sticks").click(function() { + var + windowWidth = 370, + windowHeight = 510; + + chrome.app.window.create("/tabs/receiver_msp.html", { + id: "receiver_msp", + innerBounds: { + minWidth: windowWidth, minHeight: windowHeight, + width: windowWidth, height: windowHeight, + maxWidth: windowWidth, maxHeight: windowHeight + } + }, function(createdWindow) { + // Give the window a callback it can use to access our MSP object to send to CF + createdWindow.contentWindow.setRawRx = MSP.setRawRx; + }); + }); + + // Only show the MSP control sticks if the MSP Rx feature is enabled + $("a.sticks").toggle(bit_check(BF_CONFIG.features, 14 /* RX_MSP */)); $('select[name="rx_refresh_rate"]').change(function () { var plot_update_rate = parseInt($(this).val(), 10); diff --git a/tabs/receiver_msp.css b/tabs/receiver_msp.css new file mode 100644 index 00000000..29ecf158 --- /dev/null +++ b/tabs/receiver_msp.css @@ -0,0 +1,109 @@ +body { + font-family: 'Segoe UI', Tahoma, sans-serif; + font-size: 12px; + color: #303030; + margin: 10px; +} + +.control-gimbals { + /* A generous padding around the window edges ensures that we continue to receive mousemove events (since + * cursor stays in the window for longer) + */ + padding:25px; + padding-bottom:0; + text-align:center; +} + +.control-gimbal { + position:relative; + width:120px; + height:120px; + background-color:#eee; + margin-left:1em; + margin-right:1em; + margin-bottom:2em; + display:inline-block; + border-radius:5px; + + cursor:pointer; +} + +.crosshair { + display:block; + position:absolute; + background-color:#ddd; +} + +.crosshair-vert { + width:1px; + height:100%; + left:50%; +} + +.crosshair-horz { + height:1px; + width:100%; + top:50%; +} + +.gimbal-label { + display:block; + position:absolute; + text-align:center; +} + +.gimbal-label-horz { + top:calc(100% + 0.5em); + width:100%; +} + +.gimbal-label-vert { + transform:rotate(-90deg); + /*transform-origin:0% 100%;*/ + top:calc(50% - 0.5em); + width:100%; + left:calc(-50% - 1em); +} + +.control-stick { + background-color:rgba(255,50,50,1.0); + width:20px; + height:20px; + margin-left:-10px; + margin-top:-10px; + display:block; + border-radius:100%; + position:absolute; + + cursor:pointer; +} + +.control-slider { + margin:20px; +} + +.tooltip { + position: absolute; + left: calc(100% + 24px); + top: 0; +} + +.control-slider .slider { + margin-left:50px; + margin-right:50px; +} + +.slider-label { + position:absolute; + text-align:right; + width:40px; + left:-65px; +} + +.button-enable { + padding:0.5em; + font-size:110%; + margin-left:auto; + margin-right:auto; + display:block; +} \ No newline at end of file diff --git a/tabs/receiver_msp.html b/tabs/receiver_msp.html new file mode 100644 index 00000000..fb1a5482 --- /dev/null +++ b/tabs/receiver_msp.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + ++ These sticks allow Cleanflight to be armed and tested without a transmitter or receiver being + present. However, this feature is not intended for flight and propellers must not be attached. +
++ This feature does not guarantee reliable control of your craft. Serious injury is likely to + result if propellers are left on. +
+ +