From dc21a8cd50b7c1ceeeb5c233b4593eb388303dfe Mon Sep 17 00:00:00 2001 From: Buzz Date: Sat, 28 Nov 2020 13:23:36 +1000 Subject: [PATCH 1/2] upgrade mavlink-enabled Node backend with newer Node parser. seratch and replace .name to ._name and .header to ._header --- assets/mavFlightMode.js | 4 +- local_modules/README.md | 6 + local_modules/jspack/.npmignore | 19 + local_modules/jspack/LICENSE | 26 + local_modules/jspack/README.md | 147 + local_modules/jspack/jspack.js | 890 +++ local_modules/jspack/package.json | 64 + local_modules/jspack/test/int64.js | 456 ++ local_modules/long/LICENSE | 202 + local_modules/long/README.md | 246 + local_modules/long/index.js | 1 + local_modules/long/long | 1 + local_modules/long/package.json | 64 + local_modules/long/src/long.js | 1325 ++++ mav_v2.js | 7141 ++++++++++++++----- mav_v2.js.prev | 10188 +++++++++++++++++++++++++++ mavudp_to_ws_server.js | 54 +- update_mavlink.sh | 1 + 18 files changed, 18921 insertions(+), 1914 deletions(-) create mode 100644 local_modules/README.md create mode 100644 local_modules/jspack/.npmignore create mode 100644 local_modules/jspack/LICENSE create mode 100644 local_modules/jspack/README.md create mode 100644 local_modules/jspack/jspack.js create mode 100644 local_modules/jspack/package.json create mode 100644 local_modules/jspack/test/int64.js create mode 100644 local_modules/long/LICENSE create mode 100644 local_modules/long/README.md create mode 100644 local_modules/long/index.js create mode 120000 local_modules/long/long create mode 100644 local_modules/long/package.json create mode 100644 local_modules/long/src/long.js create mode 100644 mav_v2.js.prev create mode 100755 update_mavlink.sh diff --git a/assets/mavFlightMode.js b/assets/mavFlightMode.js index 111a195..085c177 100644 --- a/assets/mavFlightMode.js +++ b/assets/mavFlightMode.js @@ -86,9 +86,9 @@ MavFlightMode.prototype.attachHandlers = function(sysid,mavlink,mavlinkParser,st // else ignore data for other sysids than the one we are interested in. - if ( heartbeat.header.srcSystem != sysid ) return; + if ( heartbeat._header.srcSystem != sysid ) return; - //console.log('zzzzzzzzzzzzzzzzzzzz'+heartbeat.header.srcSystem); + //console.log('zzzzzzzzzzzzzzzzzzzz'+heartbeat._header.srcSystem); //console.log('xxxxxxxxxxxxxxxxxxxx'+sysid); //console.log(`custom mode: ${heartbeat.custom_mode}`); //console.log(`base mode: ${heartbeat.base_mode}`); diff --git a/local_modules/README.md b/local_modules/README.md new file mode 100644 index 0000000..76643a5 --- /dev/null +++ b/local_modules/README.md @@ -0,0 +1,6 @@ +This folder is a locally modified copy of some Node/npm packages 'jspack' and 'long'. we have copied them here and tweaked them to be compatible with our needs, please see their respective README.md file for their original info, which we have not changed. + +This README.md serves to make you aware that these two packages as stored here in the 'jspack' and 'long' folders ARE MODIFIED from the originals. +By placing this statement here, and putting a notice in long.js as well, we feel are in compliance with the LICENSE file of 'long' , wich requires us to tell you they are modified. + +We have included their original license files, in compliance with them, as both license/s permit distribution of derived works in source and/or binary form. diff --git a/local_modules/jspack/.npmignore b/local_modules/jspack/.npmignore new file mode 100644 index 0000000..be1ea81 --- /dev/null +++ b/local_modules/jspack/.npmignore @@ -0,0 +1,19 @@ +lib-cov +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz +*.pyc + +pids +logs +results + +npm-debug.log +node_modules + +**~ +**.swp diff --git a/local_modules/jspack/LICENSE b/local_modules/jspack/LICENSE new file mode 100644 index 0000000..d646dd7 --- /dev/null +++ b/local_modules/jspack/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2008, Fair Oaks Labs, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors may be + used to endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/local_modules/jspack/README.md b/local_modules/jspack/README.md new file mode 100644 index 0000000..2a6e6ef --- /dev/null +++ b/local_modules/jspack/README.md @@ -0,0 +1,147 @@ +jspack - library to pack primitives to octet arrays +==================================================== + +[![Build status](https://travis-ci.org/birchroad/node-jspack.svg?branch=master)](https://travis-ci.org/birchroad/node-jspack) + +## Disclaimer +The jspack module and documentation are essentially ports of the +Python struct module and documentation, with such changes as were necessary. The port was originaly made by Fair Oaks Labs, Inc. and published at http://code.google.com/p/jspack/ +If any Python people are miffed that their documentation got ripped off, let me know, +and I'll gladly revise them. + +This module performs conversions between JavaScript values and C structs +represented as octet arrays (i.e. JavaScript arrays of integral numbers +between 0 and 255, inclusive). It uses format strings (explained below) as +compact descriptions of the layout of the C structs and the intended conversion +to/from JavaScript values. This can be used to handle binary data stored in +files, or received from network connections or other sources. + +## Install + npm install jspack + +## Reference + +The module defines the following functions: + +### Unpack(fmt, a, p) +Return an array containing values unpacked from the octet array a, +beginning at position p, according to the supplied format string. If there +are more octets in a than required by the format string, the excess is +ignored. If there are fewer octets than required, Unpack() will return +undefined. If no value is supplied for the p argument, zero is assumed. + +### PackTo(fmt, a, p, values) +Pack and store the values array into the supplied octet array a, beginning +at position p. If there are more values supplied than are specified in the +format string, the excess is ignored. If there are fewer values supplied, +PackTo() will return false. If there is insufficient space in a to store +the packed values, PackTo() will return false. On success, PackTo() returns +the a argument. If any value is of an inappropriate type, the results are +undefined. + +### Pack(fmt, values) +Return an octet array containing the packed values array. If there are +more values supplied than are specified in the format string, the excess is +ignored. If there are fewer values supplied, Pack() will return false. If +any value is of an inappropriate type, the results are undefined. + +### CalcLength(fmt) +Return the number of octets required to store the given format string. + + +## Formats +Format characters have the following meanings; the conversion between C and +JavaScript values should be obvious given their types: + + Format | C Type | JavaScript Type | Size (octets) | Notes + ------------------------------------------------------------------- + A | char[] | Array | Length | (1) + x | pad byte | N/A | 1 | + c | char | string (length 1) | 1 | (2) + b | signed char | number | 1 | (3) + B | unsigned char | number | 1 | (3) + h | signed short | number | 2 | (3) + H | unsigned short | number | 2 | (3) + i | signed int | number | 4 | (3) + I | unsigned int | number | 4 | (3) + l | signed long | number | 4 | (3) + L | unsigned long | number | 4 | (3) + q | signed long | number | 8 | (6) + Q | unsigned long | number | 8 | (6) + s | char[] | string | Length | (2) + f | float | number | 4 | (4) + d | double | number | 8 | (5) + +*Notes:* + + **(1)** The "A" code simply returns a slice of the source octet array. This is + primarily useful when a data structure contains bytes which are subject to + multiple intepretations (e.g. unions), and the data structure is being + decoded in multiple passes. + + **(2)** The "c" and "s" codes handle strings with codepoints between 0 and 255, + inclusive. The data are not bounds-checked, so strings containing characters + with codepoints outside this range will encode to "octet" arrays that contain + values outside the range of an octet. Furthermore, since these codes decode + octet arrays by assuming the octets represent UNICODE codepoints, they may + not "correctly" decode bytes in the range 128-255, since that range is subject + to multiple interpretations. Caveat coder! + + **(3)** The 8 "integer" codes clip their encoded values to the minima and maxmima + of their respective types: If you invoke Struct.Pack('b', [-129]), for + instance, the result will be [128], which is the octet encoding of -128, + which is the minima of a signed char. Similarly, Struct.Pack('h', [-32769]) + returns [128, 0]. Fractions are truncated. + + **(4)** Since JavaScript doesn't natively support 32-bit floats, whenever a float + is stored, the source JavaScript number must be rounded. This module applies + correct rounding during this process. Numbers with magnitude greater than or + equal to 2^128-2^103 round to either positive or negative Infinity. The + rounding algorithm assumes that JavsScript is using exactly 64 bits of + floating point precision; 128-bit floating point will result in subtle errors. + + **(5)** This module assumes that JavaScript is using 64 bits of floating point + precision, so the "d" code performs no rounding. 128-bit floating point will + cause the "d" code to simply truncate significands to 52 bits. + + **(6)** Since 64bit longs cannot be represented by numbers JavaScript, this version of + jspack will process longs as arrays in the form: ```[lowBits, hightBits]```. The + decoded long array contains a third element, the unsigned flag, which is ```false``` for signed + and ```true``` for unsigned values. + This representation is similar to what [Long.js](https://github.com/dcodeIO/Long.js), and + therefore the [Google Closure Libaray](https://github.com/google/closure-library), uses. + See [test/int64.js](test/int64.js) for examples how to work with Long.js. + +A format character may be preceded by an integral repeat count. For example, +the format string "4h" means exactly the same thing as "hhhh". + +Whitespace characters between formats are ignored; a count and its format must +not be separated by whitespace, however. + +For the "A" format character, the count is interpreted as the size of the +array, not a repeat count as for the other format characters; for example, "10A" +means a single 10-octet array. When packing, the Array is truncated or padded +with 0 bytes as appropriate to make it conform to the specified length. When +unpacking, the resulting Array always has exactly the specified number of bytes. +As a special case, "0A" means a single, empty Array. + +For the "s" format character, the count is interpreted as the size of the +string, not a repeat count as for the other format characters; for example, +"10s" means a single 10-byte string, while "10c" means 10 characters. When +packing, the string is truncated or padded with 0 bytes as appropriate to make +it conform to the specified length. When unpacking, the resulting string always +has exactly the specified number of bytes. As a special case, "0s" means a +single, empty string (while "0c" means 0 characters). + + +By default, C numbers are represented in network (or big-endian) byte order. +Alternatively, the first character of the format string can be used to indicate +byte order of the packed data, according to the following table: + + Character | Byte Order + ---------------------------------- + < | little-endian + > | big-endian + ! | network (= big-endian) + +If the first character is not one of these, "!" is assumed. diff --git a/local_modules/jspack/jspack.js b/local_modules/jspack/jspack.js new file mode 100644 index 0000000..02e3768 --- /dev/null +++ b/local_modules/jspack/jspack.js @@ -0,0 +1,890 @@ +/** + * @license + + Copyright © 2008 Fair Oaks Labs, Inc. + All rights reserved. + + This file is Modified from the original, by buzz 2020: + - ran thru http://www.jsnice.org/ and manually renamed the variables to be clearer + - added optionally enabled debugging/verbose/printfs throughout + - bugfixes and integration so it now passes our mavlink.js testsuite/s + - please see README.md in the upper level folder. +*/ +'use strict'; + +var Long = require('long'); + +let DEBUG = false; + +/** + * @return {undefined} + */ +function JSPack() { + var el; + /** @type {boolean} */ + var booleanIsBigEndian = false; + var m = this; + + + /** + * @param {!Object} octet_array_a + * @param {number} offset_p + * @param {number} len + * @return {?} + */ + //Raw byte arrays + // m._DeArray = function(octet_array_a, offset_p, len) { + // if (DEBUG) console.log("zzz1"); + // return [octet_array_a.slice(offset_p, offset_p + len)]; + //}; + + /** + * @param {!Array} to_octet_array_a + * @param {number} offset_p + * @param {number} len + * @param {!NodeList} from_array_v + * @return {undefined} + */ + // m._EnArray = function(to_octet_array_a, offset_p, len, from_array_v) { + // if (DEBUG) console.log("zzz2"); + /** @type {number} */ + // var i = 0; + // for (; i < len; to_octet_array_a[offset_p + i] = from_array_v[i] ? from_array_v[i] : 0, i++) { + // } + //}; + + + /** + * @param {!Object} octet_array_a + * @param {number} offset_p + * @return {?} + */ + // ASCII characters + m._DeChar = function(octet_array_a, offset_p) { + if (DEBUG) console.log("zzz3"); + return String.fromCharCode(octet_array_a[offset_p]); + }; + /** + * @param {!Array} to_octet_array_a + * @param {number} offset_p + * @param {string} from_str_array_v + * @return {undefined} + */ + // m._EnChar = function(to_octet_array_a, offset_p, from_str_array_v) { + // if (DEBUG) console.log("zzz4"); + // /** @type {number} */ + // to_octet_array_a[offset_p] = from_str_array_v.charCodeAt(0); + // }; + + + /** + * @param {!Object} octet_array_a + * @param {number} offset_p + * @return {?} + */ + //Little-endian (un)signed N-byte integers + m._DeInt = function(octet_array_a, offset_p) { + if (DEBUG) console.log("zzz5"); + /** @type {number} */ + var lsb = booleanIsBigEndian ? el.len - 1 : 0; + /** @type {number} */ + var nsb = booleanIsBigEndian ? -1 : 1; + /** @type {number} */ + var stop = lsb + nsb * el.len; + var rv; + var i; + var f; + /** @type {number} */ + rv = 0; + /** @type {number} */ + i = lsb; + /** @type {number} */ + f = 1; + for (; i != stop; rv = rv + octet_array_a[offset_p + i] * f, i = i + nsb, f = f * 256) { + } + if (el.bSigned && rv & Math.pow(2, el.len * 8 - 1)) { + /** @type {number} */ + rv = rv - Math.pow(2, el.len * 8); + } + return rv; + }; + + + /** + * @param {!Array} octet_array_a + * @param {number} offset_p + * @param {number} val + * @return {undefined} + */ + m._EnInt = function(octet_array_a, offset_p, val) { + if (DEBUG) console.log("chunk-from: "+val); + /** @type {number} */ + var lsb = booleanIsBigEndian ? el.len - 1 : 0; + /** @type {number} */ + var nsb = booleanIsBigEndian ? -1 : 1; + /** @type {number} */ + var stop = lsb + nsb * el.len; + var i; + // range limit: + if (val < el.min ) { + val = el.min; + console.log("value limited to MIN:"+val); + } + if (val > el.max ) { + val = el.max; + console.log("value limited to MAX:"+val); + } + /** @type {number} */ + i = lsb; + if (DEBUG) console.log("booleanIsBigEndian:"+booleanIsBigEndian); + if (DEBUG) console.log("el.len:"+el.len); + if (DEBUG) console.log("lsb:"+lsb); + if (DEBUG) console.log("nsb:"+nsb); + if (DEBUG) console.log("i:"+i); + if (DEBUG) console.log("stop:"+stop); + for (; i != stop; ) { + + var to = JSON.stringify(val&255); + if (DEBUG) console.log("chunk as bytes: "+to); + + octet_array_a[offset_p + i] = val & 255; + i = i + nsb; + val = val >> 8; + + + } + }; + + + /** + * @param {!Object} octet_array_a + * @param {number} offset_p + * @param {number} len + * @return {?} + */ + // ASCII character strings + m._DeString = function(octet_array_a, offset_p, len) { + if (DEBUG) console.log("zzz7"); + /** @type {!Array} */ + var retval = new Array(len); + /** @type {number} */ + var i = 0; + for (; i < len; retval[i] = String.fromCharCode(octet_array_a[offset_p + i]), i++) { + } + return retval.join(""); + }; + /** + * @param {!Array} octet_array_a + * @param {number} offset_p + * @param {number} len + * @param {string} strval + * @return {undefined} + */ + m._EnString = function(octet_array_a, offset_p, len, strval) { + if (DEBUG) console.log("zzz8"); + var t; + /** @type {number} */ + if ( DEBUG ) console.log("strencode before: "+octet_array_a+"\np:"+offset_p+" len:"+len+" strval:"+strval) + var i = 0; + //if (DEBUG) console.log("strval:"+strval); +//console.trace("Here I am!") + + // we all strings to be passed in as a string of characters, or a an array or buffer of them is ok too + + if (typeof strval.charCodeAt === "function") { + for (; i < len; octet_array_a[offset_p + i] = (t = strval.charCodeAt(i)) ? t : 0, i++) { + if ( t > 255 ) console.log("ERROR ERROR ERROR ERROR ERROR ERROR - It seems u passed unicode/utf-8/etc to jspack, not 8 bit ascii. please use .toString('binary'); not .toString();"); + } + if ( DEBUG ) console.log("strencode from CHAR-string."); + + } else if (Array.isArray(strval)) { + for (; i < len; octet_array_a[offset_p + i] = (t = strval[i]) ? t : 0, i++) { + // referring directly to 't' inside this loop is bad, seems delayed by an iteration, but strval[i] is ok. + if ( strval[i] > 255 ) console.log("ERROR ERROR ERROR ERROR ERROR ERROR - It seems u passed unicode/utf-8/etc, or array data with values > 255, to jspack, not 8 bit ascii.\n(bad Array data)"+strval[i]); + } + if ( DEBUG ) console.log("strencode from ARRAY."); + + } else if (Buffer.isBuffer(strval)) { + for (; i < len; octet_array_a[offset_p + i] = (t = strval[i]) ? t : 0, i++) { + if ( strval[i] > 255 ) console.log("ERROR ERROR ERROR ERROR ERROR ERROR - It seems u passed unicode/utf-8/etc to jspack, not 8 bit ascii. \n(bad Buffer data)"+strval[i]); + } + if ( DEBUG ) console.log("strencode from Buffer."); + + } else { + console.log("ERROR encoding string _EnString: array:"+octet_array_a+" p:"+offset_p+" len:"+len+" strval:"+JSON.stringify(strval)) +} + }; + + + /** + * @param {!Object} octet_array_a + * @param {number} offset_p + * @return {?} + */ + // Little-endian N-bit IEEE 754 floating point + m._De754 = function(octet_array_a, offset_p) { + if (DEBUG) console.log("zzz9"); + var bool_s; + var exponent; + var mantissa; + var i; + var d; + var nBits; + var mantissaLen; + var exponentLen; + var eBias; + var eMax; + mantissaLen = el.mLen; + /** @type {number} */ + exponentLen = el.len * 8 - el.mLen - 1; + /** @type {number} */ + eMax = (1 << exponentLen) - 1; + /** @type {number} */ + eBias = eMax >> 1; + /** @type {number} */ + i = booleanIsBigEndian ? 0 : el.len - 1; + /** @type {number} */ + d = booleanIsBigEndian ? 1 : -1; + bool_s = octet_array_a[offset_p + i]; + /** @type {number} */ + i = i + d; + /** @type {number} */ + nBits = -7; + /** @type {number} */ + exponent = bool_s & (1 << -nBits) - 1; + /** @type {number} */ + bool_s = bool_s >> -nBits; + /** @type {number} */ + nBits = nBits + exponentLen; + for (; nBits > 0; exponent = exponent * 256 + octet_array_a[offset_p + i], i = i + d, nBits = nBits - 8) { + } + /** @type {number} */ + mantissa = exponent & (1 << -nBits) - 1; + /** @type {number} */ + exponent = exponent >> -nBits; + nBits = nBits + mantissaLen; + for (; nBits > 0; mantissa = mantissa * 256 + octet_array_a[offset_p + i], i = i + d, nBits = nBits - 8) { + } + switch(exponent) { + case 0: + /** @type {number} */ + // Zero, or denormalized number + exponent = 1 - eBias; + break; + case eMax: + // NaN, or +/-Infinity + return mantissa ? NaN : (bool_s ? -1 : 1) * Infinity; + default: + // Normalized number + mantissa = mantissa + Math.pow(2, mantissaLen); + /** @type {number} */ + exponent = exponent - eBias; + break; + } + return (bool_s ? -1 : 1) * mantissa * Math.pow(2, exponent - mantissaLen); + }; + /** + * @param {!Array} octet_array_a + * @param {number} offset_p + * @param {number} v + * @return {undefined} + */ + m._En754 = function(octet_array_a, offset_p, v) { + if (DEBUG) console.log("zzz_10"); + var bool_s; + var exponent; + var mantissa; + var i; + var d; + var c; + var mantissaLen; + var exponentLen; + var eBias; + var eMax; + mantissaLen = el.mLen; + /** @type {number} */ + exponentLen = el.len * 8 - el.mLen - 1; + /** @type {number} */ + eMax = (1 << exponentLen) - 1; + /** @type {number} */ + eBias = eMax >> 1; + /** @type {number} */ + bool_s = v < 0 ? 1 : 0; + /** @type {number} */ + v = Math.abs(v); + if (isNaN(v) || v == Infinity) { + /** @type {number} */ + mantissa = isNaN(v) ? 1 : 0; + /** @type {number} */ + exponent = eMax; + } else { + /** @type {number} */ + exponent = Math.floor(Math.log(v) / Math.LN2);// Calculate log2 of the value + if (v * (c = Math.pow(2, -exponent)) < 1) { // Math.log() isn't 100% reliable + exponent--; + /** @type {number} */ + c = c * 2; + } + // Round by adding 1/2 the significand's LSD + if (exponent + eBias >= 1) { + /** @type {number} */ + v = v + el.rt / c; // Normalized: mLen significand digits + } else { + /** @type {number} */ + v = v + el.rt * Math.pow(2, 1 - eBias);// Denormalized: <= mLen significand digits + } + if (v * c >= 2) { + exponent++; + /** @type {number} */ + c = c / 2; // Rounding can increment the exponent + } + if (exponent + eBias >= eMax) { + // Overflow + /** @type {number} */ + mantissa = 0; + /** @type {number} */ + exponent = eMax; + } else { + if (exponent + eBias >= 1) { + // Normalized - term order matters, as Math.pow(2, 52-e) and v*Math.pow(2, 52) can overflow + /** @type {number} */ + mantissa = (v * c - 1) * Math.pow(2, mantissaLen); + /** @type {number} */ + exponent = exponent + eBias; + } else { + // Denormalized - also catches the '0' case, somewhat by chance + /** @type {number} */ + mantissa = v * Math.pow(2, eBias - 1) * Math.pow(2, mantissaLen); + /** @type {number} */ + exponent = 0; + } + } + } + /** @type {number} */ + i = booleanIsBigEndian ? el.len - 1 : 0; + /** @type {number} */ + d = booleanIsBigEndian ? -1 : 1; + for (; mantissaLen >= 8; octet_array_a[offset_p + i] = mantissa & 255, i = i + d, mantissa = mantissa / 256, mantissaLen = mantissaLen - 8) { + } + /** @type {number} */ + exponent = exponent << mantissaLen | mantissa; + exponentLen = exponentLen + mantissaLen; + for (; exponentLen > 0; octet_array_a[offset_p + i] = exponent & 255, i = i + d, exponent = exponent / 256, exponentLen = exponentLen - 8) { + } + octet_array_a[offset_p + i - d] |= bool_s * 128; + }; + + + /** + * @param {!Object} octet_array_a + * @param {number} offset_p + * @return {?} + */ + // Convert int64 to array with 3 elements: [lowBits, highBits, unsignedFlag] + // '>>>' trick to convert signed 32bit int to unsigned int (because << always results in a signed 32bit int) + m._DeInt64 = function(octet_array_a, offset_p) { + if (DEBUG) console.log("zzz_11"); + /** @type {number} */ + var lsb = booleanIsBigEndian ? 0 : 7; + /** @type {number} */ + var nsb = booleanIsBigEndian ? 1 : -1; + /** @type {number} */ + var stop = lsb + nsb * 8; + /** @type {!Array} */ + var nextIdLookup = [0, 0, !el.bSigned]; + var i; + var f; + var indexLookupKey; + /** @type {number} */ + i = lsb; + /** @type {number} */ + indexLookupKey = 1; + /** @type {number} */ + f = 0; + for (; i != stop; nextIdLookup[indexLookupKey] = (nextIdLookup[indexLookupKey] << 8 >>> 0) + octet_array_a[offset_p + i], i = i + nsb, f++, indexLookupKey = f < 4 ? 1 : 0) { + + if ( DEBUG ) console.log("jsPacking int64:"+octet_array_a[offset_p + i]); + + } + return nextIdLookup; + }; + /** + * @param {!Array} octet_array_a + * @param {number} offset_p + * @param {!Object} v + * @return {undefined} + */ + m._EnInt64 = function(octet_array_a, offset_p, v) { + + if (v.length != 2) { //todo put this error back + console.log("ERROR ERROR: jspack needs an array of at least length TWO to pack an int64 "+v+' len:'+v.length); + } +// if (DEBUG) console.log("zzz_12 v:"+v); + /** @type {number} */ + var lsb = booleanIsBigEndian ? 0 : 7; + /** @type {number} */ + var nsb = booleanIsBigEndian ? 1 : -1; + /** @type {number} */ + var stop = lsb + nsb * 8; + var i; + var f; + var j; + var shift; + /** @type {number} */ + i = lsb; + /** @type {number} */ + j = 1; + /** @type {number} */ + f = 0; + /** @type {number} */ + shift = 24; + + for (; i != stop; octet_array_a[offset_p + i] = v[j] >> shift & 255, i = i + nsb, f++, j = f < 4 ? 1 : 0, shift = 24 - 8 * (f % 4)) { + var x = v[j] >> shift & 255 ; + var vj = v[j]; + + if ( DEBUG ) console.log('js qqqq vj:'+vj+' j:'+j+' x:'+x+' a:'+octet_array_a+' i:'+i+" offset_p:"+offset_p+" v:"+v); + } + }; + + + + // Class data + /** @type {string} */ + m._sPattern = "(\\d+)?([AxcbBhHsfdiIlLqQ])"; + + m._lenLut = {'A':1, 'x':1, 'c':1, 'b':1, 'B':1, 'h':2, 'H':2, 's':1, 'f':4, 'd':8, 'i':4, 'I':4, 'l':4, 'L':4, 'q':8, 'Q':8}; + + m._elLookUpTable = { 'A': {en:m._EnArray, de:m._DeArray}, + 's': {en:m._EnString, de:m._DeString}, + 'c': {en:m._EnChar, de:m._DeChar}, + 'b': {en:m._EnInt, de:m._DeInt, len:1, bSigned:true, min:-Math.pow(2, 7), max:Math.pow(2, 7)-1}, + 'B': {en:m._EnInt, de:m._DeInt, len:1, bSigned:false, min:0, max:Math.pow(2, 8)-1}, + 'h': {en:m._EnInt, de:m._DeInt, len:2, bSigned:true, min:-Math.pow(2, 15), max:Math.pow(2, 15)-1}, + 'H': {en:m._EnInt, de:m._DeInt, len:2, bSigned:false, min:0, max:Math.pow(2, 16)-1}, + 'i': {en:m._EnInt, de:m._DeInt, len:4, bSigned:true, min:-Math.pow(2, 31), max:Math.pow(2, 31)-1}, + 'I': {en:m._EnInt, de:m._DeInt, len:4, bSigned:false, min:0, max:Math.pow(2, 32)-1}, + 'l': {en:m._EnInt, de:m._DeInt, len:4, bSigned:true, min:-Math.pow(2, 31), max:Math.pow(2, 31)-1}, + 'L': {en:m._EnInt, de:m._DeInt, len:4, bSigned:false, min:0, max:Math.pow(2, 32)-1}, + 'f': {en:m._En754, de:m._De754, len:4, mLen:23, rt:Math.pow(2, -24)-Math.pow(2, -77)}, + 'd': {en:m._En754, de:m._De754, len:8, mLen:52, rt:0}, + 'q': {en:m._EnInt64, de:m._DeInt64, bSigned:true, len:8 }, // 64bit fields need 8 bytes.. + 'Q': {en:m._EnInt64, de:m._DeInt64, bSigned:false, len:8 }}; // quirk of longs is they come in with a length of 2 in an array + + + /** + * @param {number} num_elements_n + * @param {number} size_s + * @param {!Object} octet_array_a + * @param {number} offset_p + * @return {?} + */ + // Unpack a series of n elements of size s from array a at offset p with fxn + m._UnpackSeries = function(num_elements_n, size_s, octet_array_a, offset_p) { + if (DEBUG) console.log("zzz_13"); + var fxn = el.de; + /** @type {!Array} */ + var rv = []; + /** @type {number} */ + var o = 0; + for (; o < num_elements_n; rv.push(fxn(octet_array_a, offset_p + o * size_s)), o++) { + } + return rv; + }; + /** + * @param {number} num_elements_n + * @param {number} size_s + * @param {!Array} to_octet_array_a + * @param {number} array_a_offset_p + * @param {(Array|NodeList|null)} from_array_v + * @param {number} array_v_offset_i + * @return {undefined} + */ + // Pack a series of n elements of size s from array v at offset i to array a at offset p with fxn + + m._PackSeries = function(num_elements_n, size_s, to_octet_array_a, array_a_offset_p, from_array_v, array_v_offset_i) { + if (DEBUG) console.log("pack-series: "); + + + if ( DEBUG ) console.log('js before 0:'+0+' num_elements_n:'+num_elements_n+' size_s:'+size_s+' to_a:'+to_octet_array_a+' i:'+array_v_offset_i+" offset_p:"+array_a_offset_p+" v:"+from_array_v); + var fxn = el.en; + /** @type {number} */ + var o = 0; + for (; o < num_elements_n; o++) { + //if (DEBUG) console.log("14 called fxn with o:"+o); + var z = from_array_v[array_v_offset_i + o]; + var to = JSON.stringify(z); + var too = JSON.stringify(from_array_v); + if (DEBUG) console.log('js pre-ffff z:'+z+' to:'+to+' too:'+too+''); + // handle flattened arrays - non-array things dont have a .length + try { + if (z.length == undefined ) { + //from_array_v = [ from_array_v ] ; + if (DEBUG) console.log('Z FIX'); + }} catch (e){} + var z = from_array_v[array_v_offset_i + o]; + var to = JSON.stringify(z); + var too = JSON.stringify(from_array_v); + + // if we only have one thing to back and its got an 8 byte target len ( its a 64bit long), and length of source array is 2 ( low and high bits ) + // we treat it as a singular thing... we use this for Q type, which gets passed in as [lowBits, hightBits] + if (( num_elements_n == 1 ) && (size_s == 8) && (from_array_v.length == 2) ) { + z = from_array_v; + if (DEBUG) console.log("js handling Q 64bit array"); + } + + + if (DEBUG) console.log('js partial z:'+z+' to:'+to+' too:'+too+' num_elements_n:'+num_elements_n+' size_s:'+size_s+' to_a:'+to_octet_array_a+' v_offset_i:'+array_v_offset_i+" a_offset_p:"+array_a_offset_p+" from_v:"+from_array_v); + + fxn(to_octet_array_a, array_a_offset_p + o * size_s, z); + + } + if (DEBUG) console.log('js after to_a:'+to_octet_array_a); + }; + + + /** + * @param {string} fmt + * @param {!Object} octet_array_a + * @param {number} offset_p + * @return {?} + */ + // Unpack the octet array a, beginning at offset p, according to the fmt string + m.Unpack = function(fmt, octet_array_a, offset_p) { + if (DEBUG) console.log("zzz_15"); + /** @type {boolean} */ + // Set the private bBE flag based on the format string - assume big-endianness + booleanIsBigEndian = fmt.charAt(0) != "<"; + /** @type {number} */ + offset_p = offset_p ? offset_p : 0; + /** @type {!RegExp} */ + var re = new RegExp(this._sPattern, "g"); + var re_match; + var repeat_count_n; + var element_size_s; + /** @type {!Array} */ + var rv = []; + + //loop over chars in the format string with regex due to optional digits + for (; re_match = re.exec(fmt);) { + /** @type {number} */ + repeat_count_n = re_match[1] == undefined || re_match[1] == "" ? 1 : parseInt(re_match[1]); + element_size_s = this._lenLut[re_match[2]]; + if (offset_p + repeat_count_n * element_size_s > octet_array_a.length) { + return undefined; + } + switch(re_match[2]) { + case "A": + case "s": + rv.push(this._elLookUpTable[re_match[2]].de(octet_array_a, offset_p, repeat_count_n)); + break; + case "c": + case "b": + case "B": + case "h": + case "H": + case "i": + case "I": + case "l": + case "L": + case "f": + case "d": + case "q": + case "Q": + el = this._elLookUpTable[re_match[2]]; + + //rv.push(this._UnpackSeries(repeat_count_n, element_size_s, octet_array_a, offset_p)); + + // unpack arrays to an actual array type within the field array result: + // https://github.com/AndreasAntener/node-jspack/commit/4f16680101303a6b4a1b0deba8cf7d20fc68213e + if (repeat_count_n > 1) { + // Field is array, unpack into separate array and push as such + var arr = []; + arr.push(this._UnpackSeries(repeat_count_n, element_size_s, octet_array_a, offset_p)); + rv.push(arr); + } else { + rv.push(this._UnpackSeries(repeat_count_n, element_size_s, octet_array_a, offset_p)); + } + + break; + } + /** @type {number} */ + offset_p = offset_p + repeat_count_n * element_size_s; + } + return Array.prototype.concat.apply([], rv); + }; + + + // cross check the list of input data matches the size of bytes we'll be assembling + // this is a slightly tweaked implementation of the previous 'PackTo' commented out below. + // it has a more-consistent approach to input and output arrays, paying particular attention to Q,q, long, etc + m.WouldPack = function(fmt, octet_array_a, offset_p, values) { + //if (DEBUG) console.log("zzz_16 fmt:"+JSON.stringify(fmt)+" values:"+JSON.stringify(values)); + // @type {boolean} / + // Set the private bBE flag based on the format string - assume big-endianness + booleanIsBigEndian = fmt.charAt(0) != "<"; + // @type {!RegExp} / + var re = new RegExp(this._sPattern, "g"); + + var m; + var n; + var s; + var values_i = 0; // current index into the values[] + + var j; + for (; m = re.exec(fmt);) { + + // leading optional prefix num or 1 + n = m[1] == undefined || m[1] == "" ? 1 : parseInt(m[1]); + + s = this._lenLut[m[2]]; + + + if (DEBUG) console.log("character: "+m[2]+" how many(n)?: "+n); + el = this._elLookUpTable[m[2]]; + + //if (DEBUG) console.log("using lookup table:"+JSON.stringify(el)); + var bytes_consumed_per_element = el["len"]; + bytes_consumed_per_element = bytes_consumed_per_element == undefined ? 1 : bytes_consumed_per_element ; // undefined means 1 + if (DEBUG) console.log("bytes_consumed_per_element:"+JSON.stringify(bytes_consumed_per_element)); + if (DEBUG) console.log("current_values_idx:"+JSON.stringify(values_i) +" values:"+JSON.stringify(values[values_i]) ) ; + + + // do per-case behaviours 'A' , 's' and 'x' are special, everything else gets the same + switch(m[2]) { + //------------------------------------------ + case "A": + case "s": + if (values_i + 1 > values.length) { + console.log("JSPACK-ERROR: values_i + 1 > values.length values_i:"+values_i+" values.length:"+values.length); + //return false; + } + if (DEBUG) console.log("all values:"+JSON.stringify(values)); + this._elLookUpTable[m[2]].en(octet_array_a, offset_p, n, values[values_i]); + // @type {number} / + values_i = values_i + 1; + break; + //------------------------------------------ + case "x": + // @type {number} / + j = 0; + for (; j < n; j++) { + // @type {number} / + octet_array_a[offset_p + j] = 0; + } + break; + //------------------------------------------ + // everything else + default: + + // if n > 1 , ie its multiple occurances of a 'thing' + if (n > 1 ) { + + // if we were handed an array at this idx, we need the array to be the same length as n + if (Array.isArray(values[values_i])) { + + // Value series is array, iterate through that, only increment by 1 + if ((values_i + 1) > values.length) { + if (DEBUG) console.log("JSPACK-ERROR: value series is array but (values_i + 1) > values.length. i:"+values_i+" values.length:"+values.length); + //return false; + } + if (DEBUG) console.log("(dst IS array) (source IS array)"); + this._PackSeries(n, s, octet_array_a, offset_p, values[values_i], 0); + values_i += 1; + } + else { + if (DEBUG) console.log("ERROR: (dst IS array) (source is not array)"); + } + } + + // if n == 1, it just one of a thing + if (n == 1 ) { + + // type Q can have the source as an array when there is only 1 of them. + if (Array.isArray(values[values_i]) ) { + + if (( m[2] == 'Q' ) || ( m[2] == 'q' ) ) { + this._PackSeries(n, s, octet_array_a, offset_p, values[values_i], 0); + values_i += 1; + } + if (DEBUG) console.log("(dst is not array) (source IS array)"); + + } else { + if ((values_i + n ) > values.length) { + if (DEBUG) console.log("JSPACK-ERROR: value series NOT array but (values_i + n ) > values.length. i:"+values_i+" n:"+n+" values.length:"+values.length+" values:"+JSON.stringify(values)); + //return false; + } + if (DEBUG) console.log("(dst is not array) (source is not array)"); + this._PackSeries(n, s, octet_array_a, offset_p, values, values_i); + values_i += n; + } + } + + if (DEBUG) console.log(""); + break; + //------------------------------------------ + } + + offset_p = offset_p + n * s; + + } + if (DEBUG) console.log("wouldpack completed, result array_a is:"+JSON.stringify(octet_array_a)); + return octet_array_a + } + + + + /** + * @param {string} fmt + * @param {!Array} octet_array_a + * @param {number} offset_p + * @param {!NodeList} values + * @return {?} + */ +/* + // Pack the supplied values into the octet array a, beginning at offset p, according to the fmt string + m.PackTo = function(fmt, octet_array_a, offset_p, values) { + if (DEBUG) console.log("zzz_16 fmt:"+JSON.stringify(fmt)+" values:"+JSON.stringify(values)); + // @type {boolean} / + // Set the private bBE flag based on the format string - assume big-endianness + booleanIsBigEndian = fmt.charAt(0) != "<"; + // @type {!RegExp} / + var re = new RegExp(this._sPattern, "g"); + var m; + var n; + var s; + // @type {number} / + var i = 0; + var j; + for (; m = re.exec(fmt);) { + // @type {number} / + n = m[1] == undefined || m[1] == "" ? 1 : parseInt(m[1]); + s = this._lenLut[m[2]]; + if (offset_p + n * s > octet_array_a.length) { + console.log("JSPACK-ERROR: offset_p + n * s > octet_array_a.length offset_p:"+offset_p+" n:"+n+" s:"+s+" octet_array_a.length:"+octet_array_a.length+" octet_array_a:"+JSON.stringify(octet_array_a)); + return false; + } + if (DEBUG) console.log("\n---------------------------------------------\n"); + if (DEBUG) console.log("handling format specifier:"+m[2]+" how many:"+n); + switch(m[2]) { + case "A": + case "s": + if (i + 1 > values.length) { + console.log("JSPACK-ERROR: i + 1 > values.length i:"+i+" values.length:"+values.length); + return false; + } + if (DEBUG) console.log("zzz_16A values:"+JSON.stringify(values)); + this._elLookUpTable[m[2]].en(octet_array_a, offset_p, n, values[i]); + // @type {number} / + i = i + 1; + break; + case "c": + case "b": + case "B": + case "h": + case "H": + case "i": + case "I": + case "l": + case "L": + case "f": + case "d": + case "q": + case "Q": + if (DEBUG) console.log("16 blerg"); + el = this._elLookUpTable[m[2]]; + if (DEBUG) console.log("using lookup table:"+JSON.stringify(el)); + //if (i + n > values.length) { return false; } + //this._PackSeries(n, s, octet_array_a, offset_p, values, i); + //i = i + n; + //added support for packing value series when they are supplied as arrays within the values array + // https://github.com/AndreasAntener/node-jspack/commit/8de80d20aa06dea15527b3073c6c8631abda0f17 + if (n > 1 && Array.isArray(values[i])) { + // Value series is array, iterate through that, only increment by 1 + if ((i + 1) > values.length) { + console.log("JSPACK-ERROR: value series is array but (i + 1) > values.length. i:"+i+" values.length:"+values.length); + return false; + } + if (DEBUG) console.log("zzz_16 option 1 (source is array)"); + this._PackSeries(n, s, octet_array_a, offset_p, values[i], 0); + i += 1; + } else { + if ((i + n) > values.length) { + console.log("JSPACK-ERROR: value series NOT array but (i + n) > values.length. i:"+i+" n:"+n+" values.length:"+values.length+" values:"+JSON.stringify(values)); + //return false; + } + if (DEBUG) console.log("zzz_16 option 2 (source is not array)"); + this._PackSeries(n, s, octet_array_a, offset_p, values, i); + i += n; + } + + if (DEBUG) console.log("end case"); + break; + case "x": + // @type {number} / + j = 0; + for (; j < n; j++) { + // @type {number} / + octet_array_a[offset_p + j] = 0; + } + break; + } + // @type {number} / + offset_p = offset_p + n * s; + } + console.log("pack completed, result array_a is:"+JSON.stringify(octet_array_a)); + return octet_array_a; + }; + */ + + /** + * @param {string} fmt + * @param {(Node|NodeList|null|string)} values + * @return {?} + */ + // Pack the supplied values into a new octet array, according to the fmt string + m.Pack = function(fmt, values) { + if (DEBUG) console.log("\n\n------------------------------------------------------------------------------------------------------------\n\n"); + if (DEBUG) console.log("initial unpacked values:"+JSON.stringify(values)); + if (DEBUG) console.log("initial format string:"+JSON.stringify(fmt)); + if (DEBUG) console.log("\n\nwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww\n\n"); + return this.WouldPack(fmt, new Array(this.CalcLength(fmt)), 0, values); + //if (DEBUG) console.log("\n\nmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm\n\n"); + // return this.PackTo(fmt, new Array(this.CalcLength(fmt)), 0, values); + }; + + /** + * @param {string} fmt + * @param {(Node|NodeList|null|string)} values + * @return {?} + */ + // Pack the supplied values into a new octet array, according to the fmt string + m.oldPack = function(fmt, values) { + if (DEBUG) console.log("\n\n------------------------------------------------------------------------------------------------------------\n\n"); + if (DEBUG) console.log("initial unpacked values:"+JSON.stringify(values)); + if (DEBUG) console.log("initial format string:"+JSON.stringify(fmt)); + return this.PackTo(fmt, new Array(this.CalcLength(fmt)), 0, values); + }; + + /** + * @param {string} fmt + * @return {?} + */ + // Determine the number of bytes represented by the format string + m.CalcLength = function(fmt) { + + /** @type {!RegExp} */ + var re = new RegExp(this._sPattern, "g"); + var m; + /** @type {number} */ + var value = 0; + for (; m = re.exec(fmt);) { + /** @type {number} */ + value = value + (m[1] == undefined || m[1] == "" ? 1 : parseInt(m[1])) * this._lenLut[m[2]]; + } + if (DEBUG) console.log("number of bytes in format string?: "+value+"\n"); + return value; + }; +} +exports.jspack = new JSPack; + diff --git a/local_modules/jspack/package.json b/local_modules/jspack/package.json new file mode 100644 index 0000000..1233368 --- /dev/null +++ b/local_modules/jspack/package.json @@ -0,0 +1,64 @@ +{ + "_from": "jspack@0.0.4", + "_id": "jspack@0.0.4", + "_inBundle": false, + "_integrity": "sha1-Mt01x/3LPjRWwY+7fvntC8YjgXc=", + "_location": "/jspack", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": false, + "raw": "jspack@0.0.4", + "name": "jspack", + "escapedName": "jspack", + "rawSpec": "0.0.4", + "saveSpec": null, + "fetchSpec": "0.0.4" + }, + "_requiredBy": [ + "#USER", + "/" + ], + "_resolved": "local_modules/jspack", + "_shasum": "32dd35c7fdcb3e3456c18fbb7ef9ed0bc6238177", + "_spec": "jspack@0.0.4", + "_where": "/home/buzz/GCS/mavlink/pymavlink/generator/javascript", + "author": { + "name": "https://github.com/pgriess" + }, + "bugs": { + "url": "https://github.com/birchroad/node-jspack/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "JavaScript library to pack primitives to octet arrays, including int64 support, packaged for NodeJS.", + "devDependencies": { + "long": "", + "mocha": "", + "should": "", + "sinon": "" + }, + "homepage": "https://github.com/birchroad/node-jspack", + "main": "./jspack.js", + "maintainers": [ + { + "name": "Peter Magnusson", + "email": "peter@birchroad.net", + "url": "http://github.com/birchroad/node-jspack" + }, + { + "name": "Andreas Antener", + "url": "https://github.com/AndreasAntener/node-jspack" + } + ], + "name": "jspack", + "repository": { + "type": "git", + "url": "git://github.com/birchroad/node-jspack.git" + }, + "scripts": { + "pretest": "npm install", + "test": "mocha test" + }, + "version": "0.0.4" +} diff --git a/local_modules/jspack/test/int64.js b/local_modules/jspack/test/int64.js new file mode 100644 index 0000000..b24617e --- /dev/null +++ b/local_modules/jspack/test/int64.js @@ -0,0 +1,456 @@ +// This file is MODIFIED from the original, by buzz 2020, please see README.md in the upper level folder for more details. +var should = require('should'); +var jspack = require('../jspack.js').jspack; +var Long = require('long'); + +describe('Test long integration (examples):', function() { + + // Demonstrating the use together with Long.js (https://github.com/dcodeIO/Long.js) + // + // Packing a long requires the input of a 2 part array containing the [low, high] bits + // of the specific long value. + // Unpacking a long results in a 3 part array containing [low, high, unsigned] bits and flag. + // The decoded value can be applied directly to Long.fromBits() + // + // Test number u 228290380562207 (BE: 0x00, 0x00, 0xcf, 0xa0, 0xff, 0x09, 0xff, 0x1f) + // (LE: 0x1f, 0xff, 0x09, 0xff, 0xa0, 0xcf, 0x00, 0x00) + // Test number s -228290380562207 (BE: 0xff, 0xff, 0x30, 0x5f, 0x00, 0xf6, 0x00, 0xe1) + // (LE: 0xe1, 0x00, 0xf6, 0x00, 0x5f, 0x30, 0xff, 0xff) + + it('pack Q', function() { + var buf = jspack.Pack('>Q', [[0xffe1ffff, 0xffa0]]); + buf.should.be.eql([0x00, 0x00, 0xff, 0xa0, 0xff, 0xe1, 0xff, 0xff]); + }); + + it('unpack Q', function() { + var buf = jspack.Unpack('>Q', [0x00, 0x00, 0xff, 0xa0, 0xff, 0xe1, 0xff, 0xff]); + buf.length.should.be.eql(1); + buf[0].length.should.be.eql(3); + buf[0][0].should.be.eql(0xffe1ffff); + buf[0][1].should.be.eql(0xffa0); + buf[0][2].should.be.true; + }); + + // Test lower-case q as well. This only test the matching of the caracter and the unsigned bit, + // the parsing is the same as for upper-case Q (since we don't actually convert to a number). + it('pack >q (signed)', function() { + var buf = jspack.Pack('>q', [[0xffe1ffff, 0xffa0]]); + buf.should.be.eql([0x00, 0x00, 0xff, 0xa0, 0xff, 0xe1, 0xff, 0xff]); + }); + + it('unpack >> 0).toString(2); + y = ("00000000000000000000000000000000" + x).slice(-32) + y1 = y.substring(0,8); + y2 = y.substring(8,16); + y3 = y.substring(16,24); + y4 = y.substring(24,32); + return [y,y1,y2,y3,y4]; +} +function dec2bin_ws(dec) { + var str = dec2bin(dec); + var bb = str.slice(1); //1-4 skipping zero + var bbj = bb.join(' '); + return bbj; +} + +describe('ASCII Boundary tests:', function() { + + it('pack <4s correctly over the ascii 127->128->129 boundary', function() { // should work in range 0-255 if u use 'binary' encoding + + this.format = '<4s'; + + this.ascii_bytes = new Buffer.from([ 126, 127, 128, 129]).toString('binary'); // 'binary' encoding is important here, as without it values above 128 are treated as unicode. + var buf = jspack.Pack(this.format, [ this.ascii_bytes]); + body = [ 0x7e, 0x7f, 0x80, 0x81]; // expected result + buf.should.be.eql(body); + + }); + + it('long Q buzz', function() { // should work in range 0-255 if u use 'binary' encoding + +//from aoa_ssa + + this.format = '> 8) & 0xFF), this.msgId>>16]; + + this.msgId = 130; + + var v1 = ((this.msgId & 0xFF) << 8) | ((this.msgId >> 8) & 0xFF); + var v2 = this.msgId>>16; + + v1.should.be.eql(33280); + v2.should.be.eql(0); + + var orderedfields = [253,13,0,0,40,11,10,33280,0]; + + console.log("------------------------------------------------------------------------\nmavheader:"+JSON.stringify(orderedfields)); + var hdr = jspack.Pack('BBBBBBBHB',orderedfields); + + buf = [0xfd, 0x0d, 0x00, 0x00, 0x28, 0x0b, 0x0a, 0x82, 0x00, 0x00]; + + buf.should.be.eql(hdr); + }); + +}); + +describe('Q Boundary tests:', function() { + + it('unpack >Q full', function() { + var buf = jspack.Unpack('>Q', [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); + buf.length.should.be.eql(1); + buf[0].length.should.be.eql(3); + buf[0][0].should.be.eql(0xffffffff); + buf[0][1].should.be.eql(0xffffffff); + buf[0][2].should.be.true; + }); + + it('pack >Q full', function() { + var buf = jspack.Pack('>Q', [[0xffffffff, 0xffffffff]]); + buf.should.be.eql([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); + }); + + it('unpack Q zero', function() { + var buf = jspack.Unpack('>Q', [0, 0, 0, 0, 0, 0, 0, 0]); + buf.length.should.be.eql(1); + buf[0].length.should.be.eql(3); + buf[0][0].should.be.eql(0); + buf[0][1].should.be.eql(0); + buf[0][2].should.be.true; + }); + + it('pack >Q zero', function() { + var buf = jspack.Pack('>Q', [[0, 0]]); + buf.should.be.eql([0, 0, 0, 0, 0, 0, 0, 0]); + }); + + it('unpack Q one', function() { + var buf = jspack.Unpack('>Q', [1, 1, 1, 1, 1, 1, 1, 1]); + buf.length.should.be.eql(1); + buf[0].length.should.be.eql(3); + buf[0][0].should.be.eql(0x01010101); + buf[0][1].should.be.eql(0x01010101); + buf[0][2].should.be.true; + }); + + it('pack >Q one', function() { + var buf = jspack.Pack('>Q', [[0x01010101, 0x01010101]]); + buf.should.be.eql([1, 1, 1, 1, 1, 1, 1, 1]); + }); + + it('unpack Q 0xfe', function() { + var buf = jspack.Unpack('>Q', [0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe]); + buf.length.should.be.eql(1); + buf[0].length.should.be.eql(3); + buf[0][0].should.be.eql(0xfefefefe); + buf[0][1].should.be.eql(0xfefefefe); + buf[0][2].should.be.true; + }); + + it('pack >Q 0xfe', function() { + var buf = jspack.Pack('>Q', [[0xfefefefe, 0xfefefefe]]); + buf.should.be.eql([0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe]); + }); + + it('unpack 53 are representable in the Number type", which is "representing the +doubleprecision 64-bit format IEEE 754 values as specified in the IEEE Standard for Binary Floating-Point Arithmetic". +The [maximum safe integer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER) +in JavaScript is 253-1. + +Example: 264-1 is 1844674407370955**1615** but in JavaScript it evaluates to 1844674407370955**2000**. + +Furthermore, bitwise operators in JavaScript "deal only with integers in the range −231 through +231−1, inclusive, or in the range 0 through 232−1, inclusive. These operators accept any value of +the Number type but first convert each such value to one of 232 integer values." + +In some use cases, however, it is required to be able to reliably work with and perform bitwise operations on the full +64 bits. This is where long.js comes into play. + +Usage +----- + +The class is compatible with CommonJS and AMD loaders and is exposed globally as `Long` if neither is available. + +```javascript +var Long = require("long"); + +var longVal = new Long(0xFFFFFFFF, 0x7FFFFFFF); + +console.log(longVal.toString()); +... +``` + +API +--- + +### Constructor + +* new **Long**(low: `number`, high: `number`, unsigned?: `boolean`)
+ Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as *signed* integers. See the from* functions below for more convenient ways of constructing Longs. + +### Fields + +* Long#**low**: `number`
+ The low 32 bits as a signed value. + +* Long#**high**: `number`
+ The high 32 bits as a signed value. + +* Long#**unsigned**: `boolean`
+ Whether unsigned or not. + +### Constants + +* Long.**ZERO**: `Long`
+ Signed zero. + +* Long.**ONE**: `Long`
+ Signed one. + +* Long.**NEG_ONE**: `Long`
+ Signed negative one. + +* Long.**UZERO**: `Long`
+ Unsigned zero. + +* Long.**UONE**: `Long`
+ Unsigned one. + +* Long.**MAX_VALUE**: `Long`
+ Maximum signed value. + +* Long.**MIN_VALUE**: `Long`
+ Minimum signed value. + +* Long.**MAX_UNSIGNED_VALUE**: `Long`
+ Maximum unsigned value. + +### Utility + +* Long.**isLong**(obj: `*`): `boolean`
+ Tests if the specified object is a Long. + +* Long.**fromBits**(lowBits: `number`, highBits: `number`, unsigned?: `boolean`): `Long`
+ Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is assumed to use 32 bits. + +* Long.**fromBytes**(bytes: `number[]`, unsigned?: `boolean`, le?: `boolean`): `Long`
+ Creates a Long from its byte representation. + +* Long.**fromBytesLE**(bytes: `number[]`, unsigned?: `boolean`): `Long`
+ Creates a Long from its little endian byte representation. + +* Long.**fromBytesBE**(bytes: `number[]`, unsigned?: `boolean`): `Long`
+ Creates a Long from its big endian byte representation. + +* Long.**fromInt**(value: `number`, unsigned?: `boolean`): `Long`
+ Returns a Long representing the given 32 bit integer value. + +* Long.**fromNumber**(value: `number`, unsigned?: `boolean`): `Long`
+ Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned. + +* Long.**fromString**(str: `string`, unsigned?: `boolean`, radix?: `number`)
+ Long.**fromString**(str: `string`, radix: `number`)
+ Returns a Long representation of the given string, written using the specified radix. + +* Long.**fromValue**(val: `*`, unsigned?: `boolean`): `Long`
+ Converts the specified value to a Long using the appropriate from* function for its type. + +### Methods + +* Long#**add**(addend: `Long | number | string`): `Long`
+ Returns the sum of this and the specified Long. + +* Long#**and**(other: `Long | number | string`): `Long`
+ Returns the bitwise AND of this Long and the specified. + +* Long#**compare**/**comp**(other: `Long | number | string`): `number`
+ Compares this Long's value with the specified's. Returns `0` if they are the same, `1` if the this is greater and `-1` if the given one is greater. + +* Long#**divide**/**div**(divisor: `Long | number | string`): `Long`
+ Returns this Long divided by the specified. + +* Long#**equals**/**eq**(other: `Long | number | string`): `boolean`
+ Tests if this Long's value equals the specified's. + +* Long#**getHighBits**(): `number`
+ Gets the high 32 bits as a signed integer. + +* Long#**getHighBitsUnsigned**(): `number`
+ Gets the high 32 bits as an unsigned integer. + +* Long#**getLowBits**(): `number`
+ Gets the low 32 bits as a signed integer. + +* Long#**getLowBitsUnsigned**(): `number`
+ Gets the low 32 bits as an unsigned integer. + +* Long#**getNumBitsAbs**(): `number`
+ Gets the number of bits needed to represent the absolute value of this Long. + +* Long#**greaterThan**/**gt**(other: `Long | number | string`): `boolean`
+ Tests if this Long's value is greater than the specified's. + +* Long#**greaterThanOrEqual**/**gte**/**ge**(other: `Long | number | string`): `boolean`
+ Tests if this Long's value is greater than or equal the specified's. + +* Long#**isEven**(): `boolean`
+ Tests if this Long's value is even. + +* Long#**isNegative**(): `boolean`
+ Tests if this Long's value is negative. + +* Long#**isOdd**(): `boolean`
+ Tests if this Long's value is odd. + +* Long#**isPositive**(): `boolean`
+ Tests if this Long's value is positive. + +* Long#**isZero**/**eqz**(): `boolean`
+ Tests if this Long's value equals zero. + +* Long#**lessThan**/**lt**(other: `Long | number | string`): `boolean`
+ Tests if this Long's value is less than the specified's. + +* Long#**lessThanOrEqual**/**lte**/**le**(other: `Long | number | string`): `boolean`
+ Tests if this Long's value is less than or equal the specified's. + +* Long#**modulo**/**mod**/**rem**(divisor: `Long | number | string`): `Long`
+ Returns this Long modulo the specified. + +* Long#**multiply**/**mul**(multiplier: `Long | number | string`): `Long`
+ Returns the product of this and the specified Long. + +* Long#**negate**/**neg**(): `Long`
+ Negates this Long's value. + +* Long#**not**(): `Long`
+ Returns the bitwise NOT of this Long. + +* Long#**notEquals**/**neq**/**ne**(other: `Long | number | string`): `boolean`
+ Tests if this Long's value differs from the specified's. + +* Long#**or**(other: `Long | number | string`): `Long`
+ Returns the bitwise OR of this Long and the specified. + +* Long#**shiftLeft**/**shl**(numBits: `Long | number | string`): `Long`
+ Returns this Long with bits shifted to the left by the given amount. + +* Long#**shiftRight**/**shr**(numBits: `Long | number | string`): `Long`
+ Returns this Long with bits arithmetically shifted to the right by the given amount. + +* Long#**shiftRightUnsigned**/**shru**/**shr_u**(numBits: `Long | number | string`): `Long`
+ Returns this Long with bits logically shifted to the right by the given amount. + +* Long#**subtract**/**sub**(subtrahend: `Long | number | string`): `Long`
+ Returns the difference of this and the specified Long. + +* Long#**toBytes**(le?: `boolean`): `number[]`
+ Converts this Long to its byte representation. + +* Long#**toBytesLE**(): `number[]`
+ Converts this Long to its little endian byte representation. + +* Long#**toBytesBE**(): `number[]`
+ Converts this Long to its big endian byte representation. + +* Long#**toInt**(): `number`
+ Converts the Long to a 32 bit integer, assuming it is a 32 bit integer. + +* Long#**toNumber**(): `number`
+ Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa). + +* Long#**toSigned**(): `Long`
+ Converts this Long to signed. + +* Long#**toString**(radix?: `number`): `string`
+ Converts the Long to a string written in the specified radix. + +* Long#**toUnsigned**(): `Long`
+ Converts this Long to unsigned. + +* Long#**xor**(other: `Long | number | string`): `Long`
+ Returns the bitwise XOR of this Long and the given one. + +Building +-------- + +To build an UMD bundle to `dist/long.js`, run: + +``` +$> npm install +$> npm run build +``` + +Running the [tests](./tests): + +``` +$> npm test +``` diff --git a/local_modules/long/index.js b/local_modules/long/index.js new file mode 100644 index 0000000..46f6341 --- /dev/null +++ b/local_modules/long/index.js @@ -0,0 +1 @@ +module.exports = require("./src/long"); diff --git a/local_modules/long/long b/local_modules/long/long new file mode 120000 index 0000000..57c4d9e --- /dev/null +++ b/local_modules/long/long @@ -0,0 +1 @@ +node_modules/long \ No newline at end of file diff --git a/local_modules/long/package.json b/local_modules/long/package.json new file mode 100644 index 0000000..532202f --- /dev/null +++ b/local_modules/long/package.json @@ -0,0 +1,64 @@ +{ + "_from": "long@^4.0.0", + "_id": "long@4.0.0", + "_inBundle": false, + "_integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "_location": "/long", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": false, + "raw": "long@^4.0.0", + "name": "long", + "escapedName": "long", + "rawSpec": "^4.0.0", + "saveSpec": null, + "fetchSpec": "^4.0.0" + }, + "_requiredBy": [ + "#USER", + "/" + ], + "_resolved": "local_modules/long", + "_shasum": "9a7b71cfb7d361a194ea555241c92f7468d5bf28", + "_spec": "long@^4.0.0", + "_where": "/home/buzz/GCS/mavlink/pymavlink/generator/javascript", + "author": { + "name": "Daniel Wirtz", + "email": "dcode@dcode.io" + }, + "bugs": { + "url": "https://github.com/dcodeIO/long.js/issues" + }, + "bundleDependencies": false, + "dependencies": {}, + "deprecated": false, + "description": "A Long class for representing a 64-bit two's-complement integer value.", + "devDependencies": { + "webpack": "^3.10.0" + }, + "files": [ + "index.js", + "LICENSE", + "README.md", + "src/long.js", + "dist/long.js", + "dist/long.js.map" + ], + "homepage": "https://github.com/dcodeIO/long.js#readme", + "keywords": [ + "math" + ], + "license": "Apache-2.0", + "main": "src/long.js", + "name": "long", + "repository": { + "type": "git", + "url": "git+https://github.com/dcodeIO/long.js.git" + }, + "scripts": { + "build": "webpack", + "test": "node tests" + }, + "version": "4.0.0" +} diff --git a/local_modules/long/src/long.js b/local_modules/long/src/long.js new file mode 100644 index 0000000..c71f8c9 --- /dev/null +++ b/local_modules/long/src/long.js @@ -0,0 +1,1325 @@ +// This file is MODIFIED from the original, by buzz 2020, please see README.md in the upper level folder for more details. + +module.exports = Long; + +/** + * wasm optimizations, to do native i64 multiplication and divide + */ +var wasm = null; + +try { + wasm = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([ + 0, 97, 115, 109, 1, 0, 0, 0, 1, 13, 2, 96, 0, 1, 127, 96, 4, 127, 127, 127, 127, 1, 127, 3, 7, 6, 0, 1, 1, 1, 1, 1, 6, 6, 1, 127, 1, 65, 0, 11, 7, 50, 6, 3, 109, 117, 108, 0, 1, 5, 100, 105, 118, 95, 115, 0, 2, 5, 100, 105, 118, 95, 117, 0, 3, 5, 114, 101, 109, 95, 115, 0, 4, 5, 114, 101, 109, 95, 117, 0, 5, 8, 103, 101, 116, 95, 104, 105, 103, 104, 0, 0, 10, 191, 1, 6, 4, 0, 35, 0, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 126, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 127, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 128, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 129, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 130, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11 + ])), {}).exports; +} catch (e) { + // no wasm support :( +} + +/** + * Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as *signed* integers. + * See the from* functions below for more convenient ways of constructing Longs. + * @exports Long + * @class A Long class for representing a 64 bit two's-complement integer value. + * @param {number} low The low (signed) 32 bits of the long + * @param {number} high The high (signed) 32 bits of the long + * @param {boolean=} unsigned Whether unsigned or not, defaults to signed + * @constructor + */ +function Long(low, high, unsigned) { + + /** + * The low 32 bits as a signed value. + * @type {number} + */ + this.low = low | 0; + + /** + * The high 32 bits as a signed value. + * @type {number} + */ + this.high = high | 0; + + /** + * Whether unsigned or not. + * @type {boolean} + */ + this.unsigned = !!unsigned; +} + +// The internal representation of a long is the two given signed, 32-bit values. +// We use 32-bit pieces because these are the size of integers on which +// Javascript performs bit-operations. For operations like addition and +// multiplication, we split each number into 16 bit pieces, which can easily be +// multiplied within Javascript's floating-point representation without overflow +// or change in sign. +// +// In the algorithms below, we frequently reduce the negative case to the +// positive case by negating the input(s) and then post-processing the result. +// Note that we must ALWAYS check specially whether those values are MIN_VALUE +// (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as +// a positive number, it overflows back into a negative). Not handling this +// case would often result in infinite recursion. +// +// Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the from* +// methods on which they depend. + +/** + * An indicator used to reliably determine if an object is a Long or not. + * @type {boolean} + * @const + * @private + */ +Long.prototype.__isLong__; + +Object.defineProperty(Long.prototype, "__isLong__", { value: true }); + +/** + * @function + * @param {*} obj Object + * @returns {boolean} + * @inner + */ +function isLong(obj) { + return (obj && obj["__isLong__"]) === true; +} + +/** + * Tests if the specified object is a Long. + * @function + * @param {*} obj Object + * @returns {boolean} + */ +Long.isLong = isLong; + +/** + * A cache of the Long representations of small integer values. + * @type {!Object} + * @inner + */ +var INT_CACHE = {}; + +/** + * A cache of the Long representations of small unsigned integer values. + * @type {!Object} + * @inner + */ +var UINT_CACHE = {}; + +/** + * @param {number} value + * @param {boolean=} unsigned + * @returns {!Long} + * @inner + */ +function fromInt(value, unsigned) { + var obj, cachedObj, cache; + if (unsigned) { + value >>>= 0; + if (cache = (0 <= value && value < 256)) { + cachedObj = UINT_CACHE[value]; + if (cachedObj) + return cachedObj; + } + obj = fromBits(value, (value | 0) < 0 ? -1 : 0, true); + if (cache) + UINT_CACHE[value] = obj; + return obj; + } else { + value |= 0; + if (cache = (-128 <= value && value < 128)) { + cachedObj = INT_CACHE[value]; + if (cachedObj) + return cachedObj; + } + obj = fromBits(value, value < 0 ? -1 : 0, false); + if (cache) + INT_CACHE[value] = obj; + return obj; + } +} + +/** + * Returns a Long representing the given 32 bit integer value. + * @function + * @param {number} value The 32 bit integer in question + * @param {boolean=} unsigned Whether unsigned or not, defaults to signed + * @returns {!Long} The corresponding Long value + */ +Long.fromInt = fromInt; + +/** + * @param {number} value + * @param {boolean=} unsigned + * @returns {!Long} + * @inner + */ +function fromNumber(value, unsigned) { + if (isNaN(value)) + return unsigned ? UZERO : ZERO; + if (unsigned) { + if (value < 0) + return UZERO; + if (value >= TWO_PWR_64_DBL) + return MAX_UNSIGNED_VALUE; + } else { + if (value <= -TWO_PWR_63_DBL) + return MIN_VALUE; + if (value + 1 >= TWO_PWR_63_DBL) + return MAX_VALUE; + } + if (value < 0) + return fromNumber(-value, unsigned).neg(); + return fromBits((value % TWO_PWR_32_DBL) | 0, (value / TWO_PWR_32_DBL) | 0, unsigned); +} + +/** + * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned. + * @function + * @param {number} value The number in question + * @param {boolean=} unsigned Whether unsigned or not, defaults to signed + * @returns {!Long} The corresponding Long value + */ +Long.fromNumber = fromNumber; + +/** + * @param {number} lowBits + * @param {number} highBits + * @param {boolean=} unsigned + * @returns {!Long} + * @inner + */ +function fromBits(lowBits, highBits, unsigned) { + return new Long(lowBits, highBits, unsigned); +} + +/** + * Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is + * assumed to use 32 bits. + * @function + * @param {number} lowBits The low 32 bits + * @param {number} highBits The high 32 bits + * @param {boolean=} unsigned Whether unsigned or not, defaults to signed + * @returns {!Long} The corresponding Long value + */ +Long.fromBits = fromBits; + +/** + * @function + * @param {number} base + * @param {number} exponent + * @returns {number} + * @inner + */ +var pow_dbl = Math.pow; // Used 4 times (4*8 to 15+4) + +/** + * @param {string} str + * @param {(boolean|number)=} unsigned + * @param {number=} radix + * @returns {!Long} + * @inner + */ +function fromString(str, unsigned, radix) { + if (str.length === 0) + throw Error('empty string'); + if (str === "NaN" || str === "Infinity" || str === "+Infinity" || str === "-Infinity") + return ZERO; + if (typeof unsigned === 'number') { + // For goog.math.long compatibility + radix = unsigned, + unsigned = false; + } else { + unsigned = !! unsigned; + } + radix = radix || 10; + if (radix < 2 || 36 < radix) + throw RangeError('radix'); + + var p; + if ((p = str.indexOf('-')) > 0) + throw Error('interior hyphen'); + else if (p === 0) { + return fromString(str.substring(1), unsigned, radix).neg(); + } + + // Do several (8) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = fromNumber(pow_dbl(radix, 8)); + + var result = ZERO; + for (var i = 0; i < str.length; i += 8) { + var size = Math.min(8, str.length - i), + value = parseInt(str.substring(i, i + size), radix); + if (size < 8) { + var power = fromNumber(pow_dbl(radix, size)); + result = result.mul(power).add(fromNumber(value)); + } else { + result = result.mul(radixToPower); + result = result.add(fromNumber(value)); + } + } + result.unsigned = unsigned; + return result; +} + +/** + * Returns a Long representation of the given string, written using the specified radix. + * @function + * @param {string} str The textual representation of the Long + * @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to signed + * @param {number=} radix The radix in which the text is written (2-36), defaults to 10 + * @returns {!Long} The corresponding Long value + */ +Long.fromString = fromString; + +/** + * @function + * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val + * @param {boolean=} unsigned + * @returns {!Long} + * @inner + */ +function fromValue(val, unsigned) { + if (typeof val === 'number') + return fromNumber(val, unsigned); + if (typeof val === 'string') + return fromString(val, unsigned); + // Throws for non-objects, converts non-instanceof Long: + return fromBits(val.low, val.high, typeof unsigned === 'boolean' ? unsigned : val.unsigned); +} + +/** + * Converts the specified value to a Long using the appropriate from* function for its type. + * @function + * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value + * @param {boolean=} unsigned Whether unsigned or not, defaults to signed + * @returns {!Long} + */ +Long.fromValue = fromValue; + +// NOTE: the compiler should inline these constant values below and then remove these variables, so there should be +// no runtime penalty for these. + +/** + * @type {number} + * @const + * @inner + */ +var TWO_PWR_16_DBL = 1 << 16; + +/** + * @type {number} + * @const + * @inner + */ +var TWO_PWR_24_DBL = 1 << 24; + +/** + * @type {number} + * @const + * @inner + */ +var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL; + +/** + * @type {number} + * @const + * @inner + */ +var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL; + +/** + * @type {number} + * @const + * @inner + */ +var TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2; + +/** + * @type {!Long} + * @const + * @inner + */ +var TWO_PWR_24 = fromInt(TWO_PWR_24_DBL); + +/** + * @type {!Long} + * @inner + */ +var ZERO = fromInt(0); + +/** + * Signed zero. + * @type {!Long} + */ +Long.ZERO = ZERO; + +/** + * @type {!Long} + * @inner + */ +var UZERO = fromInt(0, true); + +/** + * Unsigned zero. + * @type {!Long} + */ +Long.UZERO = UZERO; + +/** + * @type {!Long} + * @inner + */ +var ONE = fromInt(1); + +/** + * Signed one. + * @type {!Long} + */ +Long.ONE = ONE; + +/** + * @type {!Long} + * @inner + */ +var UONE = fromInt(1, true); + +/** + * Unsigned one. + * @type {!Long} + */ +Long.UONE = UONE; + +/** + * @type {!Long} + * @inner + */ +var NEG_ONE = fromInt(-1); + +/** + * Signed negative one. + * @type {!Long} + */ +Long.NEG_ONE = NEG_ONE; + +/** + * @type {!Long} + * @inner + */ +var MAX_VALUE = fromBits(0xFFFFFFFF|0, 0x7FFFFFFF|0, false); + +/** + * Maximum signed value. + * @type {!Long} + */ +Long.MAX_VALUE = MAX_VALUE; + +/** + * @type {!Long} + * @inner + */ +var MAX_UNSIGNED_VALUE = fromBits(0xFFFFFFFF|0, 0xFFFFFFFF|0, true); + +/** + * Maximum unsigned value. + * @type {!Long} + */ +Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE; + +/** + * @type {!Long} + * @inner + */ +var MIN_VALUE = fromBits(0, 0x80000000|0, false); + +/** + * Minimum signed value. + * @type {!Long} + */ +Long.MIN_VALUE = MIN_VALUE; + +/** + * @alias Long.prototype + * @inner + */ +var LongPrototype = Long.prototype; + +/** + * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer. + * @returns {number} + */ +LongPrototype.toInt = function toInt() { + return this.unsigned ? this.low >>> 0 : this.low; +}; + +/** + * Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa). + * @returns {number} + */ +LongPrototype.toNumber = function toNumber() { + if (this.unsigned) + return ((this.high >>> 0) * TWO_PWR_32_DBL) + (this.low >>> 0); + return this.high * TWO_PWR_32_DBL + (this.low >>> 0); +}; + +/** + * Converts the Long to a string written in the specified radix. + * @param {number=} radix Radix (2-36), defaults to 10 + * @returns {string} + * @override + * @throws {RangeError} If `radix` is out of range + */ +LongPrototype.toString = function toString(radix) { + radix = radix || 10; + if (radix < 2 || 36 < radix) + throw RangeError('radix'); + if (this.isZero()) + return '0'; + if (this.isNegative()) { // Unsigned Longs are never negative + if (this.eq(MIN_VALUE)) { + // We need to change the Long value before it can be negated, so we remove + // the bottom-most digit in this base and then recurse to do the rest. + var radixLong = fromNumber(radix), + div = this.div(radixLong), + rem1 = div.mul(radixLong).sub(this); + return div.toString(radix) + rem1.toInt().toString(radix); + } else + return '-' + this.neg().toString(radix); + } + + // Do several (6) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = fromNumber(pow_dbl(radix, 6), this.unsigned), + rem = this; + var result = ''; + while (true) { + var remDiv = rem.div(radixToPower), + intval = rem.sub(remDiv.mul(radixToPower)).toInt() >>> 0, + digits = intval.toString(radix); + rem = remDiv; + if (rem.isZero()) + return digits + result; + else { + while (digits.length < 6) + digits = '0' + digits; + result = '' + digits + result; + } + } +}; + +/** + * Gets the high 32 bits as a signed integer. + * @returns {number} Signed high bits + */ +LongPrototype.getHighBits = function getHighBits() { + return this.high; +}; + +/** + * Gets the high 32 bits as an unsigned integer. + * @returns {number} Unsigned high bits + */ +LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() { + return this.high >>> 0; +}; + +/** + * Gets the low 32 bits as a signed integer. + * @returns {number} Signed low bits + */ +LongPrototype.getLowBits = function getLowBits() { + return this.low; +}; + +/** + * Gets the low 32 bits as an unsigned integer. + * @returns {number} Unsigned low bits + */ +LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() { + return this.low >>> 0; +}; + +/** + * Gets the number of bits needed to represent the absolute value of this Long. + * @returns {number} + */ +LongPrototype.getNumBitsAbs = function getNumBitsAbs() { + if (this.isNegative()) // Unsigned Longs are never negative + return this.eq(MIN_VALUE) ? 64 : this.neg().getNumBitsAbs(); + var val = this.high != 0 ? this.high : this.low; + for (var bit = 31; bit > 0; bit--) + if ((val & (1 << bit)) != 0) + break; + return this.high != 0 ? bit + 33 : bit + 1; +}; + +/** + * Tests if this Long's value equals zero. + * @returns {boolean} + */ +LongPrototype.isZero = function isZero() { + return this.high === 0 && this.low === 0; +}; + +/** + * Tests if this Long's value equals zero. This is an alias of {@link Long#isZero}. + * @returns {boolean} + */ +LongPrototype.eqz = LongPrototype.isZero; + +/** + * Tests if this Long's value is negative. + * @returns {boolean} + */ +LongPrototype.isNegative = function isNegative() { + return !this.unsigned && this.high < 0; +}; + +/** + * Tests if this Long's value is positive. + * @returns {boolean} + */ +LongPrototype.isPositive = function isPositive() { + return this.unsigned || this.high >= 0; +}; + +/** + * Tests if this Long's value is odd. + * @returns {boolean} + */ +LongPrototype.isOdd = function isOdd() { + return (this.low & 1) === 1; +}; + +/** + * Tests if this Long's value is even. + * @returns {boolean} + */ +LongPrototype.isEven = function isEven() { + return (this.low & 1) === 0; +}; + +/** + * Tests if this Long's value equals the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.equals = function equals(other) { + if (!isLong(other)) + other = fromValue(other); + if (this.unsigned !== other.unsigned && (this.high >>> 31) === 1 && (other.high >>> 31) === 1) + return false; + return this.high === other.high && this.low === other.low; +}; + +/** + * Tests if this Long's value equals the specified's. This is an alias of {@link Long#equals}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.eq = LongPrototype.equals; + +/** + * Tests if this Long's value differs from the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.notEquals = function notEquals(other) { + return !this.eq(/* validates */ other); +}; + +/** + * Tests if this Long's value differs from the specified's. This is an alias of {@link Long#notEquals}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.neq = LongPrototype.notEquals; + +/** + * Tests if this Long's value differs from the specified's. This is an alias of {@link Long#notEquals}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.ne = LongPrototype.notEquals; + +/** + * Tests if this Long's value is less than the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.lessThan = function lessThan(other) { + return this.comp(/* validates */ other) < 0; +}; + +/** + * Tests if this Long's value is less than the specified's. This is an alias of {@link Long#lessThan}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.lt = LongPrototype.lessThan; + +/** + * Tests if this Long's value is less than or equal the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) { + return this.comp(/* validates */ other) <= 0; +}; + +/** + * Tests if this Long's value is less than or equal the specified's. This is an alias of {@link Long#lessThanOrEqual}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.lte = LongPrototype.lessThanOrEqual; + +/** + * Tests if this Long's value is less than or equal the specified's. This is an alias of {@link Long#lessThanOrEqual}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.le = LongPrototype.lessThanOrEqual; + +/** + * Tests if this Long's value is greater than the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.greaterThan = function greaterThan(other) { + return this.comp(/* validates */ other) > 0; +}; + +/** + * Tests if this Long's value is greater than the specified's. This is an alias of {@link Long#greaterThan}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.gt = LongPrototype.greaterThan; + +/** + * Tests if this Long's value is greater than or equal the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) { + return this.comp(/* validates */ other) >= 0; +}; + +/** + * Tests if this Long's value is greater than or equal the specified's. This is an alias of {@link Long#greaterThanOrEqual}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.gte = LongPrototype.greaterThanOrEqual; + +/** + * Tests if this Long's value is greater than or equal the specified's. This is an alias of {@link Long#greaterThanOrEqual}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + */ +LongPrototype.ge = LongPrototype.greaterThanOrEqual; + +/** + * Compares this Long's value with the specified's. + * @param {!Long|number|string} other Other value + * @returns {number} 0 if they are the same, 1 if the this is greater and -1 + * if the given one is greater + */ +LongPrototype.compare = function compare(other) { + if (!isLong(other)) + other = fromValue(other); + if (this.eq(other)) + return 0; + var thisNeg = this.isNegative(), + otherNeg = other.isNegative(); + if (thisNeg && !otherNeg) + return -1; + if (!thisNeg && otherNeg) + return 1; + // At this point the sign bits are the same + if (!this.unsigned) + return this.sub(other).isNegative() ? -1 : 1; + // Both are positive if at least one is unsigned + return (other.high >>> 0) > (this.high >>> 0) || (other.high === this.high && (other.low >>> 0) > (this.low >>> 0)) ? -1 : 1; +}; + +/** + * Compares this Long's value with the specified's. This is an alias of {@link Long#compare}. + * @function + * @param {!Long|number|string} other Other value + * @returns {number} 0 if they are the same, 1 if the this is greater and -1 + * if the given one is greater + */ +LongPrototype.comp = LongPrototype.compare; + +/** + * Negates this Long's value. + * @returns {!Long} Negated Long + */ +LongPrototype.negate = function negate() { + if (!this.unsigned && this.eq(MIN_VALUE)) + return MIN_VALUE; + return this.not().add(ONE); +}; + +/** + * Negates this Long's value. This is an alias of {@link Long#negate}. + * @function + * @returns {!Long} Negated Long + */ +LongPrototype.neg = LongPrototype.negate; + +/** + * Returns the sum of this and the specified Long. + * @param {!Long|number|string} addend Addend + * @returns {!Long} Sum + */ +LongPrototype.add = function add(addend) { + if (!isLong(addend)) + addend = fromValue(addend); + + // Divide each number into 4 chunks of 16 bits, and then sum the chunks. + + var a48 = this.high >>> 16; + var a32 = this.high & 0xFFFF; + var a16 = this.low >>> 16; + var a00 = this.low & 0xFFFF; + + var b48 = addend.high >>> 16; + var b32 = addend.high & 0xFFFF; + var b16 = addend.low >>> 16; + var b00 = addend.low & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 + b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 + b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 + b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 + b48; + c48 &= 0xFFFF; + return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned); +}; + +/** + * Returns the difference of this and the specified Long. + * @param {!Long|number|string} subtrahend Subtrahend + * @returns {!Long} Difference + */ +LongPrototype.subtract = function subtract(subtrahend) { + if (!isLong(subtrahend)) + subtrahend = fromValue(subtrahend); + return this.add(subtrahend.neg()); +}; + +/** + * Returns the difference of this and the specified Long. This is an alias of {@link Long#subtract}. + * @function + * @param {!Long|number|string} subtrahend Subtrahend + * @returns {!Long} Difference + */ +LongPrototype.sub = LongPrototype.subtract; + +/** + * Returns the product of this and the specified Long. + * @param {!Long|number|string} multiplier Multiplier + * @returns {!Long} Product + */ +LongPrototype.multiply = function multiply(multiplier) { + if (this.isZero()) + return this; + if (!isLong(multiplier)) + multiplier = fromValue(multiplier); + + // use wasm support if present + if (wasm) { + var low = wasm.mul(this.low, + this.high, + multiplier.low, + multiplier.high); + return fromBits(low, wasm.get_high(), this.unsigned); + } + + if (multiplier.isZero()) + return (this.unsigned?UZERO:ZERO); + if (this.eq(MIN_VALUE)) + return multiplier.isOdd() ? MIN_VALUE : (this.unsigned?UZERO:ZERO); + if (multiplier.eq(MIN_VALUE)) + return this.isOdd() ? MIN_VALUE : (this.unsigned?UZERO:ZERO); + + if (this.isNegative()) { + if (multiplier.isNegative()) + return this.neg().mul(multiplier.neg()); + else + return this.neg().mul(multiplier).neg(); + } else if (multiplier.isNegative()) + return this.mul(multiplier.neg()).neg(); + + // If both longs are small, use float multiplication + if (this.lt(TWO_PWR_24) && multiplier.lt(TWO_PWR_24)) + return fromNumber(this.toNumber() * multiplier.toNumber(), this.unsigned); + + // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products. + // We can skip products that would overflow. + + var a48 = this.high >>> 16; + var a32 = this.high & 0xFFFF; + var a16 = this.low >>> 16; + var a00 = this.low & 0xFFFF; + + var b48 = multiplier.high >>> 16; + var b32 = multiplier.high & 0xFFFF; + var b16 = multiplier.low >>> 16; + var b00 = multiplier.low & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 * b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 * b00; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c16 += a00 * b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 * b00; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a16 * b16; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a00 * b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; + c48 &= 0xFFFF; + return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned); +}; + +/** + * Returns the product of this and the specified Long. This is an alias of {@link Long#multiply}. + * @function + * @param {!Long|number|string} multiplier Multiplier + * @returns {!Long} Product + */ +LongPrototype.mul = LongPrototype.multiply; + +/** + * Returns this Long divided by the specified. The result is signed if this Long is signed or + * unsigned if this Long is unsigned. + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Quotient + */ +LongPrototype.divide = function divide(divisor) { + if (!isLong(divisor)) + divisor = fromValue(divisor); + if (divisor.isZero()) + throw Error('division by zero'); + + // use wasm support if present + if (wasm) { + // guard against signed division overflow: the largest + // negative number / -1 would be 1 larger than the largest + // positive number, due to two's complement. + if (!this.unsigned && + this.high === -0x80000000 && + divisor.low === -1 && divisor.high === -1) { + // be consistent with non-wasm code path + return this; + } + var low = (this.unsigned ? wasm.div_u : wasm.div_s)( + this.low, + this.high, + divisor.low, + divisor.high + ); + return fromBits(low, wasm.get_high(), this.unsigned); + } + + if (this.isZero()) + return this.unsigned ? UZERO : ZERO; + var approx, rem, res; + if (!this.unsigned) { + // This section is only relevant for signed longs and is derived from the + // closure library as a whole. + if (this.eq(MIN_VALUE)) { + if (divisor.eq(ONE) || divisor.eq(NEG_ONE)) + return MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE + else if (divisor.eq(MIN_VALUE)) + return ONE; + else { + // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. + var halfThis = this.shr(1); + approx = halfThis.div(divisor).shl(1); + if (approx.eq(ZERO)) { + return divisor.isNegative() ? ONE : NEG_ONE; + } else { + rem = this.sub(divisor.mul(approx)); + res = approx.add(rem.div(divisor)); + return res; + } + } + } else if (divisor.eq(MIN_VALUE)) + return this.unsigned ? UZERO : ZERO; + if (this.isNegative()) { + if (divisor.isNegative()) + return this.neg().div(divisor.neg()); + return this.neg().div(divisor).neg(); + } else if (divisor.isNegative()) + return this.div(divisor.neg()).neg(); + res = ZERO; + } else { + // The algorithm below has not been made for unsigned longs. It's therefore + // required to take special care of the MSB prior to running it. + if (!divisor.unsigned) + divisor = divisor.toUnsigned(); + if (divisor.gt(this)) + return UZERO; + if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true + return UONE; + res = UZERO; + } + + // Repeat the following until the remainder is less than other: find a + // floating-point that approximates remainder / other *from below*, add this + // into the result, and subtract it from the remainder. It is critical that + // the approximate value is less than or equal to the real value so that the + // remainder never becomes negative. + rem = this; + while (rem.gte(divisor)) { + // Approximate the result of division. This may be a little greater or + // smaller than the actual value. + approx = Math.max(1, Math.floor(rem.toNumber() / divisor.toNumber())); + + // We will tweak the approximate result by changing it in the 48-th digit or + // the smallest non-fractional digit, whichever is larger. + var log2 = Math.ceil(Math.log(approx) / Math.LN2), + delta = (log2 <= 48) ? 1 : pow_dbl(2, log2 - 48), + + // Decrease the approximation until it is smaller than the remainder. Note + // that if it is too large, the product overflows and is negative. + approxRes = fromNumber(approx), + approxRem = approxRes.mul(divisor); + while (approxRem.isNegative() || approxRem.gt(rem)) { + approx -= delta; + approxRes = fromNumber(approx, this.unsigned); + approxRem = approxRes.mul(divisor); + } + + // We know the answer can't be zero... and actually, zero would cause + // infinite recursion since we would make no progress. + if (approxRes.isZero()) + approxRes = ONE; + + res = res.add(approxRes); + rem = rem.sub(approxRem); + } + return res; +}; + +/** + * Returns this Long divided by the specified. This is an alias of {@link Long#divide}. + * @function + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Quotient + */ +LongPrototype.div = LongPrototype.divide; + +/** + * Returns this Long modulo the specified. + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Remainder + */ +LongPrototype.modulo = function modulo(divisor) { + if (!isLong(divisor)) + divisor = fromValue(divisor); + + // use wasm support if present + if (wasm) { + var low = (this.unsigned ? wasm.rem_u : wasm.rem_s)( + this.low, + this.high, + divisor.low, + divisor.high + ); + return fromBits(low, wasm.get_high(), this.unsigned); + } + + return this.sub(this.div(divisor).mul(divisor)); +}; + +/** + * Returns this Long modulo the specified. This is an alias of {@link Long#modulo}. + * @function + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Remainder + */ +LongPrototype.mod = LongPrototype.modulo; + +/** + * Returns this Long modulo the specified. This is an alias of {@link Long#modulo}. + * @function + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Remainder + */ +LongPrototype.rem = LongPrototype.modulo; + +/** + * Returns the bitwise NOT of this Long. + * @returns {!Long} + */ +LongPrototype.not = function not() { + return fromBits(~this.low, ~this.high, this.unsigned); +}; + +/** + * Returns the bitwise AND of this Long and the specified. + * @param {!Long|number|string} other Other Long + * @returns {!Long} + */ +LongPrototype.and = function and(other) { + if (!isLong(other)) + other = fromValue(other); + return fromBits(this.low & other.low, this.high & other.high, this.unsigned); +}; + +/** + * Returns the bitwise OR of this Long and the specified. + * @param {!Long|number|string} other Other Long + * @returns {!Long} + */ +LongPrototype.or = function or(other) { + if (!isLong(other)) + other = fromValue(other); + return fromBits(this.low | other.low, this.high | other.high, this.unsigned); +}; + +/** + * Returns the bitwise XOR of this Long and the given one. + * @param {!Long|number|string} other Other Long + * @returns {!Long} + */ +LongPrototype.xor = function xor(other) { + if (!isLong(other)) + other = fromValue(other); + return fromBits(this.low ^ other.low, this.high ^ other.high, this.unsigned); +}; + +/** + * Returns this Long with bits shifted to the left by the given amount. + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + */ +LongPrototype.shiftLeft = function shiftLeft(numBits) { + if (isLong(numBits)) + numBits = numBits.toInt(); + if ((numBits &= 63) === 0) + return this; + else if (numBits < 32) + return fromBits(this.low << numBits, (this.high << numBits) | (this.low >>> (32 - numBits)), this.unsigned); + else + return fromBits(0, this.low << (numBits - 32), this.unsigned); +}; + +/** + * Returns this Long with bits shifted to the left by the given amount. This is an alias of {@link Long#shiftLeft}. + * @function + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + */ +LongPrototype.shl = LongPrototype.shiftLeft; + +/** + * Returns this Long with bits arithmetically shifted to the right by the given amount. + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + */ +LongPrototype.shiftRight = function shiftRight(numBits) { + if (isLong(numBits)) + numBits = numBits.toInt(); + if ((numBits &= 63) === 0) + return this; + else if (numBits < 32) + return fromBits((this.low >>> numBits) | (this.high << (32 - numBits)), this.high >> numBits, this.unsigned); + else + return fromBits(this.high >> (numBits - 32), this.high >= 0 ? 0 : -1, this.unsigned); +}; + +/** + * Returns this Long with bits arithmetically shifted to the right by the given amount. This is an alias of {@link Long#shiftRight}. + * @function + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + */ +LongPrototype.shr = LongPrototype.shiftRight; + +/** + * Returns this Long with bits logically shifted to the right by the given amount. + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + */ +LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) { + if (isLong(numBits)) + numBits = numBits.toInt(); + numBits &= 63; + if (numBits === 0) + return this; + else { + var high = this.high; + if (numBits < 32) { + var low = this.low; + return fromBits((low >>> numBits) | (high << (32 - numBits)), high >>> numBits, this.unsigned); + } else if (numBits === 32) + return fromBits(high, 0, this.unsigned); + else + return fromBits(high >>> (numBits - 32), 0, this.unsigned); + } +}; + +/** + * Returns this Long with bits logically shifted to the right by the given amount. This is an alias of {@link Long#shiftRightUnsigned}. + * @function + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + */ +LongPrototype.shru = LongPrototype.shiftRightUnsigned; + +/** + * Returns this Long with bits logically shifted to the right by the given amount. This is an alias of {@link Long#shiftRightUnsigned}. + * @function + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + */ +LongPrototype.shr_u = LongPrototype.shiftRightUnsigned; + +/** + * Converts this Long to signed. + * @returns {!Long} Signed long + */ +LongPrototype.toSigned = function toSigned() { + if (!this.unsigned) + return this; + return fromBits(this.low, this.high, false); +}; + +/** + * Converts this Long to unsigned. + * @returns {!Long} Unsigned long + */ +LongPrototype.toUnsigned = function toUnsigned() { + if (this.unsigned) + return this; + return fromBits(this.low, this.high, true); +}; + +/** + * Converts this Long to its byte representation. + * @param {boolean=} le Whether little or big endian, defaults to big endian + * @returns {!Array.} Byte representation + */ +LongPrototype.toBytes = function toBytes(le) { + return le ? this.toBytesLE() : this.toBytesBE(); +}; + +/** + * Converts this Long to its little endian byte representation. + * @returns {!Array.} Little endian byte representation + */ +LongPrototype.toBytesLE = function toBytesLE() { + var hi = this.high, + lo = this.low; + return [ + lo & 0xff, + lo >>> 8 & 0xff, + lo >>> 16 & 0xff, + lo >>> 24 , + hi & 0xff, + hi >>> 8 & 0xff, + hi >>> 16 & 0xff, + hi >>> 24 + ]; +}; + +/** + * Converts this Long to its big endian byte representation. + * @returns {!Array.} Big endian byte representation + */ +LongPrototype.toBytesBE = function toBytesBE() { + var hi = this.high, + lo = this.low; + return [ + hi >>> 24 , + hi >>> 16 & 0xff, + hi >>> 8 & 0xff, + hi & 0xff, + lo >>> 24 , + lo >>> 16 & 0xff, + lo >>> 8 & 0xff, + lo & 0xff + ]; +}; + +/** + * Creates a Long from its byte representation. + * @param {!Array.} bytes Byte representation + * @param {boolean=} unsigned Whether unsigned or not, defaults to signed + * @param {boolean=} le Whether little or big endian, defaults to big endian + * @returns {Long} The corresponding Long value + */ +Long.fromBytes = function fromBytes(bytes, unsigned, le) { + return le ? Long.fromBytesLE(bytes, unsigned) : Long.fromBytesBE(bytes, unsigned); +}; + +/** + * Creates a Long from its little endian byte representation. + * @param {!Array.} bytes Little endian byte representation + * @param {boolean=} unsigned Whether unsigned or not, defaults to signed + * @returns {Long} The corresponding Long value + */ +Long.fromBytesLE = function fromBytesLE(bytes, unsigned) { + return new Long( + bytes[0] | + bytes[1] << 8 | + bytes[2] << 16 | + bytes[3] << 24, + bytes[4] | + bytes[5] << 8 | + bytes[6] << 16 | + bytes[7] << 24, + unsigned + ); +}; + +/** + * Creates a Long from its big endian byte representation. + * @param {!Array.} bytes Big endian byte representation + * @param {boolean=} unsigned Whether unsigned or not, defaults to signed + * @returns {Long} The corresponding Long value + */ +Long.fromBytesBE = function fromBytesBE(bytes, unsigned) { + return new Long( + bytes[4] << 24 | + bytes[5] << 16 | + bytes[6] << 8 | + bytes[7], + bytes[0] << 24 | + bytes[1] << 16 | + bytes[2] << 8 | + bytes[3], + unsigned + ); +}; diff --git a/mav_v2.js b/mav_v2.js index e2dd1e5..bc00ae2 100644 --- a/mav_v2.js +++ b/mav_v2.js @@ -8,9 +8,11 @@ Note: this file has been auto-generated. DO NOT EDIT jspack = require("jspack").jspack, _ = require("underscore"), - events = require("events"), + events = require("events"), // for .emit(..), MAVLink20Processor inherits from events.EventEmitter util = require("util"); +var Long = require('long'); + // Add a convenience method to Buffer Buffer.prototype.toByteArray = function () { return Array.prototype.slice.call(this, 0) @@ -34,8 +36,14 @@ mavlink20.x25Crc = function(buffer, crcIN) { } mavlink20.WIRE_PROTOCOL_VERSION = "2.0"; + +mavlink20.PROTOCOL_MARKER_V1 = 0xFE +mavlink20.PROTOCOL_MARKER_V2 = 0xFD +mavlink20.HEADER_LEN_V1 = 6 +mavlink20.HEADER_LEN_V2 = 10 mavlink20.HEADER_LEN = 10; + mavlink20.MAVLINK_TYPE_CHAR = 0 mavlink20.MAVLINK_TYPE_UINT8_T = 1 mavlink20.MAVLINK_TYPE_INT8_T = 2 @@ -49,6 +57,8 @@ mavlink20.MAVLINK_TYPE_FLOAT = 9 mavlink20.MAVLINK_TYPE_DOUBLE = 10 mavlink20.MAVLINK_IFLAG_SIGNED = 0x01 +mavlink20.MAVLINK_SIGNATURE_BLOCK_LEN = 13 + // Mavlink headers incorporate sequence, source system (platform) and source component. mavlink20.header = function(msgId, mlen, seq, srcSystem, srcComponent, incompat_flags=0, compat_flags=0,) { @@ -71,33 +81,101 @@ mavlink20.header.prototype.pack = function() { mavlink20.message = function() {}; // Convenience setter to facilitate turning the unpacked array of data into member properties -mavlink20.message.prototype.set = function(args) { +mavlink20.message.prototype.set = function(args,verbose) { +// inspect + _.each(this.fieldnames, function(e, i) { + var num = parseInt(i,10); + if (this.hasOwnProperty(e) && isNaN(num) ){ // asking for an attribure thats non-numeric is ok unless its already an attribute we have + console.log("WARNING, overwriting an existing property is DANGEROUS:"+e+" ==>"+i+"==>"+args[i]+" -> "+JSON.stringify(this)); + } + }, this); +// then modify _.each(this.fieldnames, function(e, i) { this[e] = args[i]; }, this); }; +// trying to be the same-ish as the python function of the same name +mavlink20.message.prototype.sign_packet = function( mav) { + var crypto= require('crypto'); + var h = crypto.createHash('sha256'); + + //mav.signing.timestamp is a 48bit number, or 6 bytes. + + // due to js not being able to shift numbers more than 32, we'll use this instead.. + // js stores all its numbers as a 64bit float with 53 bits of mantissa, so have room for 48 ok. + // positive shifts left, negative shifts right + function shift(number, shift) { + return number * Math.pow(2, shift); + } + + var thigh = shift(mav.signing.timestamp,-32) // 2 bytes from the top, shifted right by 32 bits + var tlow = (mav.signing.timestamp & 0xfffffff ) // 4 bytes from the bottom + +// return jspack.Pack('HB', [ ((this.msgId & 0xFF) << 8) | ((this.msgId >> 8) & 0xFF), this.msgId>>16]); + +/* + // I means unsigned 4bytes, H means unsigned 2 bytes + var t = jspack.Unpack(' 1 && this.payload[plen-1] == 0) { - plen = plen - 1; - } - this.payload = this.payload.slice(0, plen); - var incompat_flags = 0; - this.header = new mavlink20.header(this.id, this.payload.length, mav.seq, mav.srcSystem, mav.srcComponent, incompat_flags, 0,); - this.msgbuf = this.header.pack().concat(this.payload); - var crc = mavlink20.x25Crc(this.msgbuf.slice(1)); - - // For now, assume always using crc_extra = True. TODO: check/fix this. + this._payload = payload; + var plen = this._payload.length; + //in MAVLink2 we can strip trailing zeros off payloads. This allows for simple + // variable length arrays and smaller packets + while (plen > 1 && this._payload[plen-1] == 0) { + plen = plen - 1; + } + this._payload = this._payload.slice(0, plen); + // signing is our first incompat flag. + var incompat_flags = 0; + if (mav.signing.sign_outgoing){ + incompat_flags |= mavlink20.MAVLINK_IFLAG_SIGNED + } + // header + this._header = new mavlink20.header(this._id, this._payload.length, mav.seq, mav.srcSystem, mav.srcComponent, incompat_flags, 0,); + // payload + this._msgbuf = this._header.pack().concat(this._payload); + // crc - for now, assume always using crc_extra = True. TODO: check/fix this. + var crc = mavlink20.x25Crc(this._msgbuf.slice(1)); crc = mavlink20.x25Crc([crc_extra], crc); - this.msgbuf = this.msgbuf.concat(jspack.Pack(' MAV. Also used to return a point from MAV -> GCS. @@ -2638,25 +3083,35 @@ return a point from MAV -> GCS. lng : Longitude of point. (float) */ -mavlink20.messages.fence_point = function(target_system, target_component, idx, count, lat, lng) { + mavlink20.messages.fence_point = function(target_system, target_component, idx, count, lat, lng) { - this.format = ' MAV. Also used to return a point from MAV -> GCS. @@ -3054,25 +3639,35 @@ return a point from MAV -> GCS. flags : Configuration flags. (uint8_t) */ -mavlink20.messages.rally_point = function(target_system, target_component, idx, count, lat, lng, alt, break_alt, land_dir, flags) { + mavlink20.messages.rally_point = function(target_system, target_component, idx, count, lat, lng, alt, break_alt, land_dir, flags) { - this.format = ' value[float]. @@ -4446,25 +5586,35 @@ a full documentation of QGroundControl and IMU code. param_index : Parameter index. Send -1 to use the param ID field as identifier (else the param id will be ignored) (int16_t) */ -mavlink20.messages.param_request_read = function(target_system, target_component, param_id, param_index) { + mavlink20.messages.param_request_read = function(target_system, target_component, param_id, param_index) { - this.format = ' 0 indicates the interval at which it is sent. (int32_t) */ -mavlink20.messages.message_interval = function(message_id, interval_us) { + mavlink20.messages.message_interval = function(message_id, interval_us) { - this.format = '= 1 && this.buf[0] == this.protocol_marker ) { - // this.have_prefix_error = false; - //} } // Determine the length. Leaves buffer untouched. +// Although the 'len' of a packet is available as of the second byte, the third byte with 'incompat_flags' lets us know if we have signing +// enabled, which affects the real-world length by the signature-block length of 13 bytes +// once successful, 'this.expected_length' is correctly set for the whole packet. MAVLink20Processor.prototype.parseLength = function() { - if( this.buf.length >= 2 ) { - var unpacked = jspack.Unpack('BB', this.buf.slice(0, 2)); - this.expected_length = unpacked[1] + mavlink20.HEADER_LEN + 2 // length of message + header + CRC + if( this.buf.length >= 3 ) { + var unpacked = jspack.Unpack('BBB', this.buf.slice(0, 3)); + var magic = unpacked[0]; // stx ie fd or fe etc + this.expected_length = unpacked[1] + mavlink20.HEADER_LEN + 2 // length of message + header + CRC (ie non-signed length) + this.incompat_flags = unpacked[2]; + // mavlink2 only.. in mavlink1, incompat_flags var above is actually the 'seq', but for this test its ok. + if ((magic == mavlink20.PROTOCOL_MARKER_V2 ) && ( this.incompat_flags & mavlink20.MAVLINK_IFLAG_SIGNED )){ + this.expected_length += mavlink20.MAVLINK_SIGNATURE_BLOCK_LEN; + } } } -// input some data bytes, possibly returning a new message +// input some data bytes, possibly returning a new message - python equiv function is called parse_char / __parse_char_legacy MAVLink20Processor.prototype.parseChar = function(c) { var m = null; @@ -10024,8 +13082,9 @@ MAVLink20Processor.prototype.parseChar = function(c) { } + // emit a packet-specific message as well as a generic message, user/s can choose to use either or both of these. if(null != m) { - this.emit(m.name, m); + this.emit(m._name, m); this.emit('message', m); } @@ -10033,22 +13092,26 @@ MAVLink20Processor.prototype.parseChar = function(c) { } +// continuation of python's __parse_char_legacy MAVLink20Processor.prototype.parsePayload = function() { var m = null; - // If we have enough bytes to try and read it, read it. - if( this.expected_length >= 8 && this.buf.length >= this.expected_length ) { + // tip: this.expected_length and this.incompat_flags both already set correctly by parseLength(..) above + + // If we have enough bytes to try and read it, read it. + // shortest packet is header+checksum(2) with no payload, so we need at least that many + // but once we have a longer 'expected length' we have to read all of it. + if(( this.expected_length >= mavlink20.HEADER_LEN+2) && (this.buf.length >= this.expected_length) ) { // Slice off the expected packet length, reset expectation to be to find a header. var mbuf = this.buf.slice(0, this.expected_length); + // TODO: slicing off the buffer should depend on the error produced by the decode() function - // - if a message we find a well formed message, cut-off the expected_length + // - if we find a well formed message, cut-off the expected_length // - if the message is not well formed (correct prefix by accident), cut-off 1 char only this.buf = this.buf.slice(this.expected_length); - this.expected_length = 6; - - // w.info("Attempting to parse packet, message candidate buffer is ["+mbuf.toByteArray()+"]"); + this.expected_length = mavlink20.HEADER_LEN; // after attempting a parse, we'll next expect to find just a header. try { m = this.decode(mbuf); @@ -10090,14 +13153,141 @@ MAVLink20Processor.prototype.parseBuffer = function(s) { } +// from Buffer to ArrayBuffer +function toArrayBuffer(buf) { + var ab = new ArrayBuffer(buf.length); + var view = new Uint8Array(ab); + for (var i = 0; i < buf.length; ++i) { + view[i] = buf[i]; + } + return ab; +} +// and back +function toBuffer(ab) { + var buf = Buffer.alloc(ab.byteLength); + var view = new Uint8Array(ab); + for (var i = 0; i < buf.length; ++i) { + buf[i] = view[i]; + } + return buf; +} + +//check signature on incoming message +MAVLink20Processor.prototype.check_signature = function(msgbuf, srcSystem, srcComponent) { + + //if (isinstance(msgbuf, array.array)){ + // msgbuf = msgbuf.tostring() + //} + if ( Buffer.isBuffer(msgbuf) ) { + msgbuf = toArrayBuffer(msgbuf); + } + + //timestamp_buf = msgbuf[-12:-6] + var timestamp_buf= msgbuf.slice(-12,-6); + + //link_id = msgbuf[-13] + var link_id= new Buffer.from(msgbuf.slice(-13,-12)); // just a single byte really, but returned as a buffer + link_id = link_id[0]; // get the first byte. + + //self.mav_sign_unpacker = jspack.Unpack('> 8) & 0xFF); - var msgIDhigh = unpacked[8]; - msgId = msgIDlow | (msgIDhigh<<16); + var msgIDlow = ((unpacked[7] & 0xFF) << 8) | ((unpacked[7] >> 8) & 0xFF); // first-two msgid bytes + var msgIDhigh = unpacked[8]; // the 3rd msgid byte + msgId = msgIDlow | (msgIDhigh<<16); // combined result. 0 - 16777215 24bit number } catch(e) { throw new Error('Unable to unpack MAVLink header: ' + e.message); } + // TODO allow full parsing of 1.0 inside the 2.0 parser, this is just a start + if (magic == mavlink20.PROTOCOL_MARKER_V1){ + //headerlen = 6; + + // these two are in the same place in both v1 and v2 so no change needed: + //magic = magic; + //mlen = mlen; + + // grab mavlink-v1 header position info from v2 unpacked position + seq1 = incompat_flags; + srcSystem1 = compat_flags; + srcComponent1 = seq; + msgId1 = srcSystem; + // override the v1 vs v2 offsets so we get the correct data either way... + seq = seq1; + srcSystem = srcSystem1; + srcComponent = srcComponent1; + msgId = msgId1; + // don't exist in mavlink1, so zero-them + incompat_flags = 0; + compat_flags = 0; + signature_len = 0; + // todo add more v1 here and don't just return + return; + } + if (magic.charCodeAt(0) != this.protocol_marker) { throw new Error("Invalid MAVLink prefix ("+magic.charCodeAt(0)+")"); } - if( mlen != msgbuf.length - (mavlink20.HEADER_LEN + 2)) { - throw new Error("Invalid MAVLink message length. Got " + (msgbuf.length - (mavlink20.HEADER_LEN + 2)) + " expected " + mlen + ", msgId=" + msgId); - } - + // is packet supposed to be signed? + if ( incompat_flags & mavlink20.MAVLINK_IFLAG_SIGNED ){ + signature_len = mavlink20.MAVLINK_SIGNATURE_BLOCK_LEN; + //console.log("incompat_flags:",incompat_flags,signature_len); + } else { + signature_len = 0; + } + + // header's declared len compared to packets actual len + var actual_len = (msgbuf.length - (mavlink20.HEADER_LEN + 2 + signature_len)); + var actual_len_nosign = (msgbuf.length - (mavlink20.HEADER_LEN + 2 )); + + //console.log("mavlink20.HEADER_LEN " , mavlink20.HEADER_LEN); + //console.log("signature_len " , signature_len); + //console.log("msgbuf.length " , msgbuf.length); + //console.log("actual_len " , actual_len); + //console.log("actual_len_nosign " , actual_len_nosign); + //console.log("mlen " , mlen); + + if ((mlen == actual_len) && (signature_len > 0)){ + var len_if_signed = mlen+signature_len; + //console.log("Packet appears signed && labled as signed, OK. msgId=" + msgId); + + } else if ((mlen == actual_len_nosign) && (signature_len > 0)){ + + var len_if_signed = mlen+signature_len; + throw new Error("Packet appears unsigned when labled as signed. Got actual_len "+actual_len_nosign+" expected " + len_if_signed + ", msgId=" + msgId); + + } else if( mlen != actual_len) { + throw new Error("Invalid MAVLink message length. Got " + (msgbuf.length - (mavlink20.HEADER_LEN + 2)) + " expected " + mlen + ", msgId=" + msgId); + + } + if( false === _.has(mavlink20.map, msgId) ) { throw new Error("Unknown MAVLink message ID (" + msgId + ")"); } + // here's the 4 common chunks of packer we want to work with below.. + var headerBuf= msgbuf.slice(mavlink20.HEADER_LEN); // first10 + var sigBuf = msgbuf.slice(-signature_len); // last 13 or nothing + var crcBuf1 = msgbuf.slice(-2); // either last-2 or last-2-prior-to-signature + var crcBuf2 = msgbuf.slice(-15,-13); // either last-2 or last-2-prior-to-signature + var payloadBuf = msgbuf.slice(mavlink20.HEADER_LEN, -(signature_len+2)); // the remaining bit between the header and the crc + var crcCheckBuf = msgbuf.slice(1, -(signature_len+2)); // the part uses to calculate the crc - ie between the magic and signature, + // decode the payload // refs: (fmt, type, order_map, crc_extra) = mavlink20.map[msgId] var decoder = mavlink20.map[msgId]; + //console.log("signature_len:",signature_len); + //console.log("sigBuf:",sigBuf); + //console.log("msgbuf:",msgbuf); + //console.log("crcBuf-nosig:",crcBuf1); + //console.log("crcBuf-sig:",crcBuf2); + //console.log("payloadBuf:",payloadBuf); + //console.log("crcCheckBuf:",crcCheckBuf); + // decode the checksum - try { - var receivedChecksum = jspack.Unpack(' payload.length) { - payload = Buffer.concat([payload, Buffer.alloc(paylen - payload.length)]); + //put any truncated 0's back in (ie zero-pad ) + if (paylen > payloadBuf.length) { + payloadBuf = Buffer.concat([payloadBuf, Buffer.alloc(paylen - payloadBuf.length)]); } // Decode the payload and reorder the fields to match the order map. try { - var t = jspack.Unpack(decoder.format, payload); + var t = jspack.Unpack(decoder.format, payloadBuf); } catch (e) { - throw new Error('Unable to unpack MAVLink payload type='+decoder.type+' format='+decoder.format+' payloadLength='+ payload +': '+ e.message); + throw new Error('Unable to unpack MAVLink payload type='+decoder.type+' format='+decoder.format+' payloadLength='+ payloadBuf +': '+ e.message); } - // Reorder the fields to match the order map - var args = []; - _.each(t, function(e, i, l) { - args[i] = t[decoder.order_map[i]] - }); + // Need to check if the message contains arrays + var args = {}; + const elementsInMsg = decoder.order_map.length; + const actualElementsInMsg = JSON.parse(JSON.stringify(t)).length; + + if (elementsInMsg == actualElementsInMsg) { + // Reorder the fields to match the order map + _.each(t, function(e, i, l) { + args[i] = t[decoder.order_map[i]] + }); + } else { + // This message contains arrays + var typeIndex = 1; + var orderIndex = 0; + var memberIndex = 0; + var tempArgs = {}; + + // Walk through the fields + for(var i = 0, size = decoder.format.length-1; i <= size; ++i) { + var order = decoder.order_map[orderIndex]; + var currentType = decoder.format[typeIndex]; + + if (isNaN(parseInt(currentType))) { + // This field is not an array cehck the type and add it to the args + tempArgs[orderIndex] = t[memberIndex]; + memberIndex++; + } else { + // This field is part of an array, need to find the length of the array + var arraySize = '' + var newArray = [] + while (!isNaN(decoder.format[typeIndex])) { + arraySize = arraySize + decoder.format[typeIndex]; + typeIndex++; + } + + // Now that we know how long the array is, create an array with the values + for(var j = 0, size = parseInt(arraySize); j < size; ++j){ + newArray.push(t[j+orderIndex]); + memberIndex++; + } + + // Add the array to the args object + arraySize = arraySize + decoder.format[typeIndex]; + currentType = arraySize; + tempArgs[orderIndex] = newArray; + } + orderIndex++; + typeIndex++; + } + + // Finally reorder the fields to match the order map + _.each(t, function(e, i, l) { + args[i] = tempArgs[decoder.order_map[i]] + }); + } // construct the message object try { var m = new decoder.type(args); - m.set.call(m, args); + m.set.call(m, args,false); } catch (e) { throw new Error('Unable to instantiate MAVLink message of type '+decoder.type+' : ' + e.message); } - m.msgbuf = msgbuf; - m.payload = payload + + m._signed = sig_ok; + if (m._signed) { m._link_id = msgbuf[-13]; } + + m._msgbuf = msgbuf; + m._payload = payloadBuf m.crc = receivedChecksum; - m.header = new mavlink20.header(msgId, mlen, seq, srcSystem, srcComponent, incompat_flags, compat_flags); + m._header = new mavlink20.header(msgId, mlen, seq, srcSystem, srcComponent, incompat_flags, compat_flags); this.log(m); return m; } diff --git a/mav_v2.js.prev b/mav_v2.js.prev new file mode 100644 index 0000000..e2dd1e5 --- /dev/null +++ b/mav_v2.js.prev @@ -0,0 +1,10188 @@ +/* +MAVLink protocol implementation for node.js (auto-generated by mavgen_javascript.py) + +Generated from: ardupilotmega.xml,common.xml,uAvionix.xml,icarous.xml + +Note: this file has been auto-generated. DO NOT EDIT +*/ + +jspack = require("jspack").jspack, + _ = require("underscore"), + events = require("events"), + util = require("util"); + +// Add a convenience method to Buffer +Buffer.prototype.toByteArray = function () { + return Array.prototype.slice.call(this, 0) +} + +mavlink20 = function(){}; + +// Implement the X25CRC function (present in the Python version through the mavutil.py package) +mavlink20.x25Crc = function(buffer, crcIN) { + + var bytes = buffer; + var crcOUT = crcIN || 0xffff; + _.each(bytes, function(e) { + var tmp = e ^ (crcOUT & 0xff); + tmp = (tmp ^ (tmp << 4)) & 0xff; + crcOUT = (crcOUT >> 8) ^ (tmp << 8) ^ (tmp << 3) ^ (tmp >> 4); + crcOUT = crcOUT & 0xffff; + }); + return crcOUT; + +} + +mavlink20.WIRE_PROTOCOL_VERSION = "2.0"; +mavlink20.HEADER_LEN = 10; + +mavlink20.MAVLINK_TYPE_CHAR = 0 +mavlink20.MAVLINK_TYPE_UINT8_T = 1 +mavlink20.MAVLINK_TYPE_INT8_T = 2 +mavlink20.MAVLINK_TYPE_UINT16_T = 3 +mavlink20.MAVLINK_TYPE_INT16_T = 4 +mavlink20.MAVLINK_TYPE_UINT32_T = 5 +mavlink20.MAVLINK_TYPE_INT32_T = 6 +mavlink20.MAVLINK_TYPE_UINT64_T = 7 +mavlink20.MAVLINK_TYPE_INT64_T = 8 +mavlink20.MAVLINK_TYPE_FLOAT = 9 +mavlink20.MAVLINK_TYPE_DOUBLE = 10 + +mavlink20.MAVLINK_IFLAG_SIGNED = 0x01 + +// Mavlink headers incorporate sequence, source system (platform) and source component. +mavlink20.header = function(msgId, mlen, seq, srcSystem, srcComponent, incompat_flags=0, compat_flags=0,) { + + this.mlen = ( typeof mlen === 'undefined' ) ? 0 : mlen; + this.seq = ( typeof seq === 'undefined' ) ? 0 : seq; + this.srcSystem = ( typeof srcSystem === 'undefined' ) ? 0 : srcSystem; + this.srcComponent = ( typeof srcComponent === 'undefined' ) ? 0 : srcComponent; + this.msgId = msgId + this.incompat_flags = incompat_flags + this.compat_flags = compat_flags + +} +mavlink20.header.prototype.pack = function() { + return jspack.Pack('BBBBBBBHB', [253, this.mlen, this.incompat_flags, this.compat_flags, this.seq, this.srcSystem, this.srcComponent, ((this.msgId & 0xFF) << 8) | ((this.msgId >> 8) & 0xFF), this.msgId>>16]); +} + +// Base class declaration: mavlink.message will be the parent class for each +// concrete implementation in mavlink.messages. +mavlink20.message = function() {}; + +// Convenience setter to facilitate turning the unpacked array of data into member properties +mavlink20.message.prototype.set = function(args) { + _.each(this.fieldnames, function(e, i) { + this[e] = args[i]; + }, this); +}; + +// This pack function builds the header and produces a complete MAVLink message, +// including header and message CRC. +mavlink20.message.prototype.pack = function(mav, crc_extra, payload) { + + this.payload = payload; + var plen = this.payload.length; + //in MAVLink2 we can strip trailing zeros off payloads. This allows for simple + // variable length arrays and smaller packets + while (plen > 1 && this.payload[plen-1] == 0) { + plen = plen - 1; + } + this.payload = this.payload.slice(0, plen); + var incompat_flags = 0; + this.header = new mavlink20.header(this.id, this.payload.length, mav.seq, mav.srcSystem, mav.srcComponent, incompat_flags, 0,); + this.msgbuf = this.header.pack().concat(this.payload); + var crc = mavlink20.x25Crc(this.msgbuf.slice(1)); + + // For now, assume always using crc_extra = True. TODO: check/fix this. + crc = mavlink20.x25Crc([crc_extra], crc); + this.msgbuf = this.msgbuf.concat(jspack.Pack(' MAV. Also used to +return a point from MAV -> GCS. + + target_system : System ID. (uint8_t) + target_component : Component ID. (uint8_t) + idx : Point index (first point is 1, 0 is for return point). (uint8_t) + count : Total number of points (for sanity checking). (uint8_t) + lat : Latitude of point. (float) + lng : Longitude of point. (float) + +*/ +mavlink20.messages.fence_point = function(target_system, target_component, idx, count, lat, lng) { + + this.format = ' MAV. Also used to +return a point from MAV -> GCS. + + target_system : System ID. (uint8_t) + target_component : Component ID. (uint8_t) + idx : Point index (first point is 0). (uint8_t) + count : Total number of points (for sanity checking). (uint8_t) + lat : Latitude of point. (int32_t) + lng : Longitude of point. (int32_t) + alt : Transit / loiter altitude relative to home. (int16_t) + break_alt : Break altitude relative to home. (int16_t) + land_dir : Heading to aim for when landing. (uint16_t) + flags : Configuration flags. (uint8_t) + +*/ +mavlink20.messages.rally_point = function(target_system, target_component, idx, count, lat, lng, alt, break_alt, land_dir, flags) { + + this.format = ' value[float]. +This allows to send a parameter to any other component (such as the +GCS) without the need of previous knowledge of possible parameter +names. Thus the same GCS can store different parameters for different +autopilots. See also https://mavlink.io/en/services/parameter.html for +a full documentation of QGroundControl and IMU code. + + target_system : System ID (uint8_t) + target_component : Component ID (uint8_t) + param_id : Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string (char) + param_index : Parameter index. Send -1 to use the param ID field as identifier (else the param id will be ignored) (int16_t) + +*/ +mavlink20.messages.param_request_read = function(target_system, target_component, param_id, param_index) { + + this.format = ' 0 indicates the interval at which it is sent. (int32_t) + +*/ +mavlink20.messages.message_interval = function(message_id, interval_us) { + + this.format = '= 1 && this.buf[0] != this.protocol_marker ) { + + // Strip the offending initial byte and throw an error. + var badPrefix = this.buf[0]; + this.bufInError = this.buf.slice(0,1); + this.buf = this.buf.slice(1); + this.expected_length = mavlink20.HEADER_LEN; + + // TODO: enable subsequent prefix error suppression if robust_parsing is implemented + //if(!this.have_prefix_error) { + // this.have_prefix_error = true; + throw new Error("Bad prefix ("+badPrefix+")"); + //} + + } + //else if( this.buf.length >= 1 && this.buf[0] == this.protocol_marker ) { + // this.have_prefix_error = false; + //} + +} + +// Determine the length. Leaves buffer untouched. +MAVLink20Processor.prototype.parseLength = function() { + + if( this.buf.length >= 2 ) { + var unpacked = jspack.Unpack('BB', this.buf.slice(0, 2)); + this.expected_length = unpacked[1] + mavlink20.HEADER_LEN + 2 // length of message + header + CRC + } + +} + +// input some data bytes, possibly returning a new message +MAVLink20Processor.prototype.parseChar = function(c) { + + var m = null; + + try { + + this.pushBuffer(c); + this.parsePrefix(); + this.parseLength(); + m = this.parsePayload(); + + } catch(e) { + + this.log('error', e.message); + this.total_receive_errors += 1; + m = new mavlink20.messages.bad_data(this.bufInError, e.message); + this.bufInError = new Buffer.from([]); + + } + + if(null != m) { + this.emit(m.name, m); + this.emit('message', m); + } + + return m; + +} + +MAVLink20Processor.prototype.parsePayload = function() { + + var m = null; + + // If we have enough bytes to try and read it, read it. + if( this.expected_length >= 8 && this.buf.length >= this.expected_length ) { + + // Slice off the expected packet length, reset expectation to be to find a header. + var mbuf = this.buf.slice(0, this.expected_length); + // TODO: slicing off the buffer should depend on the error produced by the decode() function + // - if a message we find a well formed message, cut-off the expected_length + // - if the message is not well formed (correct prefix by accident), cut-off 1 char only + this.buf = this.buf.slice(this.expected_length); + this.expected_length = 6; + + // w.info("Attempting to parse packet, message candidate buffer is ["+mbuf.toByteArray()+"]"); + + try { + m = this.decode(mbuf); + this.total_packets_received += 1; + } + catch(e) { + // Set buffer in question and re-throw to generic error handling + this.bufInError = mbuf; + throw e; + } + } + + return m; + +} + +// input some data bytes, possibly returning an array of new messages +MAVLink20Processor.prototype.parseBuffer = function(s) { + + // Get a message, if one is available in the stream. + var m = this.parseChar(s); + + // No messages available, bail. + if ( null === m ) { + return null; + } + + // While more valid messages can be read from the existing buffer, add + // them to the array of new messages and return them. + var ret = [m]; + while(true) { + m = this.parseChar(); + if ( null === m ) { + // No more messages left. + return ret; + } + ret.push(m); + } + +} + +/* decode a buffer as a MAVLink message */ +MAVLink20Processor.prototype.decode = function(msgbuf) { + + var magic, incompat_flags, compat_flags, mlen, seq, srcSystem, srcComponent, unpacked, msgId; + + // decode the header + try { + unpacked = jspack.Unpack('cBBBBBBHB', msgbuf.slice(0, 10)); + magic = unpacked[0]; + mlen = unpacked[1]; + incompat_flags = unpacked[2]; + compat_flags = unpacked[3]; + seq = unpacked[4]; + srcSystem = unpacked[5]; + srcComponent = unpacked[6]; + var msgIDlow = ((unpacked[7] & 0xFF) << 8) | ((unpacked[7] >> 8) & 0xFF); + var msgIDhigh = unpacked[8]; + msgId = msgIDlow | (msgIDhigh<<16); + } + catch(e) { + throw new Error('Unable to unpack MAVLink header: ' + e.message); + } + + if (magic.charCodeAt(0) != this.protocol_marker) { + throw new Error("Invalid MAVLink prefix ("+magic.charCodeAt(0)+")"); + } + + if( mlen != msgbuf.length - (mavlink20.HEADER_LEN + 2)) { + throw new Error("Invalid MAVLink message length. Got " + (msgbuf.length - (mavlink20.HEADER_LEN + 2)) + " expected " + mlen + ", msgId=" + msgId); + } + + if( false === _.has(mavlink20.map, msgId) ) { + throw new Error("Unknown MAVLink message ID (" + msgId + ")"); + } + + // decode the payload + // refs: (fmt, type, order_map, crc_extra) = mavlink20.map[msgId] + var decoder = mavlink20.map[msgId]; + + // decode the checksum + try { + var receivedChecksum = jspack.Unpack(' payload.length) { + payload = Buffer.concat([payload, Buffer.alloc(paylen - payload.length)]); + } + // Decode the payload and reorder the fields to match the order map. + try { + var t = jspack.Unpack(decoder.format, payload); + } + catch (e) { + throw new Error('Unable to unpack MAVLink payload type='+decoder.type+' format='+decoder.format+' payloadLength='+ payload +': '+ e.message); + } + + // Reorder the fields to match the order map + var args = []; + _.each(t, function(e, i, l) { + args[i] = t[decoder.order_map[i]] + }); + + // construct the message object + try { + var m = new decoder.type(args); + m.set.call(m, args); + } + catch (e) { + throw new Error('Unable to instantiate MAVLink message of type '+decoder.type+' : ' + e.message); + } + m.msgbuf = msgbuf; + m.payload = payload + m.crc = receivedChecksum; + m.header = new mavlink20.header(msgId, mlen, seq, srcSystem, srcComponent, incompat_flags, compat_flags); + this.log(m); + return m; +} + + +// Expose this code as a module +module.exports = {mavlink20, MAVLink20Processor}; + diff --git a/mavudp_to_ws_server.js b/mavudp_to_ws_server.js index feb632f..09e53da 100644 --- a/mavudp_to_ws_server.js +++ b/mavudp_to_ws_server.js @@ -140,19 +140,19 @@ const udpserver = dgram.createSocket('udp4'); // after INCOMiNG MAVLINK goes thru the mavlink parser in the browser, it dispatches them to here where we save the source ip/port for each sysid var mavlink_ip_and_port_handler = function(message,ip,port,mavlinktype) { - if (typeof message.header == 'undefined'){ - console.log('message.header UNDEFINED, skipping packet:'); + if (typeof message._header == 'undefined'){ + console.log('message._header UNDEFINED, skipping packet:'); console.log(message); return; } // it's been parsed, and must be a valid mavlink packet, and thus must have a sysid available now.. - if ( sysid_to_ip_address[message.header.srcSystem] == null ) { - console.log(`Got first PARSED MSG from sysid:${message.header.srcSystem} src:${ip}:${port}, mav-proto:${mavlinktype}. Not repeating this. `); + if ( sysid_to_ip_address[message._header.srcSystem] == null ) { + console.log(`Got first PARSED MSG from sysid:${message._header.srcSystem} src:${ip}:${port}, mav-proto:${mavlinktype}. Not repeating this. `); } // by having this inside the above if() the source port and ip can't change without a page reload, having it below, it keeps uptodate. - sysid_to_ip_address[message.header.srcSystem] = {'ip':ip, 'port':port}; - sysid_to_mavlink_type[message.header.srcSystem] = mavlinktype; // 1 or 2 + sysid_to_ip_address[message._header.srcSystem] = {'ip':ip, 'port':port}; + sysid_to_mavlink_type[message._header.srcSystem] = mavlinktype; // 1 or 2 } @@ -215,12 +215,12 @@ var generic_message_handler = function(message) { 'NAV_CONTROLLER_OUTPUT', 'STATUSTEXT' , 'COMMAND_ACK' , 'MISSION_ITEM', 'MISSION_ITEM_INT','MISSION_COUNT','MISSION_REQUEST', 'MISSION_ACK', 'AIRSPEED_AUTOCAL', 'MISSION_ITEM_REACHED' , 'STAT_FLTTIME' ,'AUTOPILOT_VERSION' , - 'FENCE_STATUS' , 'AOA_SSA' , 'GPS_GLOBAL_ORIGIN', ].includes(message.name) ) { + 'FENCE_STATUS' , 'AOA_SSA' , 'GPS_GLOBAL_ORIGIN', ].includes(message._name) ) { console.log(message); } // log PARAM_VALUE differently to exclude common ones like where param_id starts with 'STAT_RUNTIME' etc - if ( ['PARAM_VALUE' ].includes(message.name) ) { + if ( ['PARAM_VALUE' ].includes(message._name) ) { if ( message.param_id.startsWith('STAT_RUNTIME') || message.param_id.startsWith('STAT_FLTTIME') || message.param_id.startsWith('COMPASS_') || @@ -233,39 +233,39 @@ var generic_message_handler = function(message) { } // display STATUSTEXT as simple console.log - if ( ['STATUSTEXT' ].includes(message.name) ) { + if ( ['STATUSTEXT' ].includes(message._name) ) { //console.log(`STATUSTEXT: ${message.text}`); } - if ( ['COMMAND_ACK' ].includes(message.name) ) { + if ( ['COMMAND_ACK' ].includes(message._name) ) { console.log(`COMMAND_ACK command= ${message.command} result= ${message.result} `); } - if ( ['MISSION_ITEM' ].includes(message.name) ) { + if ( ['MISSION_ITEM' ].includes(message._name) ) { // console.log(`MISSION_ITEM command= ${message.command} x= ${message.x} y= ${message.y} z= ${message.z} `); } - if ( ['MISSION_ITEM_INT' ].includes(message.name) ) { + if ( ['MISSION_ITEM_INT' ].includes(message._name) ) { console.log(`MISSION_ITEM_INT seq= ${message.seq} command= ${message.command} x= ${message.x} y= ${message.y} z= ${message.z} `); //console.log(message); } - if ( ['MISSION_COUNT' ].includes(message.name) ) { + if ( ['MISSION_COUNT' ].includes(message._name) ) { // console.log(`MISSION_COUNT number of mission items:= ${message.count} `); moved to mavMission.js } - if ( ['MISSION_ACK' ].includes(message.name) ) { + if ( ['MISSION_ACK' ].includes(message._name) ) { console.log(`MISSION_ACK recieved `); } - if ( ['MISSION_ITEM_REACHED' ].includes(message.name) ) { + if ( ['MISSION_ITEM_REACHED' ].includes(message._name) ) { console.log(`MISSION_ITEM_REACHED recieved num:= ${message.seq} `); } - if ( ['PARAM_VALUE' ].includes(message.name) && message.param_id.startsWith('STAT_FLTTIME')){ + if ( ['PARAM_VALUE' ].includes(message._name) && message.param_id.startsWith('STAT_FLTTIME')){ mins = parseInt(message.param_value/60,10); secs = parseInt(message.param_value%60,10); console.log(`TIME IN AIR: ${mins}min:${secs}secs `); @@ -411,7 +411,7 @@ In simple terms, it adds properties from other objects (source) on to a target o // these change/s are vehicle specific events, and so are bound to a specific vehicle in the collection, not the whole collection. -// We pull the Vehicle from the Collection by its sysid "current_vehicle = AllVehicles.get(message.header.srcSystem); " +// We pull the Vehicle from the Collection by its sysid "current_vehicle = AllVehicles.get(message._header.srcSystem); " //------------------------------------------------------------- @@ -428,8 +428,8 @@ In simple terms, it adds properties from other objects (source) on to a target o var heartbeat_handler = function(message) { //console.log(`Got a HEARTBEAT message from ${udpserver.last_ip_address.address}:${udpserver.last_ip_address.port} `); //console.log(message); - //console.log(`got HEARTBEAT with ID: ${message.header.srcSystem}`); - var tmp_sysid = message.header.srcSystem; + //console.log(`got HEARTBEAT with ID: ${message._header.srcSystem}`); + var tmp_sysid = message._header.srcSystem; var current_vehicle = AllVehicles.get(tmp_sysid); // returns the entire vehicle object // if we already have the vehicle in the collection: if ( current_vehicle) { @@ -457,7 +457,7 @@ var heartbeat_handler = function(message) { //console.log("UPDATE:"+JSON.stringify(AllVehicles)); // we only CREATE new vehicle object/s when we successfully see a HEARTBEAT from them: } else { - var tmpVehicle = new VehicleClass({id:message.header.srcSystem}); + var tmpVehicle = new VehicleClass({id:message._header.srcSystem}); // put the modified temporary object back onto the collection AllVehicles.add(tmpVehicle, {merge: true}); // 'add' can do "update" when merge=true, in case theres 2 of them somehow. //console.log("ADD:"+JSON.stringify(AllVehicles)); @@ -500,7 +500,7 @@ mavlinkParser2.on('HEARTBEAT', heartbeat_handler); var gpi_handler = function(message) { - var current_vehicle = AllVehicles.get(message.header.srcSystem); + var current_vehicle = AllVehicles.get(message._header.srcSystem); // if we already have the vehicle in the collection: if ( current_vehicle) { //console.log(`Got a GLOBAL_POSITION_INT message from ${udpserver.last_ip_address.address}:${udpserver.last_ip_address.port} `); @@ -530,7 +530,7 @@ mavlinkParser2.on('GLOBAL_POSITION_INT', gpi_handler); var sysstatus_handler = function(message) { - var current_vehicle = AllVehicles.get(message.header.srcSystem); + var current_vehicle = AllVehicles.get(message._header.srcSystem); // if we already have the vehicle in the collection: if ( current_vehicle) { //console.log(`Got a SYS_STATUS message from ${udpserver.last_ip_address.address}:${udpserver.last_ip_address.port} `); @@ -557,7 +557,7 @@ mavlinkParser2.on('SYS_STATUS', sysstatus_handler); // there are specific status-text messages that help us know if we really are armed/disarmed , and the rest are sent as 'message' for the web-console. var statustext_handler = function(message) { - var current_vehicle = AllVehicles.get(message.header.srcSystem); + var current_vehicle = AllVehicles.get(message._header.srcSystem); // if we already have the vehicle in the collection: if ( current_vehicle) { @@ -575,7 +575,7 @@ var statustext_handler = function(message) { } // everything else is just pushed into the 'messages' display box by this event... - io.of(IONameSpace).emit('status_text', { "sysid": message.header.srcSystem, "text": _message}); + io.of(IONameSpace).emit('status_text', { "sysid": message._header.srcSystem, "text": _message}); //io.of(IONameSpace).emit('message', { "sysid": current_vehicle.get('id'), "message": _message}); } } @@ -584,7 +584,7 @@ mavlinkParser2.on('STATUSTEXT', statustext_handler); var att_handler = function(message) { - var current_vehicle = AllVehicles.get(message.header.srcSystem); + var current_vehicle = AllVehicles.get(message._header.srcSystem); // if we already have the vehicle in the collection: if ( current_vehicle) { //console.log(`Got a ATTITUDE message from ${udpserver.last_ip_address.address}:${udpserver.last_ip_address.port} `); @@ -611,7 +611,7 @@ mavlinkParser2.on('ATTITUDE', att_handler); var vfrhud_handler = function(message) { - var current_vehicle = AllVehicles.get(message.header.srcSystem); + var current_vehicle = AllVehicles.get(message._header.srcSystem); // if we already have the vehicle in the collection: if ( current_vehicle) { //console.log(`Got a VFR_HUD message from ${udpserver.last_ip_address.address}:${udpserver.last_ip_address.port} `); @@ -638,7 +638,7 @@ mavlinkParser2.on('VFR_HUD', vfrhud_handler); var gpsrawint_handler = function(message) { - var current_vehicle = AllVehicles.get(message.header.srcSystem); + var current_vehicle = AllVehicles.get(message._header.srcSystem); // if we already have the vehicle in the collection: if ( current_vehicle) { //console.log(`Got a GPS_RAW_INT message from ${udpserver.last_ip_address.address}:${udpserver.last_ip_address.port} `); diff --git a/update_mavlink.sh b/update_mavlink.sh new file mode 100755 index 0000000..5730d4d --- /dev/null +++ b/update_mavlink.sh @@ -0,0 +1 @@ +cp ~/GCS/mavlink/pymavlink/generator/javascript/implementations/mavlink_ardupilotmega_v2.0/mavlink.js ./mav_v2.js From e985fb05ac7ed8f57a356134e728498447646b9d Mon Sep 17 00:00:00 2001 From: Buzz Date: Sat, 10 Apr 2021 17:54:45 +1000 Subject: [PATCH 2/2] bit of a start on copter support... can now render copter/s on-screen, and differentiate between copters and planes and understands copter flight modes..... can't send commands like 'takeoff' or mode change to copters yet tho... --- assets/mavFlightMode.js | 13 +- mav_v1.js | 2777 ++++-- mav_v2.js | 16388 ++++++++++++++++----------------- node_index.html | 2 +- static/img/copter.svg | 1 + static/img/copter_black.png | Bin 0 -> 26844 bytes static/img/copter_blue.png | Bin 0 -> 28563 bytes static/img/copter_green.png | Bin 0 -> 28517 bytes static/img/copter_indigo.png | Bin 0 -> 28725 bytes static/img/copter_orange.png | Bin 0 -> 28550 bytes static/img/copter_purple.png | Bin 0 -> 28632 bytes static/img/copter_red.png | Bin 0 -> 28692 bytes static/img/copter_red_a.png | Bin 0 -> 52687 bytes static/js/leaflet-stuff.js | 23 +- static/js/main.js | 61 +- static/js/mav-stuff.js | 25 +- 16 files changed, 10223 insertions(+), 9067 deletions(-) create mode 100644 static/img/copter.svg create mode 100644 static/img/copter_black.png create mode 100644 static/img/copter_blue.png create mode 100644 static/img/copter_green.png create mode 100644 static/img/copter_indigo.png create mode 100644 static/img/copter_orange.png create mode 100644 static/img/copter_purple.png create mode 100644 static/img/copter_red.png create mode 100644 static/img/copter_red_a.png diff --git a/assets/mavFlightMode.js b/assets/mavFlightMode.js index 085c177..0be5e2c 100644 --- a/assets/mavFlightMode.js +++ b/assets/mavFlightMode.js @@ -102,8 +102,17 @@ MavFlightMode.prototype.attachHandlers = function(sysid,mavlink,mavlinkParser,st // Translate the bitfields for use in the client. - // arduplane uses packet.custom_mode to index into mode_mapping_apm - TODO copter uses acm - newState.mode = mode_mapping_apm[heartbeat.custom_mode]; + + //copter or plane or something else? + if (heartbeat.type == mavlink20.MAV_TYPE_FIXED_WING ) { + // arduplane uses packet.custom_mode to index into mode_mapping_apm + newState.mode = mode_mapping_apm[heartbeat.custom_mode]; + } + if (heartbeat.type == mavlink20.MAV_TYPE_QUADROTOR ) { + // arducopter uses packet.custom_mode to index into mode_mapping_acm + newState.mode = mode_mapping_acm[heartbeat.custom_mode]; + } + //console.log("ardumode:"+newState.mode); newState.armed = ( mavlink.MAV_MODE_FLAG_SAFETY_ARMED & heartbeat.base_mode ) ? true : false; diff --git a/mav_v1.js b/mav_v1.js index 14eeb81..b6c8000 100644 --- a/mav_v1.js +++ b/mav_v1.js @@ -1,7 +1,7 @@ /* MAVLink protocol implementation for node.js (auto-generated by mavgen_javascript.py) -Generated from: ardupilotmega.xml,common.xml,uAvionix.xml,icarous.xml +Generated from: ardupilotmega.xml,common.xml,uAvionix.xml,icarous.xml,minimal.xml Note: this file has been auto-generated. DO NOT EDIT */ @@ -18,7 +18,7 @@ Buffer.prototype.toByteArray = function () { mavlink10 = function(){}; -// Implement the X25CRC function (present in the Python version through the mavutil.py package) +// Implement the CRC-16/MCRF4XX function (present in the Python version through the mavutil.py package) mavlink10.x25Crc = function(buffer, crcIN) { var bytes = buffer; @@ -110,14 +110,35 @@ mavlink10.ACCELCAL_VEHICLE_POS_SUCCESS = 16777215 // mavlink10.ACCELCAL_VEHICLE_POS_FAILED = 16777216 // mavlink10.ACCELCAL_VEHICLE_POS_ENUM_END = 16777217 // +// HEADING_TYPE +mavlink10.HEADING_TYPE_COURSE_OVER_GROUND = 0 // +mavlink10.HEADING_TYPE_HEADING = 1 // +mavlink10.HEADING_TYPE_ENUM_END = 2 // + +// SPEED_TYPE +mavlink10.SPEED_TYPE_AIRSPEED = 0 // +mavlink10.SPEED_TYPE_GROUNDSPEED = 1 // +mavlink10.SPEED_TYPE_ENUM_END = 2 // + // MAV_CMD mavlink10.MAV_CMD_NAV_WAYPOINT = 16 // Navigate to waypoint. mavlink10.MAV_CMD_NAV_LOITER_UNLIM = 17 // Loiter around this waypoint an unlimited amount of time mavlink10.MAV_CMD_NAV_LOITER_TURNS = 18 // Loiter around this waypoint for X turns -mavlink10.MAV_CMD_NAV_LOITER_TIME = 19 // Loiter around this waypoint for X seconds +mavlink10.MAV_CMD_NAV_LOITER_TIME = 19 // Loiter at the specified latitude, longitude and altitude for a certain + // amount of time. Multicopter vehicles stop + // at the point (within a vehicle-specific + // acceptance radius). Forward-only moving + // vehicles (e.g. fixed-wing) circle the point + // with the specified radius/direction. If the + // Heading Required parameter (2) is non-zero + // forward moving aircraft will only leave the + // loiter circle once heading towards the next + // waypoint. mavlink10.MAV_CMD_NAV_RETURN_TO_LAUNCH = 20 // Return to launch location mavlink10.MAV_CMD_NAV_LAND = 21 // Land at location. -mavlink10.MAV_CMD_NAV_TAKEOFF = 22 // Takeoff from ground / hand +mavlink10.MAV_CMD_NAV_TAKEOFF = 22 // Takeoff from ground / hand. Vehicles that support multiple takeoff + // modes (e.g. VTOL quadplane) should take off + // using the currently configured mode. mavlink10.MAV_CMD_NAV_LAND_LOCAL = 23 // Land at local position (local frame only) mavlink10.MAV_CMD_NAV_TAKEOFF_LOCAL = 24 // Takeoff from local position (local frame only) mavlink10.MAV_CMD_NAV_FOLLOW = 25 // Vehicle following, i.e. this waypoint represents the position of a @@ -131,15 +152,18 @@ mavlink10.MAV_CMD_NAV_LOITER_TO_ALT = 31 // Begin loiter at the specified Latitu // then loiter at the current position. Don't // consider the navigation command complete // (don't leave loiter) until the altitude has - // been reached. Additionally, if the Heading - // Required parameter is non-zero the - // aircraft will not leave the loiter until - // heading toward the next waypoint. + // been reached. Additionally, if the Heading + // Required parameter is non-zero the aircraft + // will not leave the loiter until heading + // toward the next waypoint. mavlink10.MAV_CMD_DO_FOLLOW = 32 // Begin following a target mavlink10.MAV_CMD_DO_FOLLOW_REPOSITION = 33 // Reposition the MAV after a follow target command has been sent +mavlink10.MAV_CMD_DO_ORBIT = 34 // Start orbiting on the circumference of a circle defined by the + // parameters. Setting any value NaN results + // in using defaults. mavlink10.MAV_CMD_NAV_ROI = 80 // Sets the region of interest (ROI) for a sensor set or the vehicle // itself. This can then be used by the - // vehicles control system to control the + // vehicle's control system to control the // vehicle attitude and the attitude of // various sensors such as cameras. mavlink10.MAV_CMD_NAV_PATHPLANNING = 81 // Control autonomous path planning on the MAV. @@ -154,7 +178,10 @@ mavlink10.MAV_CMD_NAV_ALTITUDE_WAIT = 83 // Mission command to wait for an altit // control surfaces to prevent them seizing // up. mavlink10.MAV_CMD_NAV_VTOL_TAKEOFF = 84 // Takeoff from ground using VTOL mode, and transition to forward flight - // with specified heading. + // with specified heading. The command should + // be ignored by vehicles that dont support + // both VTOL and fixed-wing flight + // (multicopters, boats,etc.). mavlink10.MAV_CMD_NAV_VTOL_LAND = 85 // Land using VTOL mode mavlink10.MAV_CMD_NAV_GUIDED_ENABLE = 92 // hand control over to an external controller mavlink10.MAV_CMD_NAV_DELAY = 93 // Delay the next navigation command a number of seconds or until a @@ -169,8 +196,9 @@ mavlink10.MAV_CMD_NAV_PAYLOAD_PLACE = 94 // Descend and place payload. Vehicle m mavlink10.MAV_CMD_NAV_LAST = 95 // NOP - This command is only used to mark the upper limit of the // NAV/ACTION commands in the enumeration mavlink10.MAV_CMD_CONDITION_DELAY = 112 // Delay mission state machine. -mavlink10.MAV_CMD_CONDITION_CHANGE_ALT = 113 // Ascend/descend at rate. Delay mission state machine until desired - // altitude reached. +mavlink10.MAV_CMD_CONDITION_CHANGE_ALT = 113 // Ascend/descend to target altitude at specified rate. Delay mission + // state machine until desired altitude + // reached. mavlink10.MAV_CMD_CONDITION_DISTANCE = 114 // Delay mission state machine until within desired distance of next NAV // point. mavlink10.MAV_CMD_CONDITION_YAW = 115 // Reach a certain target angle. @@ -193,6 +221,11 @@ mavlink10.MAV_CMD_DO_REPEAT_SERVO = 184 // Cycle a between its nominal setting a // number of cycles with a desired period. mavlink10.MAV_CMD_DO_FLIGHTTERMINATION = 185 // Terminate flight immediately mavlink10.MAV_CMD_DO_CHANGE_ALTITUDE = 186 // Change altitude set point. +mavlink10.MAV_CMD_DO_SET_ACTUATOR = 187 // Sets actuators (e.g. servos) to a desired value. The actuator numbers + // are mapped to specific outputs (e.g. on any + // MAIN or AUX PWM or UAVCAN) using a flight- + // stack specific mechanism (i.e. a + // parameter). mavlink10.MAV_CMD_DO_LAND_START = 189 // Mission command to perform a landing. This is used as a marker in a // mission to tell the autopilot where a // sequence of mission items that represents a @@ -211,28 +244,44 @@ mavlink10.MAV_CMD_DO_PAUSE_CONTINUE = 193 // If in a GPS controlled position mod // continue. mavlink10.MAV_CMD_DO_SET_REVERSE = 194 // Set moving direction to forward or reverse. mavlink10.MAV_CMD_DO_SET_ROI_LOCATION = 195 // Sets the region of interest (ROI) to a location. This can then be used - // by the vehicles control system to control + // by the vehicle's control system to control // the vehicle attitude and the attitude of - // various sensors such as cameras. + // various sensors such as cameras. This + // command can be sent to a gimbal manager but + // not to a gimbal device. A gimbal is not to + // react to this message. mavlink10.MAV_CMD_DO_SET_ROI_WPNEXT_OFFSET = 196 // Sets the region of interest (ROI) to be toward next waypoint, with // optional pitch/roll/yaw offset. This can - // then be used by the vehicles control system - // to control the vehicle attitude and the - // attitude of various sensors such as - // cameras. + // then be used by the vehicle's control + // system to control the vehicle attitude and + // the attitude of various sensors such as + // cameras. This command can be sent to a + // gimbal manager but not to a gimbal device. + // A gimbal device is not to react to this + // message. mavlink10.MAV_CMD_DO_SET_ROI_NONE = 197 // Cancels any previous ROI command returning the vehicle/sensors to // default flight characteristics. This can - // then be used by the vehicles control system - // to control the vehicle attitude and the - // attitude of various sensors such as - // cameras. + // then be used by the vehicle's control + // system to control the vehicle attitude and + // the attitude of various sensors such as + // cameras. This command can be sent to a + // gimbal manager but not to a gimbal device. + // A gimbal device is not to react to this + // message. After this command the gimbal + // manager should go back to manual input if + // available, and otherwise assume a neutral + // position. mavlink10.MAV_CMD_DO_SET_ROI_SYSID = 198 // Mount tracks system with specified system ID. Determination of target // vehicle position may be done with // GLOBAL_POSITION_INT or any other means. + // This command can be sent to a gimbal + // manager but not to a gimbal device. A + // gimbal device is not to react to this + // message. mavlink10.MAV_CMD_DO_CONTROL_VIDEO = 200 // Control onboard camera system. mavlink10.MAV_CMD_DO_SET_ROI = 201 // Sets the region of interest (ROI) for a sensor set or the vehicle // itself. This can then be used by the - // vehicles control system to control the + // vehicle's control system to control the // vehicle attitude and the attitude of // various sensors such as cameras. mavlink10.MAV_CMD_DO_DIGICAM_CONFIGURE = 202 // Configure digital camera. This is a fallback message for systems that @@ -253,10 +302,11 @@ mavlink10.MAV_CMD_DO_SET_CAM_TRIGG_DIST = 206 // Mission command to set camera t // to set the shutter integration time for the // camera. mavlink10.MAV_CMD_DO_FENCE_ENABLE = 207 // Mission command to enable the geofence -mavlink10.MAV_CMD_DO_PARACHUTE = 208 // Mission command to trigger a parachute +mavlink10.MAV_CMD_DO_PARACHUTE = 208 // Mission item/command to release a parachute or enable/disable auto + // release. mavlink10.MAV_CMD_DO_MOTOR_TEST = 209 // Mission command to perform motor test. mavlink10.MAV_CMD_DO_INVERTED_FLIGHT = 210 // Change to/from inverted flight. -mavlink10.MAV_CMD_DO_GRIPPER = 211 // Mission command to operate EPM gripper. +mavlink10.MAV_CMD_DO_GRIPPER = 211 // Mission command to operate a gripper. mavlink10.MAV_CMD_DO_AUTOTUNE_ENABLE = 212 // Enable/disable autotune. mavlink10.MAV_CMD_NAV_SET_YAW_SPEED = 213 // Sets a desired vehicle turn angle and speed change. mavlink10.MAV_CMD_DO_SET_CAM_TRIGG_INTERVAL = 214 // Mission command to set camera trigger interval for this flight. If @@ -264,6 +314,8 @@ mavlink10.MAV_CMD_DO_SET_CAM_TRIGG_INTERVAL = 214 // Mission command to set came // triggered each time this interval expires. // This command can also be used to set the // shutter integration time for the camera. +mavlink10.MAV_CMD_DO_SET_RESUME_REPEAT_DIST = 215 // Set the distance to be repeated on mission resume +mavlink10.MAV_CMD_DO_SPRAYER = 216 // Control attached liquid sprayer mavlink10.MAV_CMD_DO_MOUNT_CONTROL_QUAT = 220 // Mission command to control a camera or antenna mount, using a // quaternion as reference. mavlink10.MAV_CMD_DO_GUIDED_MASTER = 221 // set id of master controller @@ -285,21 +337,57 @@ mavlink10.MAV_CMD_PREFLIGHT_CALIBRATION = 241 // Trigger calibration. This comma // be zero. mavlink10.MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS = 242 // Set sensor offsets. This command will be only accepted if in pre- // flight mode. -mavlink10.MAV_CMD_PREFLIGHT_UAVCAN = 243 // Trigger UAVCAN config. This command will be only accepted if in pre- - // flight mode. +mavlink10.MAV_CMD_PREFLIGHT_UAVCAN = 243 // Trigger UAVCAN configuration (actuator ID assignment and direction + // mapping). Note that this maps to the legacy + // UAVCAN v0 function UAVCAN_ENUMERATE, which + // is intended to be executed just once during + // initial vehicle configuration (it is not a + // normal pre-flight command and has been + // poorly named). mavlink10.MAV_CMD_PREFLIGHT_STORAGE = 245 // Request storage of different parameter values and logs. This command // will be only accepted if in pre-flight // mode. mavlink10.MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN = 246 // Request the reboot or shutdown of system components. +mavlink10.MAV_CMD_DO_UPGRADE = 247 // Request a target system to start an upgrade of one (or all) of its + // components. For example, the command might + // be sent to a companion computer to cause it + // to upgrade a connected flight controller. + // The system doing the upgrade will report + // progress using the normal command protocol + // sequence for a long running operation. + // Command protocol information: https://mavli + // nk.io/en/services/command.html. mavlink10.MAV_CMD_OVERRIDE_GOTO = 252 // Override current mission with command to pause mission, pause mission // and move to position, continue/resume // mission. When param 1 indicates that the // mission is paused (MAV_GOTO_DO_HOLD), param // 2 defines whether it holds in place or // moves to another position. +mavlink10.MAV_CMD_OBLIQUE_SURVEY = 260 // Mission command to set a Camera Auto Mount Pivoting Oblique Survey + // (Replaces CAM_TRIGG_DIST for this purpose). + // The camera is triggered each time this + // distance is exceeded, then the mount moves + // to the next position. Params 4~6 set-up the + // angle limits and number of positions for + // oblique survey, where mount-enabled + // vehicles automatically roll the camera + // between shots to emulate an oblique camera + // setup (providing an increased HFOV). This + // command can also be used to set the shutter + // integration time for the camera. mavlink10.MAV_CMD_MISSION_START = 300 // start running a mission mavlink10.MAV_CMD_COMPONENT_ARM_DISARM = 400 // Arms / Disarms a component +mavlink10.MAV_CMD_ILLUMINATOR_ON_OFF = 405 // Turns illuminators ON/OFF. An illuminator is a light source that is + // used for lighting up dark areas external to + // the sytstem: e.g. a torch or searchlight + // (as opposed to a light source for + // illuminating the system itself, e.g. an + // indicator light). mavlink10.MAV_CMD_GET_HOME_POSITION = 410 // Request the home position from the vehicle. +mavlink10.MAV_CMD_INJECT_FAILURE = 420 // Inject artificial failure for testing purposes. Note that autopilots + // should implement an additional protection + // before accepting this command such as a + // specific param setting. mavlink10.MAV_CMD_START_RX_PAIR = 500 // Starts receiver pairing. mavlink10.MAV_CMD_GET_MESSAGE_INTERVAL = 510 // Request the interval between messages for a particular MAVLink message // ID. The receiver should ACK the command and @@ -311,6 +399,9 @@ mavlink10.MAV_CMD_SET_MESSAGE_INTERVAL = 511 // Set the interval between message mavlink10.MAV_CMD_REQUEST_MESSAGE = 512 // Request the target system(s) emit a single instance of a specified // message (i.e. a "one-shot" version of // MAV_CMD_SET_MESSAGE_INTERVAL). +mavlink10.MAV_CMD_REQUEST_PROTOCOL_VERSION = 519 // Request MAVLink protocol version compatibility. All receivers should + // ACK the command and then emit their + // capabilities in an PROTOCOL_VERSION message mavlink10.MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES = 520 // Request autopilot capabilities. The receiver should ACK the command // and then emit its capabilities in an // AUTOPILOT_VERSION message @@ -330,6 +421,10 @@ mavlink10.MAV_CMD_SET_CAMERA_MODE = 530 // Set camera running mode. Use NaN for // MAV_CMD_REQUEST_VIDEO_STREAM_STATUS command // after a mode change if the camera supports // video streaming. +mavlink10.MAV_CMD_SET_CAMERA_ZOOM = 531 // Set camera zoom. Camera must respond with a CAMERA_SETTINGS message + // (on success). +mavlink10.MAV_CMD_SET_CAMERA_FOCUS = 532 // Set camera focus. Camera must respond with a CAMERA_SETTINGS message + // (on success). mavlink10.MAV_CMD_JUMP_TAG = 600 // Tagged jump target. Can be jumped to with MAV_CMD_DO_JUMP_TAG. mavlink10.MAV_CMD_DO_JUMP_TAG = 601 // Jump to the matching tag in the mission list. Repeat this action for // the specified number of times. A mission @@ -340,13 +435,45 @@ mavlink10.MAV_CMD_DO_JUMP_TAG = 601 // Jump to the matching tag in the mission l // multiple matching tags should always select // the one with the lowest mission sequence // number. +mavlink10.MAV_CMD_PARAM_TRANSACTION = 900 // Request to start or end a parameter transaction. Multiple kinds of + // transport layers can be used to exchange + // parameters in the transaction (param, + // param_ext and mavftp). The command response + // can either be a success/failure or an in + // progress in case the receiving side takes + // some time to apply the parameters. +mavlink10.MAV_CMD_DO_GIMBAL_MANAGER_PITCHYAW = 1000 // High level setpoint to be sent to a gimbal manager to set a gimbal + // attitude. It is possible to set + // combinations of the values below. E.g. an + // angle as well as a desired angular rate can + // be used to get to this angle at a certain + // angular rate, or an angular rate only will + // result in continuous turning. NaN is to be + // used to signal unset. Note: a gimbal is + // never to react to this command but only the + // gimbal manager. +mavlink10.MAV_CMD_DO_GIMBAL_MANAGER_CONFIGURE = 1001 // Gimbal configuration to set which sysid/compid is in primary and + // secondary control. mavlink10.MAV_CMD_IMAGE_START_CAPTURE = 2000 // Start image capture sequence. Sends CAMERA_IMAGE_CAPTURED after each // capture. Use NaN for reserved values. mavlink10.MAV_CMD_IMAGE_STOP_CAPTURE = 2001 // Stop image capture sequence Use NaN for reserved values. +mavlink10.MAV_CMD_REQUEST_CAMERA_IMAGE_CAPTURE = 2002 // Re-request a CAMERA_IMAGE_CAPTURED message. mavlink10.MAV_CMD_DO_TRIGGER_CONTROL = 2003 // Enable or disable on-board camera triggering system. -mavlink10.MAV_CMD_VIDEO_START_CAPTURE = 2500 // Starts video capture (recording). Use NaN for reserved values. -mavlink10.MAV_CMD_VIDEO_STOP_CAPTURE = 2501 // Stop the current video capture (recording). Use NaN for reserved - // values. +mavlink10.MAV_CMD_CAMERA_TRACK_POINT = 2004 // If the camera supports point visual tracking + // (CAMERA_CAP_FLAGS_HAS_TRACKING_POINT is + // set), this command allows to initiate the + // tracking. +mavlink10.MAV_CMD_CAMERA_TRACK_RECTANGLE = 2005 // If the camera supports rectangle visual tracking + // (CAMERA_CAP_FLAGS_HAS_TRACKING_RECTANGLE is + // set), this command allows to initiate the + // tracking. +mavlink10.MAV_CMD_CAMERA_STOP_TRACKING = 2010 // Stops ongoing tracking. +mavlink10.MAV_CMD_VIDEO_START_CAPTURE = 2500 // Starts video capture (recording). +mavlink10.MAV_CMD_VIDEO_STOP_CAPTURE = 2501 // Stop the current video capture (recording). +mavlink10.MAV_CMD_VIDEO_START_STREAMING = 2502 // Start video streaming +mavlink10.MAV_CMD_VIDEO_STOP_STREAMING = 2503 // Stop the given video stream +mavlink10.MAV_CMD_REQUEST_VIDEO_STREAM_INFORMATION = 2504 // Request video stream information (VIDEO_STREAM_INFORMATION) +mavlink10.MAV_CMD_REQUEST_VIDEO_STREAM_STATUS = 2505 // Request video stream status (VIDEO_STREAM_STATUS) mavlink10.MAV_CMD_LOGGING_START = 2510 // Request to start streaming logging data over MAVLink (see also // LOGGING_DATA message) mavlink10.MAV_CMD_LOGGING_STOP = 2511 // Request to stop streaming log data over MAVLink @@ -374,7 +501,10 @@ mavlink10.MAV_CMD_SET_GUIDED_SUBMODE_CIRCLE = 4001 // This command sets submode // the velocity along the circle and change // the radius. If no input is given the // vehicle will hold position. -mavlink10.MAV_CMD_NAV_FENCE_RETURN_POINT = 5000 // Fence return point. There can only be one fence return point. +mavlink10.MAV_CMD_CONDITION_GATE = 4501 // Delay mission state machine until gate has been reached. +mavlink10.MAV_CMD_NAV_FENCE_RETURN_POINT = 5000 // Fence return point (there can only be one such point in a geofence + // definition). If rally points are supported + // they should be used instead. mavlink10.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION = 5001 // Fence vertex for an inclusion polygon (the polygon must not be self- // intersecting). The vehicle must stay within // this area. Minimum of 3 vertices required. @@ -447,8 +577,7 @@ mavlink10.MAV_CMD_SOLO_BTN_PAUSE_CLICK = 42003 // PAUSE button has been clicked. mavlink10.MAV_CMD_FIXED_MAG_CAL = 42004 // Magnetometer calibration based on fixed position in earth // field given by inclination, declination and // intensity. -mavlink10.MAV_CMD_FIXED_MAG_CAL_FIELD = 42005 // Magnetometer calibration based on fixed expected field values in - // milliGauss. +mavlink10.MAV_CMD_FIXED_MAG_CAL_FIELD = 42005 // Magnetometer calibration based on fixed expected field values. mavlink10.MAV_CMD_FIXED_MAG_CAL_YAW = 42006 // Magnetometer calibration based on provided known yaw. This allows for // fast calibration using WMM field tables in // the vehicle, given only the known yaw of @@ -456,7 +585,7 @@ mavlink10.MAV_CMD_FIXED_MAG_CAL_YAW = 42006 // Magnetometer calibration based on // both zero then use the current vehicle // location. mavlink10.MAV_CMD_DO_START_MAG_CAL = 42424 // Initiate a magnetometer calibration. -mavlink10.MAV_CMD_DO_ACCEPT_MAG_CAL = 42425 // Initiate a magnetometer calibration. +mavlink10.MAV_CMD_DO_ACCEPT_MAG_CAL = 42425 // Accept a magnetometer calibration. mavlink10.MAV_CMD_DO_CANCEL_MAG_CAL = 42426 // Cancel a running magnetometer calibration. mavlink10.MAV_CMD_SET_FACTORY_TEST_MODE = 42427 // Command autopilot to get into factory test/diagnostic mode. mavlink10.MAV_CMD_DO_SEND_BANNER = 42428 // Reply with the version banner. @@ -473,7 +602,38 @@ mavlink10.MAV_CMD_DO_WINCH = 42600 // Command to operate winch. mavlink10.MAV_CMD_FLASH_BOOTLOADER = 42650 // Update the bootloader mavlink10.MAV_CMD_BATTERY_RESET = 42651 // Reset battery capacity for batteries that accumulate consumed battery // via integration. -mavlink10.MAV_CMD_ENUM_END = 42652 // +mavlink10.MAV_CMD_DEBUG_TRAP = 42700 // Issue a trap signal to the autopilot process, presumably to enter the + // debugger. +mavlink10.MAV_CMD_SCRIPTING = 42701 // Control onboard scripting. +mavlink10.MAV_CMD_GUIDED_CHANGE_SPEED = 43000 // Change flight speed at a given rate. This slews the vehicle at a + // controllable rate between it's previous + // speed and the new one. (affects GUIDED + // only. Outside GUIDED, aircraft ignores + // these commands. Designed for onboard + // companion-computer command-and-control, not + // normally operator/GCS control.) +mavlink10.MAV_CMD_GUIDED_CHANGE_ALTITUDE = 43001 // Change target altitude at a given rate. This slews the vehicle at a + // controllable rate between it's previous + // altitude and the new one. (affects GUIDED + // only. Outside GUIDED, aircraft ignores + // these commands. Designed for onboard + // companion-computer command-and-control, not + // normally operator/GCS control.) +mavlink10.MAV_CMD_GUIDED_CHANGE_HEADING = 43002 // Change to target heading at a given rate, overriding previous + // heading/s. This slews the vehicle at a + // controllable rate between it's previous + // heading and the new one. (affects GUIDED + // only. Exiting GUIDED returns aircraft to + // normal behaviour defined elsewhere. + // Designed for onboard companion-computer + // command-and-control, not normally + // operator/GCS control.) +mavlink10.MAV_CMD_ENUM_END = 43003 // + +// SCRIPTING_CMD +mavlink10.SCRIPTING_CMD_REPL_START = 0 // Start a REPL session. +mavlink10.SCRIPTING_CMD_REPL_STOP = 1 // End a REPL session. +mavlink10.SCRIPTING_CMD_ENUM_END = 2 // // LIMITS_STATE mavlink10.LIMITS_INIT = 0 // Pre-initialization. @@ -498,18 +658,6 @@ mavlink10.LAND_IMMEDIATELY = 2 // Flag set when plane is to immediately descend // until commanded to land. mavlink10.RALLY_FLAGS_ENUM_END = 3 // -// GRIPPER_ACTIONS -mavlink10.GRIPPER_ACTION_RELEASE = 0 // Gripper release cargo. -mavlink10.GRIPPER_ACTION_GRAB = 1 // Gripper grab onto cargo. -mavlink10.GRIPPER_ACTIONS_ENUM_END = 2 // - -// WINCH_ACTIONS -mavlink10.WINCH_RELAXED = 0 // Relax winch. -mavlink10.WINCH_RELATIVE_LENGTH_CONTROL = 1 // Winch unwinds or winds specified length of cable optionally using - // specified rate. -mavlink10.WINCH_RATE_CONTROL = 2 // Winch unwinds or winds cable at specified rate in meters/seconds. -mavlink10.WINCH_ACTIONS_ENUM_END = 3 // - // CAMERA_STATUS_TYPES mavlink10.CAMERA_STATUS_TYPE_HEARTBEAT = 0 // Camera heartbeat, announce camera component ID at 1Hz. mavlink10.CAMERA_STATUS_TYPE_TRIGGER = 1 // Camera image triggered. @@ -762,7 +910,8 @@ mavlink10.EKF_PRED_POS_HORIZ_REL = 256 // Set if EKF's predicted horizontal posi // good. mavlink10.EKF_PRED_POS_HORIZ_ABS = 512 // Set if EKF's predicted horizontal position (absolute) estimate is // good. -mavlink10.EKF_STATUS_FLAGS_ENUM_END = 513 // +mavlink10.EKF_UNINITIALIZED = 1024 // Set if EKF has never been healthy. +mavlink10.EKF_STATUS_FLAGS_ENUM_END = 1025 // // PID_TUNING_AXIS mavlink10.PID_TUNING_ROLL = 1 // @@ -773,17 +922,6 @@ mavlink10.PID_TUNING_STEER = 5 // mavlink10.PID_TUNING_LANDING = 6 // mavlink10.PID_TUNING_AXIS_ENUM_END = 7 // -// MAG_CAL_STATUS -mavlink10.MAG_CAL_NOT_STARTED = 0 // -mavlink10.MAG_CAL_WAITING_TO_START = 1 // -mavlink10.MAG_CAL_RUNNING_STEP_ONE = 2 // -mavlink10.MAG_CAL_RUNNING_STEP_TWO = 3 // -mavlink10.MAG_CAL_SUCCESS = 4 // -mavlink10.MAG_CAL_FAILED = 5 // -mavlink10.MAG_CAL_BAD_ORIENTATION = 6 // -mavlink10.MAG_CAL_BAD_RADIUS = 7 // -mavlink10.MAG_CAL_STATUS_ENUM_END = 8 // - // MAV_REMOTE_LOG_DATA_BLOCK_COMMANDS mavlink10.MAV_REMOTE_LOG_DATA_BLOCK_STOP = 2147483645 // UAV to stop sending DataFlash blocks. mavlink10.MAV_REMOTE_LOG_DATA_BLOCK_START = 2147483646 // UAV to start sending DataFlash blocks. @@ -832,7 +970,9 @@ mavlink10.PLANE_MODE_QLOITER = 19 // mavlink10.PLANE_MODE_QLAND = 20 // mavlink10.PLANE_MODE_QRTL = 21 // mavlink10.PLANE_MODE_QAUTOTUNE = 22 // -mavlink10.PLANE_MODE_ENUM_END = 23 // +mavlink10.PLANE_MODE_QACRO = 23 // +mavlink10.PLANE_MODE_THERMAL = 24 // +mavlink10.PLANE_MODE_ENUM_END = 25 // // COPTER_MODE mavlink10.COPTER_MODE_STABILIZE = 0 // @@ -854,7 +994,12 @@ mavlink10.COPTER_MODE_THROW = 18 // mavlink10.COPTER_MODE_AVOID_ADSB = 19 // mavlink10.COPTER_MODE_GUIDED_NOGPS = 20 // mavlink10.COPTER_MODE_SMART_RTL = 21 // -mavlink10.COPTER_MODE_ENUM_END = 22 // +mavlink10.COPTER_MODE_FLOWHOLD = 22 // +mavlink10.COPTER_MODE_FOLLOW = 23 // +mavlink10.COPTER_MODE_ZIGZAG = 24 // +mavlink10.COPTER_MODE_SYSTEMID = 25 // +mavlink10.COPTER_MODE_AUTOROTATE = 26 // +mavlink10.COPTER_MODE_ENUM_END = 27 // // SUB_MODE mavlink10.SUB_MODE_STABILIZE = 0 // @@ -874,6 +1019,8 @@ mavlink10.ROVER_MODE_ACRO = 1 // mavlink10.ROVER_MODE_STEERING = 3 // mavlink10.ROVER_MODE_HOLD = 4 // mavlink10.ROVER_MODE_LOITER = 5 // +mavlink10.ROVER_MODE_FOLLOW = 6 // +mavlink10.ROVER_MODE_SIMPLE = 7 // mavlink10.ROVER_MODE_AUTO = 10 // mavlink10.ROVER_MODE_RTL = 11 // mavlink10.ROVER_MODE_SMART_RTL = 12 // @@ -890,68 +1037,24 @@ mavlink10.TRACKER_MODE_AUTO = 10 // mavlink10.TRACKER_MODE_INITIALIZING = 16 // mavlink10.TRACKER_MODE_ENUM_END = 17 // -// MAV_AUTOPILOT -mavlink10.MAV_AUTOPILOT_GENERIC = 0 // Generic autopilot, full support for everything -mavlink10.MAV_AUTOPILOT_RESERVED = 1 // Reserved for future use. -mavlink10.MAV_AUTOPILOT_SLUGS = 2 // SLUGS autopilot, http://slugsuav.soe.ucsc.edu -mavlink10.MAV_AUTOPILOT_ARDUPILOTMEGA = 3 // ArduPilot - Plane/Copter/Rover/Sub/Tracker, http://ardupilot.org -mavlink10.MAV_AUTOPILOT_OPENPILOT = 4 // OpenPilot, http://openpilot.org -mavlink10.MAV_AUTOPILOT_GENERIC_WAYPOINTS_ONLY = 5 // Generic autopilot only supporting simple waypoints -mavlink10.MAV_AUTOPILOT_GENERIC_WAYPOINTS_AND_SIMPLE_NAVIGATION_ONLY = 6 // Generic autopilot supporting waypoints and other simple navigation - // commands -mavlink10.MAV_AUTOPILOT_GENERIC_MISSION_FULL = 7 // Generic autopilot supporting the full mission command set -mavlink10.MAV_AUTOPILOT_INVALID = 8 // No valid autopilot, e.g. a GCS or other MAVLink component -mavlink10.MAV_AUTOPILOT_PPZ = 9 // PPZ UAV - http://nongnu.org/paparazzi -mavlink10.MAV_AUTOPILOT_UDB = 10 // UAV Dev Board -mavlink10.MAV_AUTOPILOT_FP = 11 // FlexiPilot -mavlink10.MAV_AUTOPILOT_PX4 = 12 // PX4 Autopilot - http://px4.io/ -mavlink10.MAV_AUTOPILOT_SMACCMPILOT = 13 // SMACCMPilot - http://smaccmpilot.org -mavlink10.MAV_AUTOPILOT_AUTOQUAD = 14 // AutoQuad -- http://autoquad.org -mavlink10.MAV_AUTOPILOT_ARMAZILA = 15 // Armazila -- http://armazila.com -mavlink10.MAV_AUTOPILOT_AEROB = 16 // Aerob -- http://aerob.ru -mavlink10.MAV_AUTOPILOT_ASLUAV = 17 // ASLUAV autopilot -- http://www.asl.ethz.ch -mavlink10.MAV_AUTOPILOT_SMARTAP = 18 // SmartAP Autopilot - http://sky-drones.com -mavlink10.MAV_AUTOPILOT_AIRRAILS = 19 // AirRails - http://uaventure.com -mavlink10.MAV_AUTOPILOT_ENUM_END = 20 // - -// MAV_TYPE -mavlink10.MAV_TYPE_GENERIC = 0 // Generic micro air vehicle -mavlink10.MAV_TYPE_FIXED_WING = 1 // Fixed wing aircraft. -mavlink10.MAV_TYPE_QUADROTOR = 2 // Quadrotor -mavlink10.MAV_TYPE_COAXIAL = 3 // Coaxial helicopter -mavlink10.MAV_TYPE_HELICOPTER = 4 // Normal helicopter with tail rotor. -mavlink10.MAV_TYPE_ANTENNA_TRACKER = 5 // Ground installation -mavlink10.MAV_TYPE_GCS = 6 // Operator control unit / ground control station -mavlink10.MAV_TYPE_AIRSHIP = 7 // Airship, controlled -mavlink10.MAV_TYPE_FREE_BALLOON = 8 // Free balloon, uncontrolled -mavlink10.MAV_TYPE_ROCKET = 9 // Rocket -mavlink10.MAV_TYPE_GROUND_ROVER = 10 // Ground rover -mavlink10.MAV_TYPE_SURFACE_BOAT = 11 // Surface vessel, boat, ship -mavlink10.MAV_TYPE_SUBMARINE = 12 // Submarine -mavlink10.MAV_TYPE_HEXAROTOR = 13 // Hexarotor -mavlink10.MAV_TYPE_OCTOROTOR = 14 // Octorotor -mavlink10.MAV_TYPE_TRICOPTER = 15 // Tricopter -mavlink10.MAV_TYPE_FLAPPING_WING = 16 // Flapping wing -mavlink10.MAV_TYPE_KITE = 17 // Kite -mavlink10.MAV_TYPE_ONBOARD_CONTROLLER = 18 // Onboard companion controller -mavlink10.MAV_TYPE_VTOL_DUOROTOR = 19 // Two-rotor VTOL using control surfaces in vertical operation in - // addition. Tailsitter. -mavlink10.MAV_TYPE_VTOL_QUADROTOR = 20 // Quad-rotor VTOL using a V-shaped quad config in vertical operation. - // Tailsitter. -mavlink10.MAV_TYPE_VTOL_TILTROTOR = 21 // Tiltrotor VTOL -mavlink10.MAV_TYPE_VTOL_RESERVED2 = 22 // VTOL reserved 2 -mavlink10.MAV_TYPE_VTOL_RESERVED3 = 23 // VTOL reserved 3 -mavlink10.MAV_TYPE_VTOL_RESERVED4 = 24 // VTOL reserved 4 -mavlink10.MAV_TYPE_VTOL_RESERVED5 = 25 // VTOL reserved 5 -mavlink10.MAV_TYPE_GIMBAL = 26 // Gimbal -mavlink10.MAV_TYPE_ADSB = 27 // ADSB system -mavlink10.MAV_TYPE_PARAFOIL = 28 // Steerable, nonrigid airfoil -mavlink10.MAV_TYPE_DODECAROTOR = 29 // Dodecarotor -mavlink10.MAV_TYPE_CAMERA = 30 // Camera -mavlink10.MAV_TYPE_CHARGING_STATION = 31 // Charging station -mavlink10.MAV_TYPE_FLARM = 32 // FLARM collision avoidance system -mavlink10.MAV_TYPE_SERVO = 33 // Servo -mavlink10.MAV_TYPE_ENUM_END = 34 // +// OSD_PARAM_CONFIG_TYPE +mavlink10.OSD_PARAM_NONE = 0 // +mavlink10.OSD_PARAM_SERIAL_PROTOCOL = 1 // +mavlink10.OSD_PARAM_SERVO_FUNCTION = 2 // +mavlink10.OSD_PARAM_AUX_FUNCTION = 3 // +mavlink10.OSD_PARAM_FLIGHT_MODE = 4 // +mavlink10.OSD_PARAM_FAILSAFE_ACTION = 5 // +mavlink10.OSD_PARAM_FAILSAFE_ACTION_1 = 6 // +mavlink10.OSD_PARAM_FAILSAFE_ACTION_2 = 7 // +mavlink10.OSD_PARAM_NUM_TYPES = 8 // +mavlink10.OSD_PARAM_CONFIG_TYPE_ENUM_END = 9 // + +// OSD_PARAM_CONFIG_ERROR +mavlink10.OSD_PARAM_SUCCESS = 0 // +mavlink10.OSD_PARAM_INVALID_SCREEN = 1 // +mavlink10.OSD_PARAM_INVALID_PARAMETER_INDEX = 2 // +mavlink10.OSD_PARAM_INVALID_PARAMETER = 3 // +mavlink10.OSD_PARAM_CONFIG_ERROR_ENUM_END = 4 // // FIRMWARE_VERSION_TYPE mavlink10.FIRMWARE_VERSION_TYPE_DEV = 0 // development release @@ -961,42 +1064,23 @@ mavlink10.FIRMWARE_VERSION_TYPE_RC = 192 // release candidate mavlink10.FIRMWARE_VERSION_TYPE_OFFICIAL = 255 // official stable release mavlink10.FIRMWARE_VERSION_TYPE_ENUM_END = 256 // -// MAV_MODE_FLAG -mavlink10.MAV_MODE_FLAG_CUSTOM_MODE_ENABLED = 1 // 0b00000001 Reserved for future use. -mavlink10.MAV_MODE_FLAG_TEST_ENABLED = 2 // 0b00000010 system has a test mode enabled. This flag is intended for - // temporary system tests and should not be - // used for stable implementations. -mavlink10.MAV_MODE_FLAG_AUTO_ENABLED = 4 // 0b00000100 autonomous mode enabled, system finds its own goal - // positions. Guided flag can be set or not, - // depends on the actual implementation. -mavlink10.MAV_MODE_FLAG_GUIDED_ENABLED = 8 // 0b00001000 guided mode enabled, system flies waypoints / mission - // items. -mavlink10.MAV_MODE_FLAG_STABILIZE_ENABLED = 16 // 0b00010000 system stabilizes electronically its attitude (and - // optionally position). It needs however - // further control inputs to move around. -mavlink10.MAV_MODE_FLAG_HIL_ENABLED = 32 // 0b00100000 hardware in the loop simulation. All motors / actuators are - // blocked, but internal software is full - // operational. -mavlink10.MAV_MODE_FLAG_MANUAL_INPUT_ENABLED = 64 // 0b01000000 remote control input is enabled. -mavlink10.MAV_MODE_FLAG_SAFETY_ARMED = 128 // 0b10000000 MAV safety set to armed. Motors are enabled / running / can - // start. Ready to fly. Additional note: this - // flag is to be ignore when sent in the - // command MAV_CMD_DO_SET_MODE and - // MAV_CMD_COMPONENT_ARM_DISARM shall be used - // instead. The flag can still be used to - // report the armed state. -mavlink10.MAV_MODE_FLAG_ENUM_END = 129 // - -// MAV_MODE_FLAG_DECODE_POSITION -mavlink10.MAV_MODE_FLAG_DECODE_POSITION_CUSTOM_MODE = 1 // Eighth bit: 00000001 -mavlink10.MAV_MODE_FLAG_DECODE_POSITION_TEST = 2 // Seventh bit: 00000010 -mavlink10.MAV_MODE_FLAG_DECODE_POSITION_AUTO = 4 // Sixth bit: 00000100 -mavlink10.MAV_MODE_FLAG_DECODE_POSITION_GUIDED = 8 // Fifth bit: 00001000 -mavlink10.MAV_MODE_FLAG_DECODE_POSITION_STABILIZE = 16 // Fourth bit: 00010000 -mavlink10.MAV_MODE_FLAG_DECODE_POSITION_HIL = 32 // Third bit: 00100000 -mavlink10.MAV_MODE_FLAG_DECODE_POSITION_MANUAL = 64 // Second bit: 01000000 -mavlink10.MAV_MODE_FLAG_DECODE_POSITION_SAFETY = 128 // First bit: 10000000 -mavlink10.MAV_MODE_FLAG_DECODE_POSITION_ENUM_END = 129 // +// HL_FAILURE_FLAG +mavlink10.HL_FAILURE_FLAG_GPS = 1 // GPS failure. +mavlink10.HL_FAILURE_FLAG_DIFFERENTIAL_PRESSURE = 2 // Differential pressure sensor failure. +mavlink10.HL_FAILURE_FLAG_ABSOLUTE_PRESSURE = 4 // Absolute pressure sensor failure. +mavlink10.HL_FAILURE_FLAG_3D_ACCEL = 8 // Accelerometer sensor failure. +mavlink10.HL_FAILURE_FLAG_3D_GYRO = 16 // Gyroscope sensor failure. +mavlink10.HL_FAILURE_FLAG_3D_MAG = 32 // Magnetometer sensor failure. +mavlink10.HL_FAILURE_FLAG_TERRAIN = 64 // Terrain subsystem failure. +mavlink10.HL_FAILURE_FLAG_BATTERY = 128 // Battery failure/critical low battery. +mavlink10.HL_FAILURE_FLAG_RC_RECEIVER = 256 // RC receiver failure/no rc connection. +mavlink10.HL_FAILURE_FLAG_OFFBOARD_LINK = 512 // Offboard link failure. +mavlink10.HL_FAILURE_FLAG_ENGINE = 1024 // Engine failure. +mavlink10.HL_FAILURE_FLAG_GEOFENCE = 2048 // Geofence violation. +mavlink10.HL_FAILURE_FLAG_ESTIMATOR = 4096 // Estimator failure, for example measurement rejection or large + // variances. +mavlink10.HL_FAILURE_FLAG_MISSION = 8192 // Mission failure. +mavlink10.HL_FAILURE_FLAG_ENUM_END = 8193 // // MAV_GOTO mavlink10.MAV_GOTO_DO_HOLD = 0 // Hold at the current position. @@ -1031,350 +1115,53 @@ mavlink10.MAV_MODE_AUTO_ARMED = 220 // System is allowed to be active, under aut // waypoints) mavlink10.MAV_MODE_ENUM_END = 221 // -// MAV_STATE -mavlink10.MAV_STATE_UNINIT = 0 // Uninitialized system, state is unknown. -mavlink10.MAV_STATE_BOOT = 1 // System is booting up. -mavlink10.MAV_STATE_CALIBRATING = 2 // System is calibrating and not flight-ready. -mavlink10.MAV_STATE_STANDBY = 3 // System is grounded and on standby. It can be launched any time. -mavlink10.MAV_STATE_ACTIVE = 4 // System is active and might be already airborne. Motors are engaged. -mavlink10.MAV_STATE_CRITICAL = 5 // System is in a non-normal flight mode. It can however still navigate. -mavlink10.MAV_STATE_EMERGENCY = 6 // System is in a non-normal flight mode. It lost control over parts or - // over the whole airframe. It is in mayday - // and going down. -mavlink10.MAV_STATE_POWEROFF = 7 // System just initialized its power-down sequence, will shut down now. -mavlink10.MAV_STATE_FLIGHT_TERMINATION = 8 // System is terminating itself. -mavlink10.MAV_STATE_ENUM_END = 9 // - -// MAV_COMPONENT -mavlink10.MAV_COMP_ID_ALL = 0 // Target id (target_component) used to broadcast messages to all - // components of the receiving system. - // Components should attempt to process - // messages with this component ID and forward - // to components on any other interfaces. - // Note: This is not a valid *source* - // component id for a message. -mavlink10.MAV_COMP_ID_AUTOPILOT1 = 1 // System flight controller component ("autopilot"). Only one autopilot - // is expected in a particular system. -mavlink10.MAV_COMP_ID_USER1 = 25 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER2 = 26 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER3 = 27 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER4 = 28 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER5 = 29 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER6 = 30 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER7 = 31 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER8 = 32 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER9 = 33 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER10 = 34 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER11 = 35 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER12 = 36 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER13 = 37 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER14 = 38 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER15 = 39 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USE16 = 40 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER17 = 41 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER18 = 42 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER19 = 43 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER20 = 44 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER21 = 45 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER22 = 46 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER23 = 47 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER24 = 48 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER25 = 49 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER26 = 50 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER27 = 51 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER28 = 52 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER29 = 53 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER30 = 54 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER31 = 55 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER32 = 56 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER33 = 57 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER34 = 58 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER35 = 59 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER36 = 60 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER37 = 61 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER38 = 62 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER39 = 63 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER40 = 64 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER41 = 65 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER42 = 66 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER43 = 67 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER44 = 68 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER45 = 69 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER46 = 70 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER47 = 71 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER48 = 72 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER49 = 73 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER50 = 74 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER51 = 75 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER52 = 76 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER53 = 77 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER54 = 78 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER55 = 79 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER56 = 80 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER57 = 81 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER58 = 82 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER59 = 83 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER60 = 84 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER61 = 85 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER62 = 86 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER63 = 87 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER64 = 88 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER65 = 89 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER66 = 90 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER67 = 91 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER68 = 92 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER69 = 93 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER70 = 94 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER71 = 95 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER72 = 96 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER73 = 97 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER74 = 98 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_USER75 = 99 // Id for a component on privately managed MAVLink network. Can be used - // for any purpose but may not be published by - // components outside of the private network. -mavlink10.MAV_COMP_ID_CAMERA = 100 // Camera #1. -mavlink10.MAV_COMP_ID_CAMERA2 = 101 // Camera #2. -mavlink10.MAV_COMP_ID_CAMERA3 = 102 // Camera #3. -mavlink10.MAV_COMP_ID_CAMERA4 = 103 // Camera #4. -mavlink10.MAV_COMP_ID_CAMERA5 = 104 // Camera #5. -mavlink10.MAV_COMP_ID_CAMERA6 = 105 // Camera #6. -mavlink10.MAV_COMP_ID_SERVO1 = 140 // Servo #1. -mavlink10.MAV_COMP_ID_SERVO2 = 141 // Servo #2. -mavlink10.MAV_COMP_ID_SERVO3 = 142 // Servo #3. -mavlink10.MAV_COMP_ID_SERVO4 = 143 // Servo #4. -mavlink10.MAV_COMP_ID_SERVO5 = 144 // Servo #5. -mavlink10.MAV_COMP_ID_SERVO6 = 145 // Servo #6. -mavlink10.MAV_COMP_ID_SERVO7 = 146 // Servo #7. -mavlink10.MAV_COMP_ID_SERVO8 = 147 // Servo #8. -mavlink10.MAV_COMP_ID_SERVO9 = 148 // Servo #9. -mavlink10.MAV_COMP_ID_SERVO10 = 149 // Servo #10. -mavlink10.MAV_COMP_ID_SERVO11 = 150 // Servo #11. -mavlink10.MAV_COMP_ID_SERVO12 = 151 // Servo #12. -mavlink10.MAV_COMP_ID_SERVO13 = 152 // Servo #13. -mavlink10.MAV_COMP_ID_SERVO14 = 153 // Servo #14. -mavlink10.MAV_COMP_ID_GIMBAL = 154 // Gimbal #1. -mavlink10.MAV_COMP_ID_LOG = 155 // Logging component. -mavlink10.MAV_COMP_ID_ADSB = 156 // Automatic Dependent Surveillance-Broadcast (ADS-B) component. -mavlink10.MAV_COMP_ID_OSD = 157 // On Screen Display (OSD) devices for video links. -mavlink10.MAV_COMP_ID_PERIPHERAL = 158 // Generic autopilot peripheral component ID. Meant for devices that do - // not implement the parameter microservice. -mavlink10.MAV_COMP_ID_QX1_GIMBAL = 159 // Gimbal ID for QX1. -mavlink10.MAV_COMP_ID_FLARM = 160 // FLARM collision alert component. -mavlink10.MAV_COMP_ID_GIMBAL2 = 171 // Gimbal #2. -mavlink10.MAV_COMP_ID_GIMBAL3 = 172 // Gimbal #3. -mavlink10.MAV_COMP_ID_GIMBAL4 = 173 // Gimbal #4 -mavlink10.MAV_COMP_ID_GIMBAL5 = 174 // Gimbal #5. -mavlink10.MAV_COMP_ID_GIMBAL6 = 175 // Gimbal #6. -mavlink10.MAV_COMP_ID_MISSIONPLANNER = 190 // Component that can generate/supply a mission flight plan (e.g. GCS or - // developer API). -mavlink10.MAV_COMP_ID_PATHPLANNER = 195 // Component that finds an optimal path between points based on a certain - // constraint (e.g. minimum snap, shortest - // path, cost, etc.). -mavlink10.MAV_COMP_ID_OBSTACLE_AVOIDANCE = 196 // Component that plans a collision free path between two points. -mavlink10.MAV_COMP_ID_VISUAL_INERTIAL_ODOMETRY = 197 // Component that provides position estimates using VIO techniques. -mavlink10.MAV_COMP_ID_IMU = 200 // Inertial Measurement Unit (IMU) #1. -mavlink10.MAV_COMP_ID_IMU_2 = 201 // Inertial Measurement Unit (IMU) #2. -mavlink10.MAV_COMP_ID_IMU_3 = 202 // Inertial Measurement Unit (IMU) #3. -mavlink10.MAV_COMP_ID_GPS = 220 // GPS #1. -mavlink10.MAV_COMP_ID_GPS2 = 221 // GPS #2. -mavlink10.MAV_COMP_ID_UDP_BRIDGE = 240 // Component to bridge MAVLink to UDP (i.e. from a UART). -mavlink10.MAV_COMP_ID_UART_BRIDGE = 241 // Component to bridge to UART (i.e. from UDP). -mavlink10.MAV_COMP_ID_SYSTEM_CONTROL = 250 // Component for handling system messages (e.g. to ARM, takeoff, etc.). -mavlink10.MAV_COMPONENT_ENUM_END = 251 // - -// MAV_SYS_STATUS_SENSOR -mavlink10.MAV_SYS_STATUS_SENSOR_3D_GYRO = 1 // 0x01 3D gyro -mavlink10.MAV_SYS_STATUS_SENSOR_3D_ACCEL = 2 // 0x02 3D accelerometer -mavlink10.MAV_SYS_STATUS_SENSOR_3D_MAG = 4 // 0x04 3D magnetometer -mavlink10.MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE = 8 // 0x08 absolute pressure -mavlink10.MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE = 16 // 0x10 differential pressure -mavlink10.MAV_SYS_STATUS_SENSOR_GPS = 32 // 0x20 GPS -mavlink10.MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW = 64 // 0x40 optical flow -mavlink10.MAV_SYS_STATUS_SENSOR_VISION_POSITION = 128 // 0x80 computer vision position -mavlink10.MAV_SYS_STATUS_SENSOR_LASER_POSITION = 256 // 0x100 laser based position -mavlink10.MAV_SYS_STATUS_SENSOR_EXTERNAL_GROUND_TRUTH = 512 // 0x200 external ground truth (Vicon or Leica) -mavlink10.MAV_SYS_STATUS_SENSOR_ANGULAR_RATE_CONTROL = 1024 // 0x400 3D angular rate control -mavlink10.MAV_SYS_STATUS_SENSOR_ATTITUDE_STABILIZATION = 2048 // 0x800 attitude stabilization -mavlink10.MAV_SYS_STATUS_SENSOR_YAW_POSITION = 4096 // 0x1000 yaw position -mavlink10.MAV_SYS_STATUS_SENSOR_Z_ALTITUDE_CONTROL = 8192 // 0x2000 z/altitude control -mavlink10.MAV_SYS_STATUS_SENSOR_XY_POSITION_CONTROL = 16384 // 0x4000 x/y position control -mavlink10.MAV_SYS_STATUS_SENSOR_MOTOR_OUTPUTS = 32768 // 0x8000 motor outputs / control -mavlink10.MAV_SYS_STATUS_SENSOR_RC_RECEIVER = 65536 // 0x10000 rc receiver -mavlink10.MAV_SYS_STATUS_SENSOR_3D_GYRO2 = 131072 // 0x20000 2nd 3D gyro -mavlink10.MAV_SYS_STATUS_SENSOR_3D_ACCEL2 = 262144 // 0x40000 2nd 3D accelerometer -mavlink10.MAV_SYS_STATUS_SENSOR_3D_MAG2 = 524288 // 0x80000 2nd 3D magnetometer -mavlink10.MAV_SYS_STATUS_GEOFENCE = 1048576 // 0x100000 geofence -mavlink10.MAV_SYS_STATUS_AHRS = 2097152 // 0x200000 AHRS subsystem health -mavlink10.MAV_SYS_STATUS_TERRAIN = 4194304 // 0x400000 Terrain subsystem health -mavlink10.MAV_SYS_STATUS_REVERSE_MOTOR = 8388608 // 0x800000 Motors are reversed -mavlink10.MAV_SYS_STATUS_LOGGING = 16777216 // 0x1000000 Logging -mavlink10.MAV_SYS_STATUS_SENSOR_BATTERY = 33554432 // 0x2000000 Battery -mavlink10.MAV_SYS_STATUS_SENSOR_PROXIMITY = 67108864 // 0x4000000 Proximity -mavlink10.MAV_SYS_STATUS_SENSOR_SATCOM = 134217728 // 0x8000000 Satellite Communication -mavlink10.MAV_SYS_STATUS_PREARM_CHECK = 268435456 // 0x10000000 pre-arm check status. Always healthy when armed -mavlink10.MAV_SYS_STATUS_SENSOR_ENUM_END = 268435457 // +// MAV_SYS_STATUS_SENSOR +mavlink10.MAV_SYS_STATUS_SENSOR_3D_GYRO = 1 // 0x01 3D gyro +mavlink10.MAV_SYS_STATUS_SENSOR_3D_ACCEL = 2 // 0x02 3D accelerometer +mavlink10.MAV_SYS_STATUS_SENSOR_3D_MAG = 4 // 0x04 3D magnetometer +mavlink10.MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE = 8 // 0x08 absolute pressure +mavlink10.MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE = 16 // 0x10 differential pressure +mavlink10.MAV_SYS_STATUS_SENSOR_GPS = 32 // 0x20 GPS +mavlink10.MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW = 64 // 0x40 optical flow +mavlink10.MAV_SYS_STATUS_SENSOR_VISION_POSITION = 128 // 0x80 computer vision position +mavlink10.MAV_SYS_STATUS_SENSOR_LASER_POSITION = 256 // 0x100 laser based position +mavlink10.MAV_SYS_STATUS_SENSOR_EXTERNAL_GROUND_TRUTH = 512 // 0x200 external ground truth (Vicon or Leica) +mavlink10.MAV_SYS_STATUS_SENSOR_ANGULAR_RATE_CONTROL = 1024 // 0x400 3D angular rate control +mavlink10.MAV_SYS_STATUS_SENSOR_ATTITUDE_STABILIZATION = 2048 // 0x800 attitude stabilization +mavlink10.MAV_SYS_STATUS_SENSOR_YAW_POSITION = 4096 // 0x1000 yaw position +mavlink10.MAV_SYS_STATUS_SENSOR_Z_ALTITUDE_CONTROL = 8192 // 0x2000 z/altitude control +mavlink10.MAV_SYS_STATUS_SENSOR_XY_POSITION_CONTROL = 16384 // 0x4000 x/y position control +mavlink10.MAV_SYS_STATUS_SENSOR_MOTOR_OUTPUTS = 32768 // 0x8000 motor outputs / control +mavlink10.MAV_SYS_STATUS_SENSOR_RC_RECEIVER = 65536 // 0x10000 rc receiver +mavlink10.MAV_SYS_STATUS_SENSOR_3D_GYRO2 = 131072 // 0x20000 2nd 3D gyro +mavlink10.MAV_SYS_STATUS_SENSOR_3D_ACCEL2 = 262144 // 0x40000 2nd 3D accelerometer +mavlink10.MAV_SYS_STATUS_SENSOR_3D_MAG2 = 524288 // 0x80000 2nd 3D magnetometer +mavlink10.MAV_SYS_STATUS_GEOFENCE = 1048576 // 0x100000 geofence +mavlink10.MAV_SYS_STATUS_AHRS = 2097152 // 0x200000 AHRS subsystem health +mavlink10.MAV_SYS_STATUS_TERRAIN = 4194304 // 0x400000 Terrain subsystem health +mavlink10.MAV_SYS_STATUS_REVERSE_MOTOR = 8388608 // 0x800000 Motors are reversed +mavlink10.MAV_SYS_STATUS_LOGGING = 16777216 // 0x1000000 Logging +mavlink10.MAV_SYS_STATUS_SENSOR_BATTERY = 33554432 // 0x2000000 Battery +mavlink10.MAV_SYS_STATUS_SENSOR_PROXIMITY = 67108864 // 0x4000000 Proximity +mavlink10.MAV_SYS_STATUS_SENSOR_SATCOM = 134217728 // 0x8000000 Satellite Communication +mavlink10.MAV_SYS_STATUS_PREARM_CHECK = 268435456 // 0x10000000 pre-arm check status. Always healthy when armed +mavlink10.MAV_SYS_STATUS_OBSTACLE_AVOIDANCE = 536870912 // 0x20000000 Avoidance/collision prevention +mavlink10.MAV_SYS_STATUS_SENSOR_PROPULSION = 1073741824 // 0x40000000 propulsion (actuator, esc, motor or propellor) +mavlink10.MAV_SYS_STATUS_SENSOR_ENUM_END = 1073741825 // // MAV_FRAME mavlink10.MAV_FRAME_GLOBAL = 0 // Global (WGS84) coordinate frame + MSL altitude. First value / x: // latitude, second value / y: longitude, // third value / z: positive altitude over // mean sea level (MSL). -mavlink10.MAV_FRAME_LOCAL_NED = 1 // Local coordinate frame, Z-down (x: north, y: east, z: down). +mavlink10.MAV_FRAME_LOCAL_NED = 1 // Local coordinate frame, Z-down (x: North, y: East, z: Down). mavlink10.MAV_FRAME_MISSION = 2 // NOT a coordinate frame, indicates a mission command. mavlink10.MAV_FRAME_GLOBAL_RELATIVE_ALT = 3 // Global (WGS84) coordinate frame + altitude relative to the home // position. First value / x: latitude, second // value / y: longitude, third value / z: // positive altitude with 0 being at the // altitude of the home location. -mavlink10.MAV_FRAME_LOCAL_ENU = 4 // Local coordinate frame, Z-up (x: east, y: north, z: up). +mavlink10.MAV_FRAME_LOCAL_ENU = 4 // Local coordinate frame, Z-up (x: East, y: North, z: Up). mavlink10.MAV_FRAME_GLOBAL_INT = 5 // Global (WGS84) coordinate frame (scaled) + MSL altitude. First value / // x: latitude in degrees*1.0e-7, second value // / y: longitude in degrees*1.0e-7, third @@ -1408,24 +1195,27 @@ mavlink10.MAV_FRAME_GLOBAL_TERRAIN_ALT_INT = 11 // Global (WGS84) coordinate fra // y: longitude in degrees*10e-7, third value // / z: positive altitude in meters with 0 // being at ground level in terrain model. -mavlink10.MAV_FRAME_BODY_FRD = 12 // Body fixed frame of reference, Z-down (x: forward, y: right, z: down). -mavlink10.MAV_FRAME_BODY_FLU = 13 // Body fixed frame of reference, Z-up (x: forward, y: left, z: up). -mavlink10.MAV_FRAME_MOCAP_NED = 14 // Odometry local coordinate frame of data given by a motion capture - // system, Z-down (x: north, y: east, z: - // down). -mavlink10.MAV_FRAME_MOCAP_ENU = 15 // Odometry local coordinate frame of data given by a motion capture - // system, Z-up (x: east, y: north, z: up). -mavlink10.MAV_FRAME_VISION_NED = 16 // Odometry local coordinate frame of data given by a vision estimation - // system, Z-down (x: north, y: east, z: - // down). -mavlink10.MAV_FRAME_VISION_ENU = 17 // Odometry local coordinate frame of data given by a vision estimation - // system, Z-up (x: east, y: north, z: up). -mavlink10.MAV_FRAME_ESTIM_NED = 18 // Odometry local coordinate frame of data given by an estimator running - // onboard the vehicle, Z-down (x: north, y: - // east, z: down). -mavlink10.MAV_FRAME_ESTIM_ENU = 19 // Odometry local coordinate frame of data given by an estimator running - // onboard the vehicle, Z-up (x: east, y: - // noth, z: up). +mavlink10.MAV_FRAME_BODY_FRD = 12 // Body fixed frame of reference, Z-down (x: Forward, y: Right, z: Down). +mavlink10.MAV_FRAME_RESERVED_13 = 13 // MAV_FRAME_BODY_FLU - Body fixed frame of reference, Z-up (x: Forward, + // y: Left, z: Up). +mavlink10.MAV_FRAME_RESERVED_14 = 14 // MAV_FRAME_MOCAP_NED - Odometry local coordinate frame of data given by + // a motion capture system, Z-down (x: North, + // y: East, z: Down). +mavlink10.MAV_FRAME_RESERVED_15 = 15 // MAV_FRAME_MOCAP_ENU - Odometry local coordinate frame of data given by + // a motion capture system, Z-up (x: East, y: + // North, z: Up). +mavlink10.MAV_FRAME_RESERVED_16 = 16 // MAV_FRAME_VISION_NED - Odometry local coordinate frame of data given + // by a vision estimation system, Z-down (x: + // North, y: East, z: Down). +mavlink10.MAV_FRAME_RESERVED_17 = 17 // MAV_FRAME_VISION_ENU - Odometry local coordinate frame of data given + // by a vision estimation system, Z-up (x: + // East, y: North, z: Up). +mavlink10.MAV_FRAME_RESERVED_18 = 18 // MAV_FRAME_ESTIM_NED - Odometry local coordinate frame of data given by + // an estimator running onboard the vehicle, + // Z-down (x: North, y: East, z: Down). +mavlink10.MAV_FRAME_RESERVED_19 = 19 // MAV_FRAME_ESTIM_ENU - Odometry local coordinate frame of data given by + // an estimator running onboard the vehicle, + // Z-up (x: East, y: North, z: Up). mavlink10.MAV_FRAME_LOCAL_FRD = 20 // Forward, Right, Down coordinate frame. This is a local frame with // Z-down and arbitrary F/R alignment (i.e. // not aligned with NED/earth frame). @@ -1435,13 +1225,13 @@ mavlink10.MAV_FRAME_LOCAL_FLU = 21 // Forward, Left, Up coordinate frame. This i mavlink10.MAV_FRAME_ENUM_END = 22 // // MAVLINK_DATA_STREAM_TYPE -mavlink10.MAVLINK_DATA_STREAM_IMG_JPEG = 1 // -mavlink10.MAVLINK_DATA_STREAM_IMG_BMP = 2 // -mavlink10.MAVLINK_DATA_STREAM_IMG_RAW8U = 3 // -mavlink10.MAVLINK_DATA_STREAM_IMG_RAW32U = 4 // -mavlink10.MAVLINK_DATA_STREAM_IMG_PGM = 5 // -mavlink10.MAVLINK_DATA_STREAM_IMG_PNG = 6 // -mavlink10.MAVLINK_DATA_STREAM_TYPE_ENUM_END = 7 // +mavlink10.MAVLINK_DATA_STREAM_IMG_JPEG = 0 // +mavlink10.MAVLINK_DATA_STREAM_IMG_BMP = 1 // +mavlink10.MAVLINK_DATA_STREAM_IMG_RAW8U = 2 // +mavlink10.MAVLINK_DATA_STREAM_IMG_RAW32U = 3 // +mavlink10.MAVLINK_DATA_STREAM_IMG_PGM = 4 // +mavlink10.MAVLINK_DATA_STREAM_IMG_PNG = 5 // +mavlink10.MAVLINK_DATA_STREAM_TYPE_ENUM_END = 6 // // FENCE_ACTION mavlink10.FENCE_ACTION_NONE = 0 // Disable fenced mode @@ -1459,6 +1249,12 @@ mavlink10.FENCE_BREACH_MAXALT = 2 // Breached maximum altitude mavlink10.FENCE_BREACH_BOUNDARY = 3 // Breached fence boundary mavlink10.FENCE_BREACH_ENUM_END = 4 // +// FENCE_MITIGATE +mavlink10.FENCE_MITIGATE_UNKNOWN = 0 // Unknown +mavlink10.FENCE_MITIGATE_NONE = 1 // No actions being taken +mavlink10.FENCE_MITIGATE_VEL_LIMIT = 2 // Velocity limiting active to prevent breach +mavlink10.FENCE_MITIGATE_ENUM_END = 3 // + // MAV_MOUNT_MODE mavlink10.MAV_MOUNT_MODE_RETRACT = 0 // Load and keep safe position (Roll,Pitch,Yaw) from permant memory and // stop stabilization @@ -1469,7 +1265,99 @@ mavlink10.MAV_MOUNT_MODE_RC_TARGETING = 3 // Load neutral position and start RC // stabilization mavlink10.MAV_MOUNT_MODE_GPS_POINT = 4 // Load neutral position and start to point to Lat,Lon,Alt mavlink10.MAV_MOUNT_MODE_SYSID_TARGET = 5 // Gimbal tracks system with specified system ID -mavlink10.MAV_MOUNT_MODE_ENUM_END = 6 // +mavlink10.MAV_MOUNT_MODE_HOME_LOCATION = 6 // Gimbal tracks home location +mavlink10.MAV_MOUNT_MODE_ENUM_END = 7 // + +// GIMBAL_DEVICE_CAP_FLAGS +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_HAS_RETRACT = 1 // Gimbal device supports a retracted position +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_HAS_NEUTRAL = 2 // Gimbal device supports a horizontal, forward looking position, + // stabilized +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_HAS_ROLL_AXIS = 4 // Gimbal device supports rotating around roll axis. +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_HAS_ROLL_FOLLOW = 8 // Gimbal device supports to follow a roll angle relative to the vehicle +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_HAS_ROLL_LOCK = 16 // Gimbal device supports locking to an roll angle (generally that's the + // default with roll stabilized) +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_HAS_PITCH_AXIS = 32 // Gimbal device supports rotating around pitch axis. +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_HAS_PITCH_FOLLOW = 64 // Gimbal device supports to follow a pitch angle relative to the vehicle +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_HAS_PITCH_LOCK = 128 // Gimbal device supports locking to an pitch angle (generally that's the + // default with pitch stabilized) +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_HAS_YAW_AXIS = 256 // Gimbal device supports rotating around yaw axis. +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_HAS_YAW_FOLLOW = 512 // Gimbal device supports to follow a yaw angle relative to the vehicle + // (generally that's the default) +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_HAS_YAW_LOCK = 1024 // Gimbal device supports locking to an absolute heading (often this is + // an option available) +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_SUPPORTS_INFINITE_YAW = 2048 // Gimbal device supports yawing/panning infinetely (e.g. using slip + // disk). +mavlink10.GIMBAL_DEVICE_CAP_FLAGS_ENUM_END = 2049 // + +// GIMBAL_MANAGER_CAP_FLAGS +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_HAS_RETRACT = 1 // Based on GIMBAL_DEVICE_CAP_FLAGS_HAS_RETRACT. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_HAS_NEUTRAL = 2 // Based on GIMBAL_DEVICE_CAP_FLAGS_HAS_NEUTRAL. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_HAS_ROLL_AXIS = 4 // Based on GIMBAL_DEVICE_CAP_FLAGS_HAS_ROLL_AXIS. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_HAS_ROLL_FOLLOW = 8 // Based on GIMBAL_DEVICE_CAP_FLAGS_HAS_ROLL_FOLLOW. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_HAS_ROLL_LOCK = 16 // Based on GIMBAL_DEVICE_CAP_FLAGS_HAS_ROLL_LOCK. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_HAS_PITCH_AXIS = 32 // Based on GIMBAL_DEVICE_CAP_FLAGS_HAS_PITCH_AXIS. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_HAS_PITCH_FOLLOW = 64 // Based on GIMBAL_DEVICE_CAP_FLAGS_HAS_PITCH_FOLLOW. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_HAS_PITCH_LOCK = 128 // Based on GIMBAL_DEVICE_CAP_FLAGS_HAS_PITCH_LOCK. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_HAS_YAW_AXIS = 256 // Based on GIMBAL_DEVICE_CAP_FLAGS_HAS_YAW_AXIS. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_HAS_YAW_FOLLOW = 512 // Based on GIMBAL_DEVICE_CAP_FLAGS_HAS_YAW_FOLLOW. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_HAS_YAW_LOCK = 1024 // Based on GIMBAL_DEVICE_CAP_FLAGS_HAS_YAW_LOCK. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_SUPPORTS_INFINITE_YAW = 2048 // Based on GIMBAL_DEVICE_CAP_FLAGS_SUPPORTS_INFINITE_YAW. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_CAN_POINT_LOCATION_LOCAL = 65536 // Gimbal manager supports to point to a local position. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_CAN_POINT_LOCATION_GLOBAL = 131072 // Gimbal manager supports to point to a global latitude, longitude, + // altitude position. +mavlink10.GIMBAL_MANAGER_CAP_FLAGS_ENUM_END = 131073 // + +// GIMBAL_DEVICE_FLAGS +mavlink10.GIMBAL_DEVICE_FLAGS_RETRACT = 1 // Set to retracted safe position (no stabilization), takes presedence + // over all other flags. +mavlink10.GIMBAL_DEVICE_FLAGS_NEUTRAL = 2 // Set to neutral position (horizontal, forward looking, with + // stabiliziation), takes presedence over all + // other flags except RETRACT. +mavlink10.GIMBAL_DEVICE_FLAGS_ROLL_LOCK = 4 // Lock roll angle to absolute angle relative to horizon (not relative to + // drone). This is generally the default with + // a stabilizing gimbal. +mavlink10.GIMBAL_DEVICE_FLAGS_PITCH_LOCK = 8 // Lock pitch angle to absolute angle relative to horizon (not relative + // to drone). This is generally the default. +mavlink10.GIMBAL_DEVICE_FLAGS_YAW_LOCK = 16 // Lock yaw angle to absolute angle relative to North (not relative to + // drone). If this flag is set, the quaternion + // is in the Earth frame with the x-axis + // pointing North (yaw absolute). If this flag + // is not set, the quaternion frame is in the + // Earth frame rotated so that the x-axis is + // pointing forward (yaw relative to vehicle). +mavlink10.GIMBAL_DEVICE_FLAGS_ENUM_END = 17 // + +// GIMBAL_MANAGER_FLAGS +mavlink10.GIMBAL_MANAGER_FLAGS_RETRACT = 1 // Based on GIMBAL_DEVICE_FLAGS_RETRACT +mavlink10.GIMBAL_MANAGER_FLAGS_NEUTRAL = 2 // Based on GIMBAL_DEVICE_FLAGS_NEUTRAL +mavlink10.GIMBAL_MANAGER_FLAGS_ROLL_LOCK = 4 // Based on GIMBAL_DEVICE_FLAGS_ROLL_LOCK +mavlink10.GIMBAL_MANAGER_FLAGS_PITCH_LOCK = 8 // Based on GIMBAL_DEVICE_FLAGS_PITCH_LOCK +mavlink10.GIMBAL_MANAGER_FLAGS_YAW_LOCK = 16 // Based on GIMBAL_DEVICE_FLAGS_YAW_LOCK +mavlink10.GIMBAL_MANAGER_FLAGS_ENUM_END = 17 // + +// GIMBAL_DEVICE_ERROR_FLAGS +mavlink10.GIMBAL_DEVICE_ERROR_FLAGS_AT_ROLL_LIMIT = 1 // Gimbal device is limited by hardware roll limit. +mavlink10.GIMBAL_DEVICE_ERROR_FLAGS_AT_PITCH_LIMIT = 2 // Gimbal device is limited by hardware pitch limit. +mavlink10.GIMBAL_DEVICE_ERROR_FLAGS_AT_YAW_LIMIT = 4 // Gimbal device is limited by hardware yaw limit. +mavlink10.GIMBAL_DEVICE_ERROR_FLAGS_ENCODER_ERROR = 8 // There is an error with the gimbal encoders. +mavlink10.GIMBAL_DEVICE_ERROR_FLAGS_POWER_ERROR = 16 // There is an error with the gimbal power source. +mavlink10.GIMBAL_DEVICE_ERROR_FLAGS_MOTOR_ERROR = 32 // There is an error with the gimbal motor's. +mavlink10.GIMBAL_DEVICE_ERROR_FLAGS_SOFTWARE_ERROR = 64 // There is an error with the gimbal's software. +mavlink10.GIMBAL_DEVICE_ERROR_FLAGS_COMMS_ERROR = 128 // There is an error with the gimbal's communication. +mavlink10.GIMBAL_DEVICE_ERROR_FLAGS_CALIBRATION_RUNNING = 256 // Gimbal is currently calibrating. +mavlink10.GIMBAL_DEVICE_ERROR_FLAGS_ENUM_END = 257 // + +// GRIPPER_ACTIONS +mavlink10.GRIPPER_ACTION_RELEASE = 0 // Gripper release cargo. +mavlink10.GRIPPER_ACTION_GRAB = 1 // Gripper grab onto cargo. +mavlink10.GRIPPER_ACTIONS_ENUM_END = 2 // + +// WINCH_ACTIONS +mavlink10.WINCH_RELAXED = 0 // Relax winch. +mavlink10.WINCH_RELATIVE_LENGTH_CONTROL = 1 // Wind or unwind specified length of cable, optionally using specified + // rate. +mavlink10.WINCH_RATE_CONTROL = 2 // Wind or unwind cable at specified rate. +mavlink10.WINCH_ACTIONS_ENUM_END = 3 // // UAVCAN_NODE_HEALTH mavlink10.UAVCAN_NODE_HEALTH_OK = 0 // The node is functioning properly. @@ -1488,6 +1376,26 @@ mavlink10.UAVCAN_NODE_MODE_SOFTWARE_UPDATE = 3 // The node is in the process of mavlink10.UAVCAN_NODE_MODE_OFFLINE = 7 // The node is no longer available online. mavlink10.UAVCAN_NODE_MODE_ENUM_END = 8 // +// ESC_CONNECTION_TYPE +mavlink10.ESC_CONNECTION_TYPE_PPM = 0 // Traditional PPM ESC. +mavlink10.ESC_CONNECTION_TYPE_SERIAL = 1 // Serial Bus connected ESC. +mavlink10.ESC_CONNECTION_TYPE_ONESHOT = 2 // One Shot PPM ESC. +mavlink10.ESC_CONNECTION_TYPE_I2C = 3 // I2C ESC. +mavlink10.ESC_CONNECTION_TYPE_CAN = 4 // CAN-Bus ESC. +mavlink10.ESC_CONNECTION_TYPE_DSHOT = 5 // DShot ESC. +mavlink10.ESC_CONNECTION_TYPE_ENUM_END = 6 // + +// ESC_FAILURE_FLAGS +mavlink10.ESC_FAILURE_NONE = 0 // No ESC failure. +mavlink10.ESC_FAILURE_OVER_CURRENT = 1 // Over current failure. +mavlink10.ESC_FAILURE_OVER_VOLTAGE = 2 // Over voltage failure. +mavlink10.ESC_FAILURE_OVER_TEMPERATURE = 4 // Over temperature failure. +mavlink10.ESC_FAILURE_OVER_RPM = 8 // Over RPM failure. +mavlink10.ESC_FAILURE_INCONSISTENT_CMD = 16 // Inconsistent command failure i.e. out of bounds. +mavlink10.ESC_FAILURE_MOTOR_STUCK = 32 // Motor stuck failure. +mavlink10.ESC_FAILURE_GENERIC = 64 // Generic ESC failure. +mavlink10.ESC_FAILURE_FLAGS_ENUM_END = 65 // + // STORAGE_STATUS mavlink10.STORAGE_STATUS_EMPTY = 0 // Storage is missing (no microSD card loaded for example.) mavlink10.STORAGE_STATUS_UNFORMATTED = 1 // Storage present but unformatted. @@ -1497,6 +1405,74 @@ mavlink10.STORAGE_STATUS_NOT_SUPPORTED = 3 // Camera does not supply storage sta // will be ignored. mavlink10.STORAGE_STATUS_ENUM_END = 4 // +// STORAGE_TYPE +mavlink10.STORAGE_TYPE_UNKNOWN = 0 // Storage type is not known. +mavlink10.STORAGE_TYPE_USB_STICK = 1 // Storage type is USB device. +mavlink10.STORAGE_TYPE_SD = 2 // Storage type is SD card. +mavlink10.STORAGE_TYPE_MICROSD = 3 // Storage type is microSD card. +mavlink10.STORAGE_TYPE_CF = 4 // Storage type is CFast. +mavlink10.STORAGE_TYPE_CFE = 5 // Storage type is CFexpress. +mavlink10.STORAGE_TYPE_XQD = 6 // Storage type is XQD. +mavlink10.STORAGE_TYPE_HD = 7 // Storage type is HD mass storage type. +mavlink10.STORAGE_TYPE_OTHER = 254 // Storage type is other, not listed type. +mavlink10.STORAGE_TYPE_ENUM_END = 255 // + +// ORBIT_YAW_BEHAVIOUR +mavlink10.ORBIT_YAW_BEHAVIOUR_HOLD_FRONT_TO_CIRCLE_CENTER = 0 // Vehicle front points to the center (default). +mavlink10.ORBIT_YAW_BEHAVIOUR_HOLD_INITIAL_HEADING = 1 // Vehicle front holds heading when message received. +mavlink10.ORBIT_YAW_BEHAVIOUR_UNCONTROLLED = 2 // Yaw uncontrolled. +mavlink10.ORBIT_YAW_BEHAVIOUR_HOLD_FRONT_TANGENT_TO_CIRCLE = 3 // Vehicle front follows flight path (tangential to circle). +mavlink10.ORBIT_YAW_BEHAVIOUR_RC_CONTROLLED = 4 // Yaw controlled by RC input. +mavlink10.ORBIT_YAW_BEHAVIOUR_ENUM_END = 5 // + +// WIFI_CONFIG_AP_RESPONSE +mavlink10.WIFI_CONFIG_AP_RESPONSE_UNDEFINED = 0 // Undefined response. Likely an indicative of a system that doesn't + // support this request. +mavlink10.WIFI_CONFIG_AP_RESPONSE_ACCEPTED = 1 // Changes accepted. +mavlink10.WIFI_CONFIG_AP_RESPONSE_REJECTED = 2 // Changes rejected. +mavlink10.WIFI_CONFIG_AP_RESPONSE_MODE_ERROR = 3 // Invalid Mode. +mavlink10.WIFI_CONFIG_AP_RESPONSE_SSID_ERROR = 4 // Invalid SSID. +mavlink10.WIFI_CONFIG_AP_RESPONSE_PASSWORD_ERROR = 5 // Invalid Password. +mavlink10.WIFI_CONFIG_AP_RESPONSE_ENUM_END = 6 // + +// CELLULAR_CONFIG_RESPONSE +mavlink10.CELLULAR_CONFIG_RESPONSE_ACCEPTED = 0 // Changes accepted. +mavlink10.CELLULAR_CONFIG_RESPONSE_APN_ERROR = 1 // Invalid APN. +mavlink10.CELLULAR_CONFIG_RESPONSE_PIN_ERROR = 2 // Invalid PIN. +mavlink10.CELLULAR_CONFIG_RESPONSE_REJECTED = 3 // Changes rejected. +mavlink10.CELLULAR_CONFIG_BLOCKED_PUK_REQUIRED = 4 // PUK is required to unblock SIM card. +mavlink10.CELLULAR_CONFIG_RESPONSE_ENUM_END = 5 // + +// WIFI_CONFIG_AP_MODE +mavlink10.WIFI_CONFIG_AP_MODE_UNDEFINED = 0 // WiFi mode is undefined. +mavlink10.WIFI_CONFIG_AP_MODE_AP = 1 // WiFi configured as an access point. +mavlink10.WIFI_CONFIG_AP_MODE_STATION = 2 // WiFi configured as a station connected to an existing local WiFi + // network. +mavlink10.WIFI_CONFIG_AP_MODE_DISABLED = 3 // WiFi disabled. +mavlink10.WIFI_CONFIG_AP_MODE_ENUM_END = 4 // + +// COMP_METADATA_TYPE +mavlink10.COMP_METADATA_TYPE_GENERAL = 0 // General information which also includes information on other optional + // supported COMP_METADATA_TYPE's. Must be + // supported. Only downloadable from vehicle. +mavlink10.COMP_METADATA_TYPE_PARAMETER = 1 // Parameter meta data. +mavlink10.COMP_METADATA_TYPE_COMMANDS = 2 // Meta data which specifies the commands the vehicle supports. (WIP) +mavlink10.COMP_METADATA_TYPE_PERIPHERALS = 3 // Meta data which specifies potential external peripherals that do not + // talk MAVLink +mavlink10.COMP_METADATA_TYPE_EVENTS = 4 // Meta data for events interface +mavlink10.COMP_METADATA_TYPE_ENUM_END = 5 // + +// PARAM_TRANSACTION_TRANSPORT +mavlink10.PARAM_TRANSACTION_TRANSPORT_PARAM = 0 // Transaction over param transport. +mavlink10.PARAM_TRANSACTION_TRANSPORT_PARAM_EXT = 1 // Transaction over param_ext transport. +mavlink10.PARAM_TRANSACTION_TRANSPORT_ENUM_END = 2 // + +// PARAM_TRANSACTION_ACTION +mavlink10.PARAM_TRANSACTION_ACTION_START = 0 // Commit the current parameter transaction. +mavlink10.PARAM_TRANSACTION_ACTION_COMMIT = 1 // Commit the current parameter transaction. +mavlink10.PARAM_TRANSACTION_ACTION_CANCEL = 2 // Cancel the current parameter transaction. +mavlink10.PARAM_TRANSACTION_ACTION_ENUM_END = 3 // + // MAV_DATA_STREAM mavlink10.MAV_DATA_STREAM_ALL = 0 // Enable all data streams mavlink10.MAV_DATA_STREAM_RAW_SENSORS = 1 // Enable IMU_RAW, GPS_RAW, GPS_STATUS packets. @@ -1519,23 +1495,23 @@ mavlink10.MAV_ROI_TARGET = 4 // Point toward of given id. mavlink10.MAV_ROI_ENUM_END = 5 // // MAV_CMD_ACK -mavlink10.MAV_CMD_ACK_OK = 1 // Command / mission item is ok. -mavlink10.MAV_CMD_ACK_ERR_FAIL = 2 // Generic error message if none of the other reasons fails or if no +mavlink10.MAV_CMD_ACK_OK = 0 // Command / mission item is ok. +mavlink10.MAV_CMD_ACK_ERR_FAIL = 1 // Generic error message if none of the other reasons fails or if no // detailed error reporting is implemented. -mavlink10.MAV_CMD_ACK_ERR_ACCESS_DENIED = 3 // The system is refusing to accept this command from this source / +mavlink10.MAV_CMD_ACK_ERR_ACCESS_DENIED = 2 // The system is refusing to accept this command from this source / // communication partner. -mavlink10.MAV_CMD_ACK_ERR_NOT_SUPPORTED = 4 // Command or mission item is not supported, other commands would be +mavlink10.MAV_CMD_ACK_ERR_NOT_SUPPORTED = 3 // Command or mission item is not supported, other commands would be // accepted. -mavlink10.MAV_CMD_ACK_ERR_COORDINATE_FRAME_NOT_SUPPORTED = 5 // The coordinate frame of this command / mission item is not supported. -mavlink10.MAV_CMD_ACK_ERR_COORDINATES_OUT_OF_RANGE = 6 // The coordinate frame of this command is ok, but he coordinate values +mavlink10.MAV_CMD_ACK_ERR_COORDINATE_FRAME_NOT_SUPPORTED = 4 // The coordinate frame of this command / mission item is not supported. +mavlink10.MAV_CMD_ACK_ERR_COORDINATES_OUT_OF_RANGE = 5 // The coordinate frame of this command is ok, but he coordinate values // exceed the safety limits of this system. // This is a generic error, please use the // more specific error messages below if // possible. -mavlink10.MAV_CMD_ACK_ERR_X_LAT_OUT_OF_RANGE = 7 // The X or latitude value is out of range. -mavlink10.MAV_CMD_ACK_ERR_Y_LON_OUT_OF_RANGE = 8 // The Y or longitude value is out of range. -mavlink10.MAV_CMD_ACK_ERR_Z_ALT_OUT_OF_RANGE = 9 // The Z or altitude value is out of range. -mavlink10.MAV_CMD_ACK_ENUM_END = 10 // +mavlink10.MAV_CMD_ACK_ERR_X_LAT_OUT_OF_RANGE = 6 // The X or latitude value is out of range. +mavlink10.MAV_CMD_ACK_ERR_Y_LON_OUT_OF_RANGE = 7 // The Y or longitude value is out of range. +mavlink10.MAV_CMD_ACK_ERR_Z_ALT_OUT_OF_RANGE = 8 // The Z or altitude value is out of range. +mavlink10.MAV_CMD_ACK_ENUM_END = 9 // // MAV_PARAM_TYPE mavlink10.MAV_PARAM_TYPE_UINT8 = 1 // 8-bit unsigned integer @@ -1550,6 +1526,20 @@ mavlink10.MAV_PARAM_TYPE_REAL32 = 9 // 32-bit floating-point mavlink10.MAV_PARAM_TYPE_REAL64 = 10 // 64-bit floating-point mavlink10.MAV_PARAM_TYPE_ENUM_END = 11 // +// MAV_PARAM_EXT_TYPE +mavlink10.MAV_PARAM_EXT_TYPE_UINT8 = 1 // 8-bit unsigned integer +mavlink10.MAV_PARAM_EXT_TYPE_INT8 = 2 // 8-bit signed integer +mavlink10.MAV_PARAM_EXT_TYPE_UINT16 = 3 // 16-bit unsigned integer +mavlink10.MAV_PARAM_EXT_TYPE_INT16 = 4 // 16-bit signed integer +mavlink10.MAV_PARAM_EXT_TYPE_UINT32 = 5 // 32-bit unsigned integer +mavlink10.MAV_PARAM_EXT_TYPE_INT32 = 6 // 32-bit signed integer +mavlink10.MAV_PARAM_EXT_TYPE_UINT64 = 7 // 64-bit unsigned integer +mavlink10.MAV_PARAM_EXT_TYPE_INT64 = 8 // 64-bit signed integer +mavlink10.MAV_PARAM_EXT_TYPE_REAL32 = 9 // 32-bit floating-point +mavlink10.MAV_PARAM_EXT_TYPE_REAL64 = 10 // 64-bit floating-point +mavlink10.MAV_PARAM_EXT_TYPE_CUSTOM = 11 // Custom Type +mavlink10.MAV_PARAM_EXT_TYPE_ENUM_END = 12 // + // MAV_RESULT mavlink10.MAV_RESULT_ACCEPTED = 0 // Command is valid (is supported and has valid parameters), and was // executed. @@ -1577,19 +1567,16 @@ mavlink10.MAV_RESULT_IN_PROGRESS = 5 // Command is valid and is being executed. // message with final result of the operation. // The COMMAND_ACK.progress field can be used // to indicate the progress of the operation. - // There is no need for the sender to retry - // the command, but if done during execution, - // the component will return - // MAV_RESULT_IN_PROGRESS with an updated - // progress. -mavlink10.MAV_RESULT_ENUM_END = 6 // +mavlink10.MAV_RESULT_CANCELLED = 6 // Command has been cancelled (as a result of receiving a COMMAND_CANCEL + // message). +mavlink10.MAV_RESULT_ENUM_END = 7 // // MAV_MISSION_RESULT mavlink10.MAV_MISSION_ACCEPTED = 0 // mission accepted OK mavlink10.MAV_MISSION_ERROR = 1 // Generic error / not accepting mission commands at all right now. mavlink10.MAV_MISSION_UNSUPPORTED_FRAME = 2 // Coordinate frame is not supported. mavlink10.MAV_MISSION_UNSUPPORTED = 3 // Command is not supported. -mavlink10.MAV_MISSION_NO_SPACE = 4 // Mission item exceeds storage space. +mavlink10.MAV_MISSION_NO_SPACE = 4 // Mission items exceed storage space. mavlink10.MAV_MISSION_INVALID = 5 // One of the parameters has an invalid value. mavlink10.MAV_MISSION_INVALID_PARAM1 = 6 // param1 has an invalid value. mavlink10.MAV_MISSION_INVALID_PARAM2 = 7 // param2 has an invalid value. @@ -1718,7 +1705,7 @@ mavlink10.MAV_SENSOR_ORIENTATION_ENUM_END = 101 // // MAV_PROTOCOL_CAPABILITY mavlink10.MAV_PROTOCOL_CAPABILITY_MISSION_FLOAT = 1 // Autopilot supports MISSION float message type. mavlink10.MAV_PROTOCOL_CAPABILITY_PARAM_FLOAT = 2 // Autopilot supports the new param float message type. -mavlink10.MAV_PROTOCOL_CAPABILITY_MISSION_INT = 4 // Autopilot supports MISSION_INT scaled integer message type. +mavlink10.MAV_PROTOCOL_CAPABILITY_MISSION_INT = 4 // Autopilot supports MISSION_ITEM_INT scaled integer message type. mavlink10.MAV_PROTOCOL_CAPABILITY_COMMAND_INT = 8 // Autopilot supports COMMAND_INT scaled integer message type. mavlink10.MAV_PROTOCOL_CAPABILITY_PARAM_UNION = 16 // Autopilot supports the new param union message type. mavlink10.MAV_PROTOCOL_CAPABILITY_FTP = 32 // Autopilot supports the new FILE_TRANSFER_PROTOCOL message type. @@ -1782,12 +1769,72 @@ mavlink10.MAV_BATTERY_CHARGE_STATE_LOW = 2 // Battery state is low, warn and mon mavlink10.MAV_BATTERY_CHARGE_STATE_CRITICAL = 3 // Battery state is critical, return or abort immediately. mavlink10.MAV_BATTERY_CHARGE_STATE_EMERGENCY = 4 // Battery state is too low for ordinary abort sequence. Perform fastest // possible emergency stop to prevent damage. -mavlink10.MAV_BATTERY_CHARGE_STATE_FAILED = 5 // Battery failed, damage unavoidable. +mavlink10.MAV_BATTERY_CHARGE_STATE_FAILED = 5 // Battery failed, damage unavoidable. Possible causes (faults) are + // listed in MAV_BATTERY_FAULT. mavlink10.MAV_BATTERY_CHARGE_STATE_UNHEALTHY = 6 // Battery is diagnosed to be defective or an error occurred, usage is - // discouraged / prohibited. + // discouraged / prohibited. Possible causes + // (faults) are listed in MAV_BATTERY_FAULT. mavlink10.MAV_BATTERY_CHARGE_STATE_CHARGING = 7 // Battery is charging. mavlink10.MAV_BATTERY_CHARGE_STATE_ENUM_END = 8 // +// MAV_BATTERY_MODE +mavlink10.MAV_BATTERY_MODE_UNKNOWN = 0 // Battery mode not supported/unknown battery mode/normal operation. +mavlink10.MAV_BATTERY_MODE_AUTO_DISCHARGING = 1 // Battery is auto discharging (towards storage level). +mavlink10.MAV_BATTERY_MODE_HOT_SWAP = 2 // Battery in hot-swap mode (current limited to prevent spikes that might + // damage sensitive electrical circuits). +mavlink10.MAV_BATTERY_MODE_ENUM_END = 3 // + +// MAV_BATTERY_FAULT +mavlink10.MAV_BATTERY_FAULT_DEEP_DISCHARGE = 1 // Battery has deep discharged. +mavlink10.MAV_BATTERY_FAULT_SPIKES = 2 // Voltage spikes. +mavlink10.MAV_BATTERY_FAULT_CELL_FAIL = 4 // One or more cells have failed. Battery should also report + // MAV_BATTERY_CHARGE_STATE_FAILE (and should + // not be used). +mavlink10.MAV_BATTERY_FAULT_OVER_CURRENT = 8 // Over-current fault. +mavlink10.MAV_BATTERY_FAULT_OVER_TEMPERATURE = 16 // Over-temperature fault. +mavlink10.MAV_BATTERY_FAULT_UNDER_TEMPERATURE = 32 // Under-temperature fault. +mavlink10.MAV_BATTERY_FAULT_INCOMPATIBLE_VOLTAGE = 64 // Vehicle voltage is not compatible with this battery (batteries on same + // power rail should have similar voltage). +mavlink10.MAV_BATTERY_FAULT_INCOMPATIBLE_FIRMWARE = 128 // Battery firmware is not compatible with current autopilot firmware. +mavlink10.BATTERY_FAULT_INCOMPATIBLE_CELLS_CONFIGURATION = 256 // Battery is not compatible due to cell configuration (e.g. 5s1p when + // vehicle requires 6s). +mavlink10.MAV_BATTERY_FAULT_ENUM_END = 257 // + +// MAV_GENERATOR_STATUS_FLAG +mavlink10.MAV_GENERATOR_STATUS_FLAG_OFF = 1 // Generator is off. +mavlink10.MAV_GENERATOR_STATUS_FLAG_READY = 2 // Generator is ready to start generating power. +mavlink10.MAV_GENERATOR_STATUS_FLAG_GENERATING = 4 // Generator is generating power. +mavlink10.MAV_GENERATOR_STATUS_FLAG_CHARGING = 8 // Generator is charging the batteries (generating enough power to charge + // and provide the load). +mavlink10.MAV_GENERATOR_STATUS_FLAG_REDUCED_POWER = 16 // Generator is operating at a reduced maximum power. +mavlink10.MAV_GENERATOR_STATUS_FLAG_MAXPOWER = 32 // Generator is providing the maximum output. +mavlink10.MAV_GENERATOR_STATUS_FLAG_OVERTEMP_WARNING = 64 // Generator is near the maximum operating temperature, cooling is + // insufficient. +mavlink10.MAV_GENERATOR_STATUS_FLAG_OVERTEMP_FAULT = 128 // Generator hit the maximum operating temperature and shutdown. +mavlink10.MAV_GENERATOR_STATUS_FLAG_ELECTRONICS_OVERTEMP_WARNING = 256 // Power electronics are near the maximum operating temperature, cooling + // is insufficient. +mavlink10.MAV_GENERATOR_STATUS_FLAG_ELECTRONICS_OVERTEMP_FAULT = 512 // Power electronics hit the maximum operating temperature and shutdown. +mavlink10.MAV_GENERATOR_STATUS_FLAG_ELECTRONICS_FAULT = 1024 // Power electronics experienced a fault and shutdown. +mavlink10.MAV_GENERATOR_STATUS_FLAG_POWERSOURCE_FAULT = 2048 // The power source supplying the generator failed e.g. mechanical + // generator stopped, tether is no longer + // providing power, solar cell is in shade, + // hydrogen reaction no longer happening. +mavlink10.MAV_GENERATOR_STATUS_FLAG_COMMUNICATION_WARNING = 4096 // Generator controller having communication problems. +mavlink10.MAV_GENERATOR_STATUS_FLAG_COOLING_WARNING = 8192 // Power electronic or generator cooling system error. +mavlink10.MAV_GENERATOR_STATUS_FLAG_POWER_RAIL_FAULT = 16384 // Generator controller power rail experienced a fault. +mavlink10.MAV_GENERATOR_STATUS_FLAG_OVERCURRENT_FAULT = 32768 // Generator controller exceeded the overcurrent threshold and shutdown + // to prevent damage. +mavlink10.MAV_GENERATOR_STATUS_FLAG_BATTERY_OVERCHARGE_CURRENT_FAULT = 65536 // Generator controller detected a high current going into the batteries + // and shutdown to prevent battery damage. +mavlink10.MAV_GENERATOR_STATUS_FLAG_OVERVOLTAGE_FAULT = 131072 // Generator controller exceeded it's overvoltage threshold and shutdown + // to prevent it exceeding the voltage rating. +mavlink10.MAV_GENERATOR_STATUS_FLAG_BATTERY_UNDERVOLT_FAULT = 262144 // Batteries are under voltage (generator will not start). +mavlink10.MAV_GENERATOR_STATUS_FLAG_START_INHIBITED = 524288 // Generator start is inhibited by e.g. a safety switch. +mavlink10.MAV_GENERATOR_STATUS_FLAG_MAINTENANCE_REQUIRED = 1048576 // Generator requires maintenance. +mavlink10.MAV_GENERATOR_STATUS_FLAG_WARMING_UP = 2097152 // Generator is not ready to generate yet. +mavlink10.MAV_GENERATOR_STATUS_FLAG_IDLE = 4194304 // Generator is idle. +mavlink10.MAV_GENERATOR_STATUS_FLAG_ENUM_END = 4194305 // + // MAV_VTOL_STATE mavlink10.MAV_VTOL_STATE_UNDEFINED = 0 // MAV is not configured as VTOL mavlink10.MAV_VTOL_STATE_TRANSITION_TO_FW = 1 // VTOL is in transition from multicopter to fixed-wing @@ -1960,10 +2007,88 @@ mavlink10.CAMERA_CAP_FLAGS_CAN_CAPTURE_VIDEO_IN_IMAGE_MODE = 16 // Camera can ca mavlink10.CAMERA_CAP_FLAGS_HAS_IMAGE_SURVEY_MODE = 32 // Camera has image survey mode (MAV_CMD_SET_CAMERA_MODE) mavlink10.CAMERA_CAP_FLAGS_HAS_BASIC_ZOOM = 64 // Camera has basic zoom control (MAV_CMD_SET_CAMERA_ZOOM) mavlink10.CAMERA_CAP_FLAGS_HAS_BASIC_FOCUS = 128 // Camera has basic focus control (MAV_CMD_SET_CAMERA_FOCUS) -mavlink10.CAMERA_CAP_FLAGS_HAS_VIDEO_STREAM = 256 // Camera has video streaming capabilities (use - // MAV_CMD_REQUEST_VIDEO_STREAM_INFORMATION - // for video streaming info) -mavlink10.CAMERA_CAP_FLAGS_ENUM_END = 257 // +mavlink10.CAMERA_CAP_FLAGS_HAS_VIDEO_STREAM = 256 // Camera has video streaming capabilities (request + // VIDEO_STREAM_INFORMATION with + // MAV_CMD_REQUEST_MESSAGE for video streaming + // info) +mavlink10.CAMERA_CAP_FLAGS_HAS_TRACKING_POINT = 512 // Camera supports tracking of a point on the camera view. +mavlink10.CAMERA_CAP_FLAGS_HAS_TRACKING_RECTANGLE = 1024 // Camera supports tracking of a selection rectangle on the camera view. +mavlink10.CAMERA_CAP_FLAGS_HAS_TRACKING_GEO_STATUS = 2048 // Camera supports tracking geo status (CAMERA_TRACKING_GEO_STATUS). +mavlink10.CAMERA_CAP_FLAGS_ENUM_END = 2049 // + +// VIDEO_STREAM_STATUS_FLAGS +mavlink10.VIDEO_STREAM_STATUS_FLAGS_RUNNING = 1 // Stream is active (running) +mavlink10.VIDEO_STREAM_STATUS_FLAGS_THERMAL = 2 // Stream is thermal imaging +mavlink10.VIDEO_STREAM_STATUS_FLAGS_ENUM_END = 3 // + +// VIDEO_STREAM_TYPE +mavlink10.VIDEO_STREAM_TYPE_RTSP = 0 // Stream is RTSP +mavlink10.VIDEO_STREAM_TYPE_RTPUDP = 1 // Stream is RTP UDP (URI gives the port number) +mavlink10.VIDEO_STREAM_TYPE_TCP_MPEG = 2 // Stream is MPEG on TCP +mavlink10.VIDEO_STREAM_TYPE_MPEG_TS_H264 = 3 // Stream is h.264 on MPEG TS (URI gives the port number) +mavlink10.VIDEO_STREAM_TYPE_ENUM_END = 4 // + +// CAMERA_TRACKING_STATUS_FLAGS +mavlink10.CAMERA_TRACKING_STATUS_FLAGS_IDLE = 0 // Camera is not tracking +mavlink10.CAMERA_TRACKING_STATUS_FLAGS_ACTIVE = 1 // Camera is tracking +mavlink10.CAMERA_TRACKING_STATUS_FLAGS_ERROR = 2 // Camera tracking in error state +mavlink10.CAMERA_TRACKING_STATUS_FLAGS_ENUM_END = 3 // + +// CAMERA_TRACKING_MODE +mavlink10.CAMERA_TRACKING_MODE_NONE = 0 // Not tracking +mavlink10.CAMERA_TRACKING_MODE_POINT = 1 // Target is a point +mavlink10.CAMERA_TRACKING_MODE_RECTANGLE = 2 // Target is a rectangle +mavlink10.CAMERA_TRACKING_MODE_ENUM_END = 3 // + +// CAMERA_TRACKING_TARGET_DATA +mavlink10.CAMERA_TRACKING_TARGET_DATA_NONE = 0 // No target data +mavlink10.CAMERA_TRACKING_TARGET_DATA_EMBEDDED = 1 // Target data embedded in image data (proprietary) +mavlink10.CAMERA_TRACKING_TARGET_DATA_RENDERED = 2 // Target data rendered in image +mavlink10.CAMERA_TRACKING_TARGET_DATA_IN_STATUS = 4 // Target data within status message (Point or Rectangle) +mavlink10.CAMERA_TRACKING_TARGET_DATA_ENUM_END = 5 // + +// CAMERA_ZOOM_TYPE +mavlink10.ZOOM_TYPE_STEP = 0 // Zoom one step increment (-1 for wide, 1 for tele) +mavlink10.ZOOM_TYPE_CONTINUOUS = 1 // Continuous zoom up/down until stopped (-1 for wide, 1 for tele, 0 to + // stop zooming) +mavlink10.ZOOM_TYPE_RANGE = 2 // Zoom value as proportion of full camera range (a value between 0.0 and + // 100.0) +mavlink10.ZOOM_TYPE_FOCAL_LENGTH = 3 // Zoom value/variable focal length in milimetres. Note that there is no + // message to get the valid zoom range of the + // camera, so this can type can only be used + // for cameras where the zoom range is known + // (implying that this cannot reliably be used + // in a GCS for an arbitrary camera) +mavlink10.CAMERA_ZOOM_TYPE_ENUM_END = 4 // + +// SET_FOCUS_TYPE +mavlink10.FOCUS_TYPE_STEP = 0 // Focus one step increment (-1 for focusing in, 1 for focusing out + // towards infinity). +mavlink10.FOCUS_TYPE_CONTINUOUS = 1 // Continuous focus up/down until stopped (-1 for focusing in, 1 for + // focusing out towards infinity, 0 to stop + // focusing) +mavlink10.FOCUS_TYPE_RANGE = 2 // Focus value as proportion of full camera focus range (a value between + // 0.0 and 100.0) +mavlink10.FOCUS_TYPE_METERS = 3 // Focus value in metres. Note that there is no message to get the valid + // focus range of the camera, so this can type + // can only be used for cameras where the + // range is known (implying that this cannot + // reliably be used in a GCS for an arbitrary + // camera). +mavlink10.SET_FOCUS_TYPE_ENUM_END = 4 // + +// PARAM_ACK +mavlink10.PARAM_ACK_ACCEPTED = 0 // Parameter value ACCEPTED and SET +mavlink10.PARAM_ACK_VALUE_UNSUPPORTED = 1 // Parameter value UNKNOWN/UNSUPPORTED +mavlink10.PARAM_ACK_FAILED = 2 // Parameter failed to set +mavlink10.PARAM_ACK_IN_PROGRESS = 3 // Parameter value received but not yet set/accepted. A subsequent + // PARAM_ACK_TRANSACTION or PARAM_EXT_ACK with + // the final result will follow once operation + // is completed. This is returned immediately + // for parameters that take longer to set, + // indicating taht the the parameter was + // recieved and does not need to be resent. +mavlink10.PARAM_ACK_ENUM_END = 4 // // CAMERA_MODE mavlink10.CAMERA_MODE_IMAGE = 0 // Camera is in image/photo capture mode. @@ -2004,6 +2129,77 @@ mavlink10.POSITION_TARGET_TYPEMASK_YAW_IGNORE = 1024 // Ignore yaw mavlink10.POSITION_TARGET_TYPEMASK_YAW_RATE_IGNORE = 2048 // Ignore yaw rate mavlink10.POSITION_TARGET_TYPEMASK_ENUM_END = 2049 // +// ATTITUDE_TARGET_TYPEMASK +mavlink10.ATTITUDE_TARGET_TYPEMASK_BODY_ROLL_RATE_IGNORE = 1 // Ignore body roll rate +mavlink10.ATTITUDE_TARGET_TYPEMASK_BODY_PITCH_RATE_IGNORE = 2 // Ignore body pitch rate +mavlink10.ATTITUDE_TARGET_TYPEMASK_BODY_YAW_RATE_IGNORE = 4 // Ignore body yaw rate +mavlink10.ATTITUDE_TARGET_TYPEMASK_THRUST_BODY_SET = 32 // Use 3D body thrust setpoint instead of throttle +mavlink10.ATTITUDE_TARGET_TYPEMASK_THROTTLE_IGNORE = 64 // Ignore throttle +mavlink10.ATTITUDE_TARGET_TYPEMASK_ATTITUDE_IGNORE = 128 // Ignore attitude +mavlink10.ATTITUDE_TARGET_TYPEMASK_ENUM_END = 129 // + +// UTM_FLIGHT_STATE +mavlink10.UTM_FLIGHT_STATE_UNKNOWN = 1 // The flight state can't be determined. +mavlink10.UTM_FLIGHT_STATE_GROUND = 2 // UAS on ground. +mavlink10.UTM_FLIGHT_STATE_AIRBORNE = 3 // UAS airborne. +mavlink10.UTM_FLIGHT_STATE_EMERGENCY = 16 // UAS is in an emergency flight state. +mavlink10.UTM_FLIGHT_STATE_NOCTRL = 32 // UAS has no active controls. +mavlink10.UTM_FLIGHT_STATE_ENUM_END = 33 // + +// UTM_DATA_AVAIL_FLAGS +mavlink10.UTM_DATA_AVAIL_FLAGS_TIME_VALID = 1 // The field time contains valid data. +mavlink10.UTM_DATA_AVAIL_FLAGS_UAS_ID_AVAILABLE = 2 // The field uas_id contains valid data. +mavlink10.UTM_DATA_AVAIL_FLAGS_POSITION_AVAILABLE = 4 // The fields lat, lon and h_acc contain valid data. +mavlink10.UTM_DATA_AVAIL_FLAGS_ALTITUDE_AVAILABLE = 8 // The fields alt and v_acc contain valid data. +mavlink10.UTM_DATA_AVAIL_FLAGS_RELATIVE_ALTITUDE_AVAILABLE = 16 // The field relative_alt contains valid data. +mavlink10.UTM_DATA_AVAIL_FLAGS_HORIZONTAL_VELO_AVAILABLE = 32 // The fields vx and vy contain valid data. +mavlink10.UTM_DATA_AVAIL_FLAGS_VERTICAL_VELO_AVAILABLE = 64 // The field vz contains valid data. +mavlink10.UTM_DATA_AVAIL_FLAGS_NEXT_WAYPOINT_AVAILABLE = 128 // The fields next_lat, next_lon and next_alt contain valid data. +mavlink10.UTM_DATA_AVAIL_FLAGS_ENUM_END = 129 // + +// CELLULAR_NETWORK_RADIO_TYPE +mavlink10.CELLULAR_NETWORK_RADIO_TYPE_NONE = 0 // +mavlink10.CELLULAR_NETWORK_RADIO_TYPE_GSM = 1 // +mavlink10.CELLULAR_NETWORK_RADIO_TYPE_CDMA = 2 // +mavlink10.CELLULAR_NETWORK_RADIO_TYPE_WCDMA = 3 // +mavlink10.CELLULAR_NETWORK_RADIO_TYPE_LTE = 4 // +mavlink10.CELLULAR_NETWORK_RADIO_TYPE_ENUM_END = 5 // + +// CELLULAR_STATUS_FLAG +mavlink10.CELLULAR_STATUS_FLAG_UNKNOWN = 0 // State unknown or not reportable. +mavlink10.CELLULAR_STATUS_FLAG_FAILED = 1 // Modem is unusable +mavlink10.CELLULAR_STATUS_FLAG_INITIALIZING = 2 // Modem is being initialized +mavlink10.CELLULAR_STATUS_FLAG_LOCKED = 3 // Modem is locked +mavlink10.CELLULAR_STATUS_FLAG_DISABLED = 4 // Modem is not enabled and is powered down +mavlink10.CELLULAR_STATUS_FLAG_DISABLING = 5 // Modem is currently transitioning to the CELLULAR_STATUS_FLAG_DISABLED + // state +mavlink10.CELLULAR_STATUS_FLAG_ENABLING = 6 // Modem is currently transitioning to the CELLULAR_STATUS_FLAG_ENABLED + // state +mavlink10.CELLULAR_STATUS_FLAG_ENABLED = 7 // Modem is enabled and powered on but not registered with a network + // provider and not available for data + // connections +mavlink10.CELLULAR_STATUS_FLAG_SEARCHING = 8 // Modem is searching for a network provider to register +mavlink10.CELLULAR_STATUS_FLAG_REGISTERED = 9 // Modem is registered with a network provider, and data connections and + // messaging may be available for use +mavlink10.CELLULAR_STATUS_FLAG_DISCONNECTING = 10 // Modem is disconnecting and deactivating the last active packet data + // bearer. This state will not be entered if + // more than one packet data bearer is active + // and one of the active bearers is + // deactivated +mavlink10.CELLULAR_STATUS_FLAG_CONNECTING = 11 // Modem is activating and connecting the first packet data bearer. + // Subsequent bearer activations when another + // bearer is already active do not cause this + // state to be entered +mavlink10.CELLULAR_STATUS_FLAG_CONNECTED = 12 // One or more packet data bearers is active and connected +mavlink10.CELLULAR_STATUS_FLAG_ENUM_END = 13 // + +// CELLULAR_NETWORK_FAILED_REASON +mavlink10.CELLULAR_NETWORK_FAILED_REASON_NONE = 0 // No error +mavlink10.CELLULAR_NETWORK_FAILED_REASON_UNKNOWN = 1 // Error state is unknown +mavlink10.CELLULAR_NETWORK_FAILED_REASON_SIM_MISSING = 2 // SIM is required for the modem but missing +mavlink10.CELLULAR_NETWORK_FAILED_REASON_SIM_ERROR = 3 // SIM is available, but not usuable for connection +mavlink10.CELLULAR_NETWORK_FAILED_REASON_ENUM_END = 4 // + // PRECISION_LAND_MODE mavlink10.PRECISION_LAND_MODE_DISABLED = 0 // Normal (non-precision) landing. mavlink10.PRECISION_LAND_MODE_OPPORTUNISTIC = 1 // Use precision landing if beacon detected when land command accepted, @@ -2014,11 +2210,381 @@ mavlink10.PRECISION_LAND_MODE_REQUIRED = 2 // Use precision landing, searching f mavlink10.PRECISION_LAND_MODE_ENUM_END = 3 // // PARACHUTE_ACTION -mavlink10.PARACHUTE_DISABLE = 0 // Disable parachute release. -mavlink10.PARACHUTE_ENABLE = 1 // Enable parachute release. -mavlink10.PARACHUTE_RELEASE = 2 // Release parachute. +mavlink10.PARACHUTE_DISABLE = 0 // Disable auto-release of parachute (i.e. release triggered by crash + // detectors). +mavlink10.PARACHUTE_ENABLE = 1 // Enable auto-release of parachute. +mavlink10.PARACHUTE_RELEASE = 2 // Release parachute and kill motors. mavlink10.PARACHUTE_ACTION_ENUM_END = 3 // +// MAV_TUNNEL_PAYLOAD_TYPE +mavlink10.MAV_TUNNEL_PAYLOAD_TYPE_UNKNOWN = 0 // Encoding of payload unknown. +mavlink10.MAV_TUNNEL_PAYLOAD_TYPE_STORM32_RESERVED0 = 200 // Registered for STorM32 gimbal controller. +mavlink10.MAV_TUNNEL_PAYLOAD_TYPE_STORM32_RESERVED1 = 201 // Registered for STorM32 gimbal controller. +mavlink10.MAV_TUNNEL_PAYLOAD_TYPE_STORM32_RESERVED2 = 202 // Registered for STorM32 gimbal controller. +mavlink10.MAV_TUNNEL_PAYLOAD_TYPE_STORM32_RESERVED3 = 203 // Registered for STorM32 gimbal controller. +mavlink10.MAV_TUNNEL_PAYLOAD_TYPE_STORM32_RESERVED4 = 204 // Registered for STorM32 gimbal controller. +mavlink10.MAV_TUNNEL_PAYLOAD_TYPE_STORM32_RESERVED5 = 205 // Registered for STorM32 gimbal controller. +mavlink10.MAV_TUNNEL_PAYLOAD_TYPE_STORM32_RESERVED6 = 206 // Registered for STorM32 gimbal controller. +mavlink10.MAV_TUNNEL_PAYLOAD_TYPE_STORM32_RESERVED7 = 207 // Registered for STorM32 gimbal controller. +mavlink10.MAV_TUNNEL_PAYLOAD_TYPE_STORM32_RESERVED8 = 208 // Registered for STorM32 gimbal controller. +mavlink10.MAV_TUNNEL_PAYLOAD_TYPE_STORM32_RESERVED9 = 209 // Registered for STorM32 gimbal controller. +mavlink10.MAV_TUNNEL_PAYLOAD_TYPE_ENUM_END = 210 // + +// MAV_ODID_ID_TYPE +mavlink10.MAV_ODID_ID_TYPE_NONE = 0 // No type defined. +mavlink10.MAV_ODID_ID_TYPE_SERIAL_NUMBER = 1 // Manufacturer Serial Number (ANSI/CTA-2063 format). +mavlink10.MAV_ODID_ID_TYPE_CAA_REGISTRATION_ID = 2 // CAA (Civil Aviation Authority) registered ID. Format: [ICAO Country + // Code].[CAA Assigned ID]. +mavlink10.MAV_ODID_ID_TYPE_UTM_ASSIGNED_UUID = 3 // UTM (Unmanned Traffic Management) assigned UUID (RFC4122). +mavlink10.MAV_ODID_ID_TYPE_ENUM_END = 4 // + +// MAV_ODID_UA_TYPE +mavlink10.MAV_ODID_UA_TYPE_NONE = 0 // No UA (Unmanned Aircraft) type defined. +mavlink10.MAV_ODID_UA_TYPE_AEROPLANE = 1 // Aeroplane/Airplane. Fixed wing. +mavlink10.MAV_ODID_UA_TYPE_HELICOPTER_OR_MULTIROTOR = 2 // Helicopter or multirotor. +mavlink10.MAV_ODID_UA_TYPE_GYROPLANE = 3 // Gyroplane. +mavlink10.MAV_ODID_UA_TYPE_HYBRID_LIFT = 4 // VTOL (Vertical Take-Off and Landing). Fixed wing aircraft that can + // take off vertically. +mavlink10.MAV_ODID_UA_TYPE_ORNITHOPTER = 5 // Ornithopter. +mavlink10.MAV_ODID_UA_TYPE_GLIDER = 6 // Glider. +mavlink10.MAV_ODID_UA_TYPE_KITE = 7 // Kite. +mavlink10.MAV_ODID_UA_TYPE_FREE_BALLOON = 8 // Free Balloon. +mavlink10.MAV_ODID_UA_TYPE_CAPTIVE_BALLOON = 9 // Captive Balloon. +mavlink10.MAV_ODID_UA_TYPE_AIRSHIP = 10 // Airship. E.g. a blimp. +mavlink10.MAV_ODID_UA_TYPE_FREE_FALL_PARACHUTE = 11 // Free Fall/Parachute (unpowered). +mavlink10.MAV_ODID_UA_TYPE_ROCKET = 12 // Rocket. +mavlink10.MAV_ODID_UA_TYPE_TETHERED_POWERED_AIRCRAFT = 13 // Tethered powered aircraft. +mavlink10.MAV_ODID_UA_TYPE_GROUND_OBSTACLE = 14 // Ground Obstacle. +mavlink10.MAV_ODID_UA_TYPE_OTHER = 15 // Other type of aircraft not listed earlier. +mavlink10.MAV_ODID_UA_TYPE_ENUM_END = 16 // + +// MAV_ODID_STATUS +mavlink10.MAV_ODID_STATUS_UNDECLARED = 0 // The status of the (UA) Unmanned Aircraft is undefined. +mavlink10.MAV_ODID_STATUS_GROUND = 1 // The UA is on the ground. +mavlink10.MAV_ODID_STATUS_AIRBORNE = 2 // The UA is in the air. +mavlink10.MAV_ODID_STATUS_EMERGENCY = 3 // The UA is having an emergency. +mavlink10.MAV_ODID_STATUS_ENUM_END = 4 // + +// MAV_ODID_HEIGHT_REF +mavlink10.MAV_ODID_HEIGHT_REF_OVER_TAKEOFF = 0 // The height field is relative to the take-off location. +mavlink10.MAV_ODID_HEIGHT_REF_OVER_GROUND = 1 // The height field is relative to ground. +mavlink10.MAV_ODID_HEIGHT_REF_ENUM_END = 2 // + +// MAV_ODID_HOR_ACC +mavlink10.MAV_ODID_HOR_ACC_UNKNOWN = 0 // The horizontal accuracy is unknown. +mavlink10.MAV_ODID_HOR_ACC_10NM = 1 // The horizontal accuracy is smaller than 10 Nautical Miles. 18.52 km. +mavlink10.MAV_ODID_HOR_ACC_4NM = 2 // The horizontal accuracy is smaller than 4 Nautical Miles. 7.408 km. +mavlink10.MAV_ODID_HOR_ACC_2NM = 3 // The horizontal accuracy is smaller than 2 Nautical Miles. 3.704 km. +mavlink10.MAV_ODID_HOR_ACC_1NM = 4 // The horizontal accuracy is smaller than 1 Nautical Miles. 1.852 km. +mavlink10.MAV_ODID_HOR_ACC_0_5NM = 5 // The horizontal accuracy is smaller than 0.5 Nautical Miles. 926 m. +mavlink10.MAV_ODID_HOR_ACC_0_3NM = 6 // The horizontal accuracy is smaller than 0.3 Nautical Miles. 555.6 m. +mavlink10.MAV_ODID_HOR_ACC_0_1NM = 7 // The horizontal accuracy is smaller than 0.1 Nautical Miles. 185.2 m. +mavlink10.MAV_ODID_HOR_ACC_0_05NM = 8 // The horizontal accuracy is smaller than 0.05 Nautical Miles. 92.6 m. +mavlink10.MAV_ODID_HOR_ACC_30_METER = 9 // The horizontal accuracy is smaller than 30 meter. +mavlink10.MAV_ODID_HOR_ACC_10_METER = 10 // The horizontal accuracy is smaller than 10 meter. +mavlink10.MAV_ODID_HOR_ACC_3_METER = 11 // The horizontal accuracy is smaller than 3 meter. +mavlink10.MAV_ODID_HOR_ACC_1_METER = 12 // The horizontal accuracy is smaller than 1 meter. +mavlink10.MAV_ODID_HOR_ACC_ENUM_END = 13 // + +// MAV_ODID_VER_ACC +mavlink10.MAV_ODID_VER_ACC_UNKNOWN = 0 // The vertical accuracy is unknown. +mavlink10.MAV_ODID_VER_ACC_150_METER = 1 // The vertical accuracy is smaller than 150 meter. +mavlink10.MAV_ODID_VER_ACC_45_METER = 2 // The vertical accuracy is smaller than 45 meter. +mavlink10.MAV_ODID_VER_ACC_25_METER = 3 // The vertical accuracy is smaller than 25 meter. +mavlink10.MAV_ODID_VER_ACC_10_METER = 4 // The vertical accuracy is smaller than 10 meter. +mavlink10.MAV_ODID_VER_ACC_3_METER = 5 // The vertical accuracy is smaller than 3 meter. +mavlink10.MAV_ODID_VER_ACC_1_METER = 6 // The vertical accuracy is smaller than 1 meter. +mavlink10.MAV_ODID_VER_ACC_ENUM_END = 7 // + +// MAV_ODID_SPEED_ACC +mavlink10.MAV_ODID_SPEED_ACC_UNKNOWN = 0 // The speed accuracy is unknown. +mavlink10.MAV_ODID_SPEED_ACC_10_METERS_PER_SECOND = 1 // The speed accuracy is smaller than 10 meters per second. +mavlink10.MAV_ODID_SPEED_ACC_3_METERS_PER_SECOND = 2 // The speed accuracy is smaller than 3 meters per second. +mavlink10.MAV_ODID_SPEED_ACC_1_METERS_PER_SECOND = 3 // The speed accuracy is smaller than 1 meters per second. +mavlink10.MAV_ODID_SPEED_ACC_0_3_METERS_PER_SECOND = 4 // The speed accuracy is smaller than 0.3 meters per second. +mavlink10.MAV_ODID_SPEED_ACC_ENUM_END = 5 // + +// MAV_ODID_TIME_ACC +mavlink10.MAV_ODID_TIME_ACC_UNKNOWN = 0 // The timestamp accuracy is unknown. +mavlink10.MAV_ODID_TIME_ACC_0_1_SECOND = 1 // The timestamp accuracy is smaller than or equal to 0.1 second. +mavlink10.MAV_ODID_TIME_ACC_0_2_SECOND = 2 // The timestamp accuracy is smaller than or equal to 0.2 second. +mavlink10.MAV_ODID_TIME_ACC_0_3_SECOND = 3 // The timestamp accuracy is smaller than or equal to 0.3 second. +mavlink10.MAV_ODID_TIME_ACC_0_4_SECOND = 4 // The timestamp accuracy is smaller than or equal to 0.4 second. +mavlink10.MAV_ODID_TIME_ACC_0_5_SECOND = 5 // The timestamp accuracy is smaller than or equal to 0.5 second. +mavlink10.MAV_ODID_TIME_ACC_0_6_SECOND = 6 // The timestamp accuracy is smaller than or equal to 0.6 second. +mavlink10.MAV_ODID_TIME_ACC_0_7_SECOND = 7 // The timestamp accuracy is smaller than or equal to 0.7 second. +mavlink10.MAV_ODID_TIME_ACC_0_8_SECOND = 8 // The timestamp accuracy is smaller than or equal to 0.8 second. +mavlink10.MAV_ODID_TIME_ACC_0_9_SECOND = 9 // The timestamp accuracy is smaller than or equal to 0.9 second. +mavlink10.MAV_ODID_TIME_ACC_1_0_SECOND = 10 // The timestamp accuracy is smaller than or equal to 1.0 second. +mavlink10.MAV_ODID_TIME_ACC_1_1_SECOND = 11 // The timestamp accuracy is smaller than or equal to 1.1 second. +mavlink10.MAV_ODID_TIME_ACC_1_2_SECOND = 12 // The timestamp accuracy is smaller than or equal to 1.2 second. +mavlink10.MAV_ODID_TIME_ACC_1_3_SECOND = 13 // The timestamp accuracy is smaller than or equal to 1.3 second. +mavlink10.MAV_ODID_TIME_ACC_1_4_SECOND = 14 // The timestamp accuracy is smaller than or equal to 1.4 second. +mavlink10.MAV_ODID_TIME_ACC_1_5_SECOND = 15 // The timestamp accuracy is smaller than or equal to 1.5 second. +mavlink10.MAV_ODID_TIME_ACC_ENUM_END = 16 // + +// MAV_ODID_AUTH_TYPE +mavlink10.MAV_ODID_AUTH_TYPE_NONE = 0 // No authentication type is specified. +mavlink10.MAV_ODID_AUTH_TYPE_UAS_ID_SIGNATURE = 1 // Signature for the UAS (Unmanned Aircraft System) ID. +mavlink10.MAV_ODID_AUTH_TYPE_OPERATOR_ID_SIGNATURE = 2 // Signature for the Operator ID. +mavlink10.MAV_ODID_AUTH_TYPE_MESSAGE_SET_SIGNATURE = 3 // Signature for the entire message set. +mavlink10.MAV_ODID_AUTH_TYPE_NETWORK_REMOTE_ID = 4 // Authentication is provided by Network Remote ID. +mavlink10.MAV_ODID_AUTH_TYPE_ENUM_END = 5 // + +// MAV_ODID_DESC_TYPE +mavlink10.MAV_ODID_DESC_TYPE_TEXT = 0 // Free-form text description of the purpose of the flight. +mavlink10.MAV_ODID_DESC_TYPE_ENUM_END = 1 // + +// MAV_ODID_OPERATOR_LOCATION_TYPE +mavlink10.MAV_ODID_OPERATOR_LOCATION_TYPE_TAKEOFF = 0 // The location of the operator is the same as the take-off location. +mavlink10.MAV_ODID_OPERATOR_LOCATION_TYPE_LIVE_GNSS = 1 // The location of the operator is based on live GNSS data. +mavlink10.MAV_ODID_OPERATOR_LOCATION_TYPE_FIXED = 2 // The location of the operator is a fixed location. +mavlink10.MAV_ODID_OPERATOR_LOCATION_TYPE_ENUM_END = 3 // + +// MAV_ODID_CLASSIFICATION_TYPE +mavlink10.MAV_ODID_CLASSIFICATION_TYPE_UNDECLARED = 0 // The classification type for the UA is undeclared. +mavlink10.MAV_ODID_CLASSIFICATION_TYPE_EU = 1 // The classification type for the UA follows EU (European Union) + // specifications. +mavlink10.MAV_ODID_CLASSIFICATION_TYPE_ENUM_END = 2 // + +// MAV_ODID_CATEGORY_EU +mavlink10.MAV_ODID_CATEGORY_EU_UNDECLARED = 0 // The category for the UA, according to the EU specification, is + // undeclared. +mavlink10.MAV_ODID_CATEGORY_EU_OPEN = 1 // The category for the UA, according to the EU specification, is the + // Open category. +mavlink10.MAV_ODID_CATEGORY_EU_SPECIFIC = 2 // The category for the UA, according to the EU specification, is the + // Specific category. +mavlink10.MAV_ODID_CATEGORY_EU_CERTIFIED = 3 // The category for the UA, according to the EU specification, is the + // Certified category. +mavlink10.MAV_ODID_CATEGORY_EU_ENUM_END = 4 // + +// MAV_ODID_CLASS_EU +mavlink10.MAV_ODID_CLASS_EU_UNDECLARED = 0 // The class for the UA, according to the EU specification, is + // undeclared. +mavlink10.MAV_ODID_CLASS_EU_CLASS_0 = 1 // The class for the UA, according to the EU specification, is Class 0. +mavlink10.MAV_ODID_CLASS_EU_CLASS_1 = 2 // The class for the UA, according to the EU specification, is Class 1. +mavlink10.MAV_ODID_CLASS_EU_CLASS_2 = 3 // The class for the UA, according to the EU specification, is Class 2. +mavlink10.MAV_ODID_CLASS_EU_CLASS_3 = 4 // The class for the UA, according to the EU specification, is Class 3. +mavlink10.MAV_ODID_CLASS_EU_CLASS_4 = 5 // The class for the UA, according to the EU specification, is Class 4. +mavlink10.MAV_ODID_CLASS_EU_CLASS_5 = 6 // The class for the UA, according to the EU specification, is Class 5. +mavlink10.MAV_ODID_CLASS_EU_CLASS_6 = 7 // The class for the UA, according to the EU specification, is Class 6. +mavlink10.MAV_ODID_CLASS_EU_ENUM_END = 8 // + +// MAV_ODID_OPERATOR_ID_TYPE +mavlink10.MAV_ODID_OPERATOR_ID_TYPE_CAA = 0 // CAA (Civil Aviation Authority) registered operator ID. +mavlink10.MAV_ODID_OPERATOR_ID_TYPE_ENUM_END = 1 // + +// TUNE_FORMAT +mavlink10.TUNE_FORMAT_QBASIC1_1 = 1 // Format is QBasic 1.1 Play: + // https://www.qbasic.net/en/reference/qb11/St + // atement/PLAY-006.htm. +mavlink10.TUNE_FORMAT_MML_MODERN = 2 // Format is Modern Music Markup Language (MML): + // https://en.wikipedia.org/wiki/Music_Macro_L + // anguage#Modern_MML. +mavlink10.TUNE_FORMAT_ENUM_END = 3 // + +// COMPONENT_CAP_FLAGS +mavlink10.COMPONENT_CAP_FLAGS_PARAM = 1 // Component has parameters, and supports the parameter protocol (PARAM + // messages). +mavlink10.COMPONENT_CAP_FLAGS_PARAM_EXT = 2 // Component has parameters, and supports the extended parameter protocol + // (PARAM_EXT messages). +mavlink10.COMPONENT_CAP_FLAGS_ENUM_END = 3 // + +// AIS_TYPE +mavlink10.AIS_TYPE_UNKNOWN = 0 // Not available (default). +mavlink10.AIS_TYPE_RESERVED_1 = 1 // +mavlink10.AIS_TYPE_RESERVED_2 = 2 // +mavlink10.AIS_TYPE_RESERVED_3 = 3 // +mavlink10.AIS_TYPE_RESERVED_4 = 4 // +mavlink10.AIS_TYPE_RESERVED_5 = 5 // +mavlink10.AIS_TYPE_RESERVED_6 = 6 // +mavlink10.AIS_TYPE_RESERVED_7 = 7 // +mavlink10.AIS_TYPE_RESERVED_8 = 8 // +mavlink10.AIS_TYPE_RESERVED_9 = 9 // +mavlink10.AIS_TYPE_RESERVED_10 = 10 // +mavlink10.AIS_TYPE_RESERVED_11 = 11 // +mavlink10.AIS_TYPE_RESERVED_12 = 12 // +mavlink10.AIS_TYPE_RESERVED_13 = 13 // +mavlink10.AIS_TYPE_RESERVED_14 = 14 // +mavlink10.AIS_TYPE_RESERVED_15 = 15 // +mavlink10.AIS_TYPE_RESERVED_16 = 16 // +mavlink10.AIS_TYPE_RESERVED_17 = 17 // +mavlink10.AIS_TYPE_RESERVED_18 = 18 // +mavlink10.AIS_TYPE_RESERVED_19 = 19 // +mavlink10.AIS_TYPE_WIG = 20 // Wing In Ground effect. +mavlink10.AIS_TYPE_WIG_HAZARDOUS_A = 21 // +mavlink10.AIS_TYPE_WIG_HAZARDOUS_B = 22 // +mavlink10.AIS_TYPE_WIG_HAZARDOUS_C = 23 // +mavlink10.AIS_TYPE_WIG_HAZARDOUS_D = 24 // +mavlink10.AIS_TYPE_WIG_RESERVED_1 = 25 // +mavlink10.AIS_TYPE_WIG_RESERVED_2 = 26 // +mavlink10.AIS_TYPE_WIG_RESERVED_3 = 27 // +mavlink10.AIS_TYPE_WIG_RESERVED_4 = 28 // +mavlink10.AIS_TYPE_WIG_RESERVED_5 = 29 // +mavlink10.AIS_TYPE_FISHING = 30 // +mavlink10.AIS_TYPE_TOWING = 31 // +mavlink10.AIS_TYPE_TOWING_LARGE = 32 // Towing: length exceeds 200m or breadth exceeds 25m. +mavlink10.AIS_TYPE_DREDGING = 33 // Dredging or other underwater ops. +mavlink10.AIS_TYPE_DIVING = 34 // +mavlink10.AIS_TYPE_MILITARY = 35 // +mavlink10.AIS_TYPE_SAILING = 36 // +mavlink10.AIS_TYPE_PLEASURE = 37 // +mavlink10.AIS_TYPE_RESERVED_20 = 38 // +mavlink10.AIS_TYPE_RESERVED_21 = 39 // +mavlink10.AIS_TYPE_HSC = 40 // High Speed Craft. +mavlink10.AIS_TYPE_HSC_HAZARDOUS_A = 41 // +mavlink10.AIS_TYPE_HSC_HAZARDOUS_B = 42 // +mavlink10.AIS_TYPE_HSC_HAZARDOUS_C = 43 // +mavlink10.AIS_TYPE_HSC_HAZARDOUS_D = 44 // +mavlink10.AIS_TYPE_HSC_RESERVED_1 = 45 // +mavlink10.AIS_TYPE_HSC_RESERVED_2 = 46 // +mavlink10.AIS_TYPE_HSC_RESERVED_3 = 47 // +mavlink10.AIS_TYPE_HSC_RESERVED_4 = 48 // +mavlink10.AIS_TYPE_HSC_UNKNOWN = 49 // +mavlink10.AIS_TYPE_PILOT = 50 // +mavlink10.AIS_TYPE_SAR = 51 // Search And Rescue vessel. +mavlink10.AIS_TYPE_TUG = 52 // +mavlink10.AIS_TYPE_PORT_TENDER = 53 // +mavlink10.AIS_TYPE_ANTI_POLLUTION = 54 // Anti-pollution equipment. +mavlink10.AIS_TYPE_LAW_ENFORCEMENT = 55 // +mavlink10.AIS_TYPE_SPARE_LOCAL_1 = 56 // +mavlink10.AIS_TYPE_SPARE_LOCAL_2 = 57 // +mavlink10.AIS_TYPE_MEDICAL_TRANSPORT = 58 // +mavlink10.AIS_TYPE_NONECOMBATANT = 59 // Noncombatant ship according to RR Resolution No. 18. +mavlink10.AIS_TYPE_PASSENGER = 60 // +mavlink10.AIS_TYPE_PASSENGER_HAZARDOUS_A = 61 // +mavlink10.AIS_TYPE_PASSENGER_HAZARDOUS_B = 62 // +mavlink10.AIS_TYPE_AIS_TYPE_PASSENGER_HAZARDOUS_C = 63 // +mavlink10.AIS_TYPE_PASSENGER_HAZARDOUS_D = 64 // +mavlink10.AIS_TYPE_PASSENGER_RESERVED_1 = 65 // +mavlink10.AIS_TYPE_PASSENGER_RESERVED_2 = 66 // +mavlink10.AIS_TYPE_PASSENGER_RESERVED_3 = 67 // +mavlink10.AIS_TYPE_AIS_TYPE_PASSENGER_RESERVED_4 = 68 // +mavlink10.AIS_TYPE_PASSENGER_UNKNOWN = 69 // +mavlink10.AIS_TYPE_CARGO = 70 // +mavlink10.AIS_TYPE_CARGO_HAZARDOUS_A = 71 // +mavlink10.AIS_TYPE_CARGO_HAZARDOUS_B = 72 // +mavlink10.AIS_TYPE_CARGO_HAZARDOUS_C = 73 // +mavlink10.AIS_TYPE_CARGO_HAZARDOUS_D = 74 // +mavlink10.AIS_TYPE_CARGO_RESERVED_1 = 75 // +mavlink10.AIS_TYPE_CARGO_RESERVED_2 = 76 // +mavlink10.AIS_TYPE_CARGO_RESERVED_3 = 77 // +mavlink10.AIS_TYPE_CARGO_RESERVED_4 = 78 // +mavlink10.AIS_TYPE_CARGO_UNKNOWN = 79 // +mavlink10.AIS_TYPE_TANKER = 80 // +mavlink10.AIS_TYPE_TANKER_HAZARDOUS_A = 81 // +mavlink10.AIS_TYPE_TANKER_HAZARDOUS_B = 82 // +mavlink10.AIS_TYPE_TANKER_HAZARDOUS_C = 83 // +mavlink10.AIS_TYPE_TANKER_HAZARDOUS_D = 84 // +mavlink10.AIS_TYPE_TANKER_RESERVED_1 = 85 // +mavlink10.AIS_TYPE_TANKER_RESERVED_2 = 86 // +mavlink10.AIS_TYPE_TANKER_RESERVED_3 = 87 // +mavlink10.AIS_TYPE_TANKER_RESERVED_4 = 88 // +mavlink10.AIS_TYPE_TANKER_UNKNOWN = 89 // +mavlink10.AIS_TYPE_OTHER = 90 // +mavlink10.AIS_TYPE_OTHER_HAZARDOUS_A = 91 // +mavlink10.AIS_TYPE_OTHER_HAZARDOUS_B = 92 // +mavlink10.AIS_TYPE_OTHER_HAZARDOUS_C = 93 // +mavlink10.AIS_TYPE_OTHER_HAZARDOUS_D = 94 // +mavlink10.AIS_TYPE_OTHER_RESERVED_1 = 95 // +mavlink10.AIS_TYPE_OTHER_RESERVED_2 = 96 // +mavlink10.AIS_TYPE_OTHER_RESERVED_3 = 97 // +mavlink10.AIS_TYPE_OTHER_RESERVED_4 = 98 // +mavlink10.AIS_TYPE_OTHER_UNKNOWN = 99 // +mavlink10.AIS_TYPE_ENUM_END = 100 // + +// AIS_NAV_STATUS +mavlink10.UNDER_WAY = 0 // Under way using engine. +mavlink10.AIS_NAV_ANCHORED = 1 // +mavlink10.AIS_NAV_UN_COMMANDED = 2 // +mavlink10.AIS_NAV_RESTRICTED_MANOEUVERABILITY = 3 // +mavlink10.AIS_NAV_DRAUGHT_CONSTRAINED = 4 // +mavlink10.AIS_NAV_MOORED = 5 // +mavlink10.AIS_NAV_AGROUND = 6 // +mavlink10.AIS_NAV_FISHING = 7 // +mavlink10.AIS_NAV_SAILING = 8 // +mavlink10.AIS_NAV_RESERVED_HSC = 9 // +mavlink10.AIS_NAV_RESERVED_WIG = 10 // +mavlink10.AIS_NAV_RESERVED_1 = 11 // +mavlink10.AIS_NAV_RESERVED_2 = 12 // +mavlink10.AIS_NAV_RESERVED_3 = 13 // +mavlink10.AIS_NAV_AIS_SART = 14 // Search And Rescue Transponder. +mavlink10.AIS_NAV_UNKNOWN = 15 // Not available (default). +mavlink10.AIS_NAV_STATUS_ENUM_END = 16 // + +// AIS_FLAGS +mavlink10.AIS_FLAGS_POSITION_ACCURACY = 1 // 1 = Position accuracy less than 10m, 0 = position accuracy greater + // than 10m. +mavlink10.AIS_FLAGS_VALID_COG = 2 // +mavlink10.AIS_FLAGS_VALID_VELOCITY = 4 // +mavlink10.AIS_FLAGS_HIGH_VELOCITY = 8 // 1 = Velocity over 52.5765m/s (102.2 knots) +mavlink10.AIS_FLAGS_VALID_TURN_RATE = 16 // +mavlink10.AIS_FLAGS_TURN_RATE_SIGN_ONLY = 32 // Only the sign of the returned turn rate value is valid, either greater + // than 5deg/30s or less than -5deg/30s +mavlink10.AIS_FLAGS_VALID_DIMENSIONS = 64 // +mavlink10.AIS_FLAGS_LARGE_BOW_DIMENSION = 128 // Distance to bow is larger than 511m +mavlink10.AIS_FLAGS_LARGE_STERN_DIMENSION = 256 // Distance to stern is larger than 511m +mavlink10.AIS_FLAGS_LARGE_PORT_DIMENSION = 512 // Distance to port side is larger than 63m +mavlink10.AIS_FLAGS_LARGE_STARBOARD_DIMENSION = 1024 // Distance to starboard side is larger than 63m +mavlink10.AIS_FLAGS_VALID_CALLSIGN = 2048 // +mavlink10.AIS_FLAGS_VALID_NAME = 4096 // +mavlink10.AIS_FLAGS_ENUM_END = 4097 // + +// FAILURE_UNIT +mavlink10.FAILURE_UNIT_SENSOR_GYRO = 0 // +mavlink10.FAILURE_UNIT_SENSOR_ACCEL = 1 // +mavlink10.FAILURE_UNIT_SENSOR_MAG = 2 // +mavlink10.FAILURE_UNIT_SENSOR_BARO = 3 // +mavlink10.FAILURE_UNIT_SENSOR_GPS = 4 // +mavlink10.FAILURE_UNIT_SENSOR_OPTICAL_FLOW = 5 // +mavlink10.FAILURE_UNIT_SENSOR_VIO = 6 // +mavlink10.FAILURE_UNIT_SENSOR_DISTANCE_SENSOR = 7 // +mavlink10.FAILURE_UNIT_SENSOR_AIRSPEED = 8 // +mavlink10.FAILURE_UNIT_SYSTEM_BATTERY = 100 // +mavlink10.FAILURE_UNIT_SYSTEM_MOTOR = 101 // +mavlink10.FAILURE_UNIT_SYSTEM_SERVO = 102 // +mavlink10.FAILURE_UNIT_SYSTEM_AVOIDANCE = 103 // +mavlink10.FAILURE_UNIT_SYSTEM_RC_SIGNAL = 104 // +mavlink10.FAILURE_UNIT_SYSTEM_MAVLINK_SIGNAL = 105 // +mavlink10.FAILURE_UNIT_ENUM_END = 106 // + +// FAILURE_TYPE +mavlink10.FAILURE_TYPE_OK = 0 // No failure injected, used to reset a previous failure. +mavlink10.FAILURE_TYPE_OFF = 1 // Sets unit off, so completely non-responsive. +mavlink10.FAILURE_TYPE_STUCK = 2 // Unit is stuck e.g. keeps reporting the same value. +mavlink10.FAILURE_TYPE_GARBAGE = 3 // Unit is reporting complete garbage. +mavlink10.FAILURE_TYPE_WRONG = 4 // Unit is consistently wrong. +mavlink10.FAILURE_TYPE_SLOW = 5 // Unit is slow, so e.g. reporting at slower than expected rate. +mavlink10.FAILURE_TYPE_DELAYED = 6 // Data of unit is delayed in time. +mavlink10.FAILURE_TYPE_INTERMITTENT = 7 // Unit is sometimes working, sometimes not. +mavlink10.FAILURE_TYPE_ENUM_END = 8 // + +// MAV_WINCH_STATUS_FLAG +mavlink10.MAV_WINCH_STATUS_HEALTHY = 1 // Winch is healthy +mavlink10.MAV_WINCH_STATUS_FULLY_RETRACTED = 2 // Winch thread is fully retracted +mavlink10.MAV_WINCH_STATUS_MOVING = 4 // Winch motor is moving +mavlink10.MAV_WINCH_STATUS_CLUTCH_ENGAGED = 8 // Winch clutch is engaged allowing motor to move freely +mavlink10.MAV_WINCH_STATUS_FLAG_ENUM_END = 9 // + +// MAG_CAL_STATUS +mavlink10.MAG_CAL_NOT_STARTED = 0 // +mavlink10.MAG_CAL_WAITING_TO_START = 1 // +mavlink10.MAG_CAL_RUNNING_STEP_ONE = 2 // +mavlink10.MAG_CAL_RUNNING_STEP_TWO = 3 // +mavlink10.MAG_CAL_SUCCESS = 4 // +mavlink10.MAG_CAL_FAILED = 5 // +mavlink10.MAG_CAL_BAD_ORIENTATION = 6 // +mavlink10.MAG_CAL_BAD_RADIUS = 7 // +mavlink10.MAG_CAL_STATUS_ENUM_END = 8 // + +// MAV_EVENT_ERROR_REASON +mavlink10.MAV_EVENT_ERROR_REASON_UNAVAILABLE = 0 // The requested event is not available (anymore). +mavlink10.MAV_EVENT_ERROR_REASON_ENUM_END = 1 // + +// MAV_EVENT_CURRENT_SEQUENCE_FLAGS +mavlink10.MAV_EVENT_CURRENT_SEQUENCE_FLAGS_RESET = 1 // A sequence reset has happened (e.g. vehicle reboot). +mavlink10.MAV_EVENT_CURRENT_SEQUENCE_FLAGS_ENUM_END = 2 // + // UAVIONIX_ADSB_OUT_DYNAMIC_STATE mavlink10.UAVIONIX_ADSB_OUT_DYNAMIC_STATE_INTENT_CHANGE = 1 // mavlink10.UAVIONIX_ADSB_OUT_DYNAMIC_STATE_AUTOPILOT_ENABLED = 2 // @@ -2110,6 +2676,420 @@ mavlink10.ICAROUS_FMS_STATE_APPROACH = 4 // mavlink10.ICAROUS_FMS_STATE_LAND = 5 // mavlink10.ICAROUS_FMS_STATE_ENUM_END = 6 // +// MAV_AUTOPILOT +mavlink10.MAV_AUTOPILOT_GENERIC = 0 // Generic autopilot, full support for everything +mavlink10.MAV_AUTOPILOT_RESERVED = 1 // Reserved for future use. +mavlink10.MAV_AUTOPILOT_SLUGS = 2 // SLUGS autopilot, http://slugsuav.soe.ucsc.edu +mavlink10.MAV_AUTOPILOT_ARDUPILOTMEGA = 3 // ArduPilot - Plane/Copter/Rover/Sub/Tracker, https://ardupilot.org +mavlink10.MAV_AUTOPILOT_OPENPILOT = 4 // OpenPilot, http://openpilot.org +mavlink10.MAV_AUTOPILOT_GENERIC_WAYPOINTS_ONLY = 5 // Generic autopilot only supporting simple waypoints +mavlink10.MAV_AUTOPILOT_GENERIC_WAYPOINTS_AND_SIMPLE_NAVIGATION_ONLY = 6 // Generic autopilot supporting waypoints and other simple navigation + // commands +mavlink10.MAV_AUTOPILOT_GENERIC_MISSION_FULL = 7 // Generic autopilot supporting the full mission command set +mavlink10.MAV_AUTOPILOT_INVALID = 8 // No valid autopilot, e.g. a GCS or other MAVLink component +mavlink10.MAV_AUTOPILOT_PPZ = 9 // PPZ UAV - http://nongnu.org/paparazzi +mavlink10.MAV_AUTOPILOT_UDB = 10 // UAV Dev Board +mavlink10.MAV_AUTOPILOT_FP = 11 // FlexiPilot +mavlink10.MAV_AUTOPILOT_PX4 = 12 // PX4 Autopilot - http://px4.io/ +mavlink10.MAV_AUTOPILOT_SMACCMPILOT = 13 // SMACCMPilot - http://smaccmpilot.org +mavlink10.MAV_AUTOPILOT_AUTOQUAD = 14 // AutoQuad -- http://autoquad.org +mavlink10.MAV_AUTOPILOT_ARMAZILA = 15 // Armazila -- http://armazila.com +mavlink10.MAV_AUTOPILOT_AEROB = 16 // Aerob -- http://aerob.ru +mavlink10.MAV_AUTOPILOT_ASLUAV = 17 // ASLUAV autopilot -- http://www.asl.ethz.ch +mavlink10.MAV_AUTOPILOT_SMARTAP = 18 // SmartAP Autopilot - http://sky-drones.com +mavlink10.MAV_AUTOPILOT_AIRRAILS = 19 // AirRails - http://uaventure.com +mavlink10.MAV_AUTOPILOT_ENUM_END = 20 // + +// MAV_TYPE +mavlink10.MAV_TYPE_GENERIC = 0 // Generic micro air vehicle +mavlink10.MAV_TYPE_FIXED_WING = 1 // Fixed wing aircraft. +mavlink10.MAV_TYPE_QUADROTOR = 2 // Quadrotor +mavlink10.MAV_TYPE_COAXIAL = 3 // Coaxial helicopter +mavlink10.MAV_TYPE_HELICOPTER = 4 // Normal helicopter with tail rotor. +mavlink10.MAV_TYPE_ANTENNA_TRACKER = 5 // Ground installation +mavlink10.MAV_TYPE_GCS = 6 // Operator control unit / ground control station +mavlink10.MAV_TYPE_AIRSHIP = 7 // Airship, controlled +mavlink10.MAV_TYPE_FREE_BALLOON = 8 // Free balloon, uncontrolled +mavlink10.MAV_TYPE_ROCKET = 9 // Rocket +mavlink10.MAV_TYPE_GROUND_ROVER = 10 // Ground rover +mavlink10.MAV_TYPE_SURFACE_BOAT = 11 // Surface vessel, boat, ship +mavlink10.MAV_TYPE_SUBMARINE = 12 // Submarine +mavlink10.MAV_TYPE_HEXAROTOR = 13 // Hexarotor +mavlink10.MAV_TYPE_OCTOROTOR = 14 // Octorotor +mavlink10.MAV_TYPE_TRICOPTER = 15 // Tricopter +mavlink10.MAV_TYPE_FLAPPING_WING = 16 // Flapping wing +mavlink10.MAV_TYPE_KITE = 17 // Kite +mavlink10.MAV_TYPE_ONBOARD_CONTROLLER = 18 // Onboard companion controller +mavlink10.MAV_TYPE_VTOL_DUOROTOR = 19 // Two-rotor VTOL using control surfaces in vertical operation in + // addition. Tailsitter. +mavlink10.MAV_TYPE_VTOL_QUADROTOR = 20 // Quad-rotor VTOL using a V-shaped quad config in vertical operation. + // Tailsitter. +mavlink10.MAV_TYPE_VTOL_TILTROTOR = 21 // Tiltrotor VTOL +mavlink10.MAV_TYPE_VTOL_RESERVED2 = 22 // VTOL reserved 2 +mavlink10.MAV_TYPE_VTOL_RESERVED3 = 23 // VTOL reserved 3 +mavlink10.MAV_TYPE_VTOL_RESERVED4 = 24 // VTOL reserved 4 +mavlink10.MAV_TYPE_VTOL_RESERVED5 = 25 // VTOL reserved 5 +mavlink10.MAV_TYPE_GIMBAL = 26 // Gimbal +mavlink10.MAV_TYPE_ADSB = 27 // ADSB system +mavlink10.MAV_TYPE_PARAFOIL = 28 // Steerable, nonrigid airfoil +mavlink10.MAV_TYPE_DODECAROTOR = 29 // Dodecarotor +mavlink10.MAV_TYPE_CAMERA = 30 // Camera +mavlink10.MAV_TYPE_CHARGING_STATION = 31 // Charging station +mavlink10.MAV_TYPE_FLARM = 32 // FLARM collision avoidance system +mavlink10.MAV_TYPE_SERVO = 33 // Servo +mavlink10.MAV_TYPE_ODID = 34 // Open Drone ID. See https://mavlink.io/en/services/opendroneid.html. +mavlink10.MAV_TYPE_DECAROTOR = 35 // Decarotor +mavlink10.MAV_TYPE_BATTERY = 36 // Battery +mavlink10.MAV_TYPE_ENUM_END = 37 // + +// MAV_MODE_FLAG +mavlink10.MAV_MODE_FLAG_CUSTOM_MODE_ENABLED = 1 // 0b00000001 Reserved for future use. +mavlink10.MAV_MODE_FLAG_TEST_ENABLED = 2 // 0b00000010 system has a test mode enabled. This flag is intended for + // temporary system tests and should not be + // used for stable implementations. +mavlink10.MAV_MODE_FLAG_AUTO_ENABLED = 4 // 0b00000100 autonomous mode enabled, system finds its own goal + // positions. Guided flag can be set or not, + // depends on the actual implementation. +mavlink10.MAV_MODE_FLAG_GUIDED_ENABLED = 8 // 0b00001000 guided mode enabled, system flies waypoints / mission + // items. +mavlink10.MAV_MODE_FLAG_STABILIZE_ENABLED = 16 // 0b00010000 system stabilizes electronically its attitude (and + // optionally position). It needs however + // further control inputs to move around. +mavlink10.MAV_MODE_FLAG_HIL_ENABLED = 32 // 0b00100000 hardware in the loop simulation. All motors / actuators are + // blocked, but internal software is full + // operational. +mavlink10.MAV_MODE_FLAG_MANUAL_INPUT_ENABLED = 64 // 0b01000000 remote control input is enabled. +mavlink10.MAV_MODE_FLAG_SAFETY_ARMED = 128 // 0b10000000 MAV safety set to armed. Motors are enabled / running / can + // start. Ready to fly. Additional note: this + // flag is to be ignore when sent in the + // command MAV_CMD_DO_SET_MODE and + // MAV_CMD_COMPONENT_ARM_DISARM shall be used + // instead. The flag can still be used to + // report the armed state. +mavlink10.MAV_MODE_FLAG_ENUM_END = 129 // + +// MAV_MODE_FLAG_DECODE_POSITION +mavlink10.MAV_MODE_FLAG_DECODE_POSITION_CUSTOM_MODE = 1 // Eighth bit: 00000001 +mavlink10.MAV_MODE_FLAG_DECODE_POSITION_TEST = 2 // Seventh bit: 00000010 +mavlink10.MAV_MODE_FLAG_DECODE_POSITION_AUTO = 4 // Sixth bit: 00000100 +mavlink10.MAV_MODE_FLAG_DECODE_POSITION_GUIDED = 8 // Fifth bit: 00001000 +mavlink10.MAV_MODE_FLAG_DECODE_POSITION_STABILIZE = 16 // Fourth bit: 00010000 +mavlink10.MAV_MODE_FLAG_DECODE_POSITION_HIL = 32 // Third bit: 00100000 +mavlink10.MAV_MODE_FLAG_DECODE_POSITION_MANUAL = 64 // Second bit: 01000000 +mavlink10.MAV_MODE_FLAG_DECODE_POSITION_SAFETY = 128 // First bit: 10000000 +mavlink10.MAV_MODE_FLAG_DECODE_POSITION_ENUM_END = 129 // + +// MAV_STATE +mavlink10.MAV_STATE_UNINIT = 0 // Uninitialized system, state is unknown. +mavlink10.MAV_STATE_BOOT = 1 // System is booting up. +mavlink10.MAV_STATE_CALIBRATING = 2 // System is calibrating and not flight-ready. +mavlink10.MAV_STATE_STANDBY = 3 // System is grounded and on standby. It can be launched any time. +mavlink10.MAV_STATE_ACTIVE = 4 // System is active and might be already airborne. Motors are engaged. +mavlink10.MAV_STATE_CRITICAL = 5 // System is in a non-normal flight mode. It can however still navigate. +mavlink10.MAV_STATE_EMERGENCY = 6 // System is in a non-normal flight mode. It lost control over parts or + // over the whole airframe. It is in mayday + // and going down. +mavlink10.MAV_STATE_POWEROFF = 7 // System just initialized its power-down sequence, will shut down now. +mavlink10.MAV_STATE_FLIGHT_TERMINATION = 8 // System is terminating itself. +mavlink10.MAV_STATE_ENUM_END = 9 // + +// MAV_COMPONENT +mavlink10.MAV_COMP_ID_ALL = 0 // Target id (target_component) used to broadcast messages to all + // components of the receiving system. + // Components should attempt to process + // messages with this component ID and forward + // to components on any other interfaces. + // Note: This is not a valid *source* + // component id for a message. +mavlink10.MAV_COMP_ID_AUTOPILOT1 = 1 // System flight controller component ("autopilot"). Only one autopilot + // is expected in a particular system. +mavlink10.MAV_COMP_ID_USER1 = 25 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER2 = 26 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER3 = 27 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER4 = 28 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER5 = 29 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER6 = 30 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER7 = 31 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER8 = 32 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER9 = 33 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER10 = 34 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER11 = 35 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER12 = 36 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER13 = 37 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER14 = 38 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER15 = 39 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER16 = 40 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER17 = 41 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER18 = 42 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER19 = 43 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER20 = 44 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER21 = 45 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER22 = 46 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER23 = 47 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER24 = 48 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER25 = 49 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER26 = 50 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER27 = 51 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER28 = 52 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER29 = 53 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER30 = 54 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER31 = 55 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER32 = 56 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER33 = 57 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER34 = 58 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER35 = 59 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER36 = 60 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER37 = 61 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER38 = 62 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER39 = 63 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER40 = 64 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER41 = 65 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER42 = 66 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER43 = 67 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_TELEMETRY_RADIO = 68 // Telemetry radio (e.g. SiK radio, or other component that emits + // RADIO_STATUS messages). +mavlink10.MAV_COMP_ID_USER45 = 69 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER46 = 70 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER47 = 71 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER48 = 72 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER49 = 73 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER50 = 74 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER51 = 75 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER52 = 76 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER53 = 77 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER54 = 78 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER55 = 79 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER56 = 80 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER57 = 81 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER58 = 82 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER59 = 83 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER60 = 84 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER61 = 85 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER62 = 86 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER63 = 87 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER64 = 88 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER65 = 89 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER66 = 90 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER67 = 91 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER68 = 92 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER69 = 93 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER70 = 94 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER71 = 95 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER72 = 96 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER73 = 97 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER74 = 98 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_USER75 = 99 // Id for a component on privately managed MAVLink network. Can be used + // for any purpose but may not be published by + // components outside of the private network. +mavlink10.MAV_COMP_ID_CAMERA = 100 // Camera #1. +mavlink10.MAV_COMP_ID_CAMERA2 = 101 // Camera #2. +mavlink10.MAV_COMP_ID_CAMERA3 = 102 // Camera #3. +mavlink10.MAV_COMP_ID_CAMERA4 = 103 // Camera #4. +mavlink10.MAV_COMP_ID_CAMERA5 = 104 // Camera #5. +mavlink10.MAV_COMP_ID_CAMERA6 = 105 // Camera #6. +mavlink10.MAV_COMP_ID_SERVO1 = 140 // Servo #1. +mavlink10.MAV_COMP_ID_SERVO2 = 141 // Servo #2. +mavlink10.MAV_COMP_ID_SERVO3 = 142 // Servo #3. +mavlink10.MAV_COMP_ID_SERVO4 = 143 // Servo #4. +mavlink10.MAV_COMP_ID_SERVO5 = 144 // Servo #5. +mavlink10.MAV_COMP_ID_SERVO6 = 145 // Servo #6. +mavlink10.MAV_COMP_ID_SERVO7 = 146 // Servo #7. +mavlink10.MAV_COMP_ID_SERVO8 = 147 // Servo #8. +mavlink10.MAV_COMP_ID_SERVO9 = 148 // Servo #9. +mavlink10.MAV_COMP_ID_SERVO10 = 149 // Servo #10. +mavlink10.MAV_COMP_ID_SERVO11 = 150 // Servo #11. +mavlink10.MAV_COMP_ID_SERVO12 = 151 // Servo #12. +mavlink10.MAV_COMP_ID_SERVO13 = 152 // Servo #13. +mavlink10.MAV_COMP_ID_SERVO14 = 153 // Servo #14. +mavlink10.MAV_COMP_ID_GIMBAL = 154 // Gimbal #1. +mavlink10.MAV_COMP_ID_LOG = 155 // Logging component. +mavlink10.MAV_COMP_ID_ADSB = 156 // Automatic Dependent Surveillance-Broadcast (ADS-B) component. +mavlink10.MAV_COMP_ID_OSD = 157 // On Screen Display (OSD) devices for video links. +mavlink10.MAV_COMP_ID_PERIPHERAL = 158 // Generic autopilot peripheral component ID. Meant for devices that do + // not implement the parameter microservice. +mavlink10.MAV_COMP_ID_QX1_GIMBAL = 159 // Gimbal ID for QX1. +mavlink10.MAV_COMP_ID_FLARM = 160 // FLARM collision alert component. +mavlink10.MAV_COMP_ID_GIMBAL2 = 171 // Gimbal #2. +mavlink10.MAV_COMP_ID_GIMBAL3 = 172 // Gimbal #3. +mavlink10.MAV_COMP_ID_GIMBAL4 = 173 // Gimbal #4 +mavlink10.MAV_COMP_ID_GIMBAL5 = 174 // Gimbal #5. +mavlink10.MAV_COMP_ID_GIMBAL6 = 175 // Gimbal #6. +mavlink10.MAV_COMP_ID_BATTERY = 180 // Battery #1. +mavlink10.MAV_COMP_ID_BATTERY2 = 181 // Battery #2. +mavlink10.MAV_COMP_ID_MISSIONPLANNER = 190 // Component that can generate/supply a mission flight plan (e.g. GCS or + // developer API). +mavlink10.MAV_COMP_ID_ONBOARD_COMPUTER = 191 // Component that lives on the onboard computer (companion computer) and + // has some generic functionalities, such as + // settings system parameters and monitoring + // the status of some processes that don't + // directly speak mavlink and so on. +mavlink10.MAV_COMP_ID_PATHPLANNER = 195 // Component that finds an optimal path between points based on a certain + // constraint (e.g. minimum snap, shortest + // path, cost, etc.). +mavlink10.MAV_COMP_ID_OBSTACLE_AVOIDANCE = 196 // Component that plans a collision free path between two points. +mavlink10.MAV_COMP_ID_VISUAL_INERTIAL_ODOMETRY = 197 // Component that provides position estimates using VIO techniques. +mavlink10.MAV_COMP_ID_PAIRING_MANAGER = 198 // Component that manages pairing of vehicle and GCS. +mavlink10.MAV_COMP_ID_IMU = 200 // Inertial Measurement Unit (IMU) #1. +mavlink10.MAV_COMP_ID_IMU_2 = 201 // Inertial Measurement Unit (IMU) #2. +mavlink10.MAV_COMP_ID_IMU_3 = 202 // Inertial Measurement Unit (IMU) #3. +mavlink10.MAV_COMP_ID_GPS = 220 // GPS #1. +mavlink10.MAV_COMP_ID_GPS2 = 221 // GPS #2. +mavlink10.MAV_COMP_ID_ODID_TXRX_1 = 236 // Open Drone ID transmitter/receiver (Bluetooth/WiFi/Internet). +mavlink10.MAV_COMP_ID_ODID_TXRX_2 = 237 // Open Drone ID transmitter/receiver (Bluetooth/WiFi/Internet). +mavlink10.MAV_COMP_ID_ODID_TXRX_3 = 238 // Open Drone ID transmitter/receiver (Bluetooth/WiFi/Internet). +mavlink10.MAV_COMP_ID_UDP_BRIDGE = 240 // Component to bridge MAVLink to UDP (i.e. from a UART). +mavlink10.MAV_COMP_ID_UART_BRIDGE = 241 // Component to bridge to UART (i.e. from UDP). +mavlink10.MAV_COMP_ID_TUNNEL_NODE = 242 // Component handling TUNNEL messages (e.g. vendor specific GUI of a + // component). +mavlink10.MAV_COMP_ID_SYSTEM_CONTROL = 250 // Component for handling system messages (e.g. to ARM, takeoff, etc.). +mavlink10.MAV_COMPONENT_ENUM_END = 251 // + // message IDs mavlink10.MAVLINK_MSG_ID_BAD_DATA = -1 mavlink10.MAVLINK_MSG_ID_SENSOR_OFFSETS = 150 @@ -2148,7 +3128,6 @@ mavlink10.MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK = 184 mavlink10.MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS = 185 mavlink10.MAVLINK_MSG_ID_LED_CONTROL = 186 mavlink10.MAVLINK_MSG_ID_MAG_CAL_PROGRESS = 191 -mavlink10.MAVLINK_MSG_ID_MAG_CAL_REPORT = 192 mavlink10.MAVLINK_MSG_ID_EKF_STATUS_REPORT = 193 mavlink10.MAVLINK_MSG_ID_PID_TUNING = 194 mavlink10.MAVLINK_MSG_ID_DEEPSTALL = 195 @@ -2160,16 +3139,16 @@ mavlink10.MAVLINK_MSG_ID_GOPRO_GET_REQUEST = 216 mavlink10.MAVLINK_MSG_ID_GOPRO_GET_RESPONSE = 217 mavlink10.MAVLINK_MSG_ID_GOPRO_SET_REQUEST = 218 mavlink10.MAVLINK_MSG_ID_GOPRO_SET_RESPONSE = 219 -mavlink10.MAVLINK_MSG_ID_EFI_STATUS = 225 mavlink10.MAVLINK_MSG_ID_RPM = 226 -mavlink10.MAVLINK_MSG_ID_HEARTBEAT = 0 mavlink10.MAVLINK_MSG_ID_SYS_STATUS = 1 mavlink10.MAVLINK_MSG_ID_SYSTEM_TIME = 2 mavlink10.MAVLINK_MSG_ID_PING = 4 mavlink10.MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL = 5 mavlink10.MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK = 6 mavlink10.MAVLINK_MSG_ID_AUTH_KEY = 7 +mavlink10.MAVLINK_MSG_ID_LINK_NODE_STATUS = 8 mavlink10.MAVLINK_MSG_ID_SET_MODE = 11 +mavlink10.MAVLINK_MSG_ID_PARAM_ACK_TRANSACTION = 19 mavlink10.MAVLINK_MSG_ID_PARAM_REQUEST_READ = 20 mavlink10.MAVLINK_MSG_ID_PARAM_REQUEST_LIST = 21 mavlink10.MAVLINK_MSG_ID_PARAM_VALUE = 22 @@ -2202,6 +3181,7 @@ mavlink10.MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN = 48 mavlink10.MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN = 49 mavlink10.MAVLINK_MSG_ID_PARAM_MAP_RC = 50 mavlink10.MAVLINK_MSG_ID_MISSION_REQUEST_INT = 51 +mavlink10.MAVLINK_MSG_ID_MISSION_CHANGED = 52 mavlink10.MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA = 54 mavlink10.MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA = 55 mavlink10.MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV = 61 @@ -2218,6 +3198,7 @@ mavlink10.MAVLINK_MSG_ID_VFR_HUD = 74 mavlink10.MAVLINK_MSG_ID_COMMAND_INT = 75 mavlink10.MAVLINK_MSG_ID_COMMAND_LONG = 76 mavlink10.MAVLINK_MSG_ID_COMMAND_ACK = 77 +mavlink10.MAVLINK_MSG_ID_COMMAND_CANCEL = 80 mavlink10.MAVLINK_MSG_ID_MANUAL_SETPOINT = 81 mavlink10.MAVLINK_MSG_ID_SET_ATTITUDE_TARGET = 82 mavlink10.MAVLINK_MSG_ID_ATTITUDE_TARGET = 83 @@ -2280,11 +3261,14 @@ mavlink10.MAVLINK_MSG_ID_BATTERY_STATUS = 147 mavlink10.MAVLINK_MSG_ID_AUTOPILOT_VERSION = 148 mavlink10.MAVLINK_MSG_ID_LANDING_TARGET = 149 mavlink10.MAVLINK_MSG_ID_FENCE_STATUS = 162 +mavlink10.MAVLINK_MSG_ID_MAG_CAL_REPORT = 192 +mavlink10.MAVLINK_MSG_ID_EFI_STATUS = 225 mavlink10.MAVLINK_MSG_ID_ESTIMATOR_STATUS = 230 mavlink10.MAVLINK_MSG_ID_WIND_COV = 231 mavlink10.MAVLINK_MSG_ID_GPS_INPUT = 232 mavlink10.MAVLINK_MSG_ID_GPS_RTCM_DATA = 233 mavlink10.MAVLINK_MSG_ID_HIGH_LATENCY = 234 +mavlink10.MAVLINK_MSG_ID_HIGH_LATENCY2 = 235 mavlink10.MAVLINK_MSG_ID_VIBRATION = 241 mavlink10.MAVLINK_MSG_ID_HOME_POSITION = 242 mavlink10.MAVLINK_MSG_ID_SET_HOME_POSITION = 243 @@ -2299,6 +3283,7 @@ mavlink10.MAVLINK_MSG_ID_NAMED_VALUE_FLOAT = 251 mavlink10.MAVLINK_MSG_ID_NAMED_VALUE_INT = 252 mavlink10.MAVLINK_MSG_ID_STATUSTEXT = 253 mavlink10.MAVLINK_MSG_ID_DEBUG = 254 +mavlink10.MAVLINK_MSG_ID_HEARTBEAT = 0 mavlink10.messages = {}; /* @@ -3369,67 +4354,28 @@ Reports progress of compass calibration. attempt : Attempt number. (uint8_t) completion_pct : Completion percentage. (uint8_t) completion_mask : Bitmask of sphere sections (see http://en.wikipedia.org/wiki/Geodesic_grid). (uint8_t) - direction_x : Body frame direction vector for display. (float) - direction_y : Body frame direction vector for display. (float) - direction_z : Body frame direction vector for display. (float) - -*/ -mavlink10.messages.mag_cal_progress = function(compass_id, cal_mask, cal_status, attempt, completion_pct, completion_mask, direction_x, direction_y, direction_z) { - - this.format = ' value[float]. @@ -4172,13 +5111,17 @@ mavlink10.messages.param_value.prototype.pack = function(mav) { /* Set a parameter value (write new value to permanent storage). -IMPORTANT: The receiving component should acknowledge the new -parameter value by sending a PARAM_VALUE message to all communication -partners. This will also ensure that multiple GCS all have an up-to- -date list of all parameters. If the sending GCS did not receive a -PARAM_VALUE message within its timeout time, it should re-send the -PARAM_SET message. The parameter microservice is documented at -https://mavlink.io/en/services/parameter.html +The receiving component should acknowledge the new parameter value by +broadcasting a PARAM_VALUE message (broadcasting ensures that multiple +GCS all have an up-to-date list of all parameters). If the sending GCS +did not receive a PARAM_VALUE within its timeout time, it should re- +send the PARAM_SET message. The parameter microservice is documented +at https://mavlink.io/en/services/parameter.html. PARAM_SET +may also be called within the context of a transaction (started with +MAV_CMD_PARAM_TRANSACTION). Within a transaction the receiving +component should respond with PARAM_ACK_TRANSACTION to the setter +component (instead of broadcasting PARAM_VALUE), and PARAM_SET should +be re-sent if this is ACK not received. target_system : System ID (uint8_t) target_component : Component ID (uint8_t) @@ -4212,13 +5155,13 @@ The global position, as returned by the Global Positioning System system, but rather a RAW sensor value. See message GLOBAL_POSITION for the global position estimate. - time_usec : Timestamp (UNIX Epoch time or time since system boot). The receiving end can infer timestamp format (since 1.1.1970 or since system boot) by checking for the magnitude the number. (uint64_t) + time_usec : Timestamp (UNIX Epoch time or time since system boot). The receiving end can infer timestamp format (since 1.1.1970 or since system boot) by checking for the magnitude of the number. (uint64_t) fix_type : GPS fix type. (uint8_t) lat : Latitude (WGS84, EGM96 ellipsoid) (int32_t) lon : Longitude (WGS84, EGM96 ellipsoid) (int32_t) alt : Altitude (MSL). Positive for up. Note that virtually all GPS modules provide the MSL altitude in addition to the WGS84 altitude. (int32_t) - eph : GPS HDOP horizontal dilution of position (unitless). If unknown, set to: UINT16_MAX (uint16_t) - epv : GPS VDOP vertical dilution of position (unitless). If unknown, set to: UINT16_MAX (uint16_t) + eph : GPS HDOP horizontal dilution of position (unitless * 100). If unknown, set to: UINT16_MAX (uint16_t) + epv : GPS VDOP vertical dilution of position (unitless * 100). If unknown, set to: UINT16_MAX (uint16_t) vel : GPS ground speed. If unknown, set to: UINT16_MAX (uint16_t) cog : Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX (uint16_t) satellites_visible : Number of satellites visible. If unknown, set to 255 (uint8_t) @@ -4317,7 +5260,7 @@ The RAW IMU readings for a 9DOF sensor, which is identified by the id (default IMU1). This message should always contain the true raw values without any scaling to allow data capture and system debugging. - time_usec : Timestamp (UNIX Epoch time or time since system boot). The receiving end can infer timestamp format (since 1.1.1970 or since system boot) by checking for the magnitude the number. (uint64_t) + time_usec : Timestamp (UNIX Epoch time or time since system boot). The receiving end can infer timestamp format (since 1.1.1970 or since system boot) by checking for the magnitude of the number. (uint64_t) xacc : X acceleration (raw) (int16_t) yacc : Y acceleration (raw) (int16_t) zacc : Z acceleration (raw) (int16_t) @@ -4353,7 +5296,7 @@ The RAW pressure readings for the typical setup of one absolute pressure and one differential pressure sensor. The sensor values should be the raw, UNSCALED ADC values. - time_usec : Timestamp (UNIX Epoch time or time since system boot). The receiving end can infer timestamp format (since 1.1.1970 or since system boot) by checking for the magnitude the number. (uint64_t) + time_usec : Timestamp (UNIX Epoch time or time since system boot). The receiving end can infer timestamp format (since 1.1.1970 or since system boot) by checking for the magnitude of the number. (uint64_t) press_abs : Absolute pressure (raw) (int16_t) press_diff1 : Differential pressure 1 (raw, 0 if nonexistent) (int16_t) press_diff2 : Differential pressure 2 (raw, 0 if nonexistent) (int16_t) @@ -4387,7 +5330,7 @@ field. time_boot_ms : Timestamp (time since system boot). (uint32_t) press_abs : Absolute pressure (float) press_diff : Differential pressure 1 (float) - temperature : Temperature (int16_t) + temperature : Absolute pressure temperature (int16_t) */ mavlink10.messages.scaled_pressure = function(time_boot_ms, press_abs, press_diff, temperature) { @@ -4624,7 +5567,7 @@ outputs (for RC input from the remote, use the RC_CHANNELS messages). The standard PPM modulation is as follows: 1000 microseconds: 0%, 2000 microseconds: 100%. - time_usec : Timestamp (UNIX Epoch time or time since system boot). The receiving end can infer timestamp format (since 1.1.1970 or since system boot) by checking for the magnitude the number. (uint32_t) + time_usec : Timestamp (UNIX Epoch time or time since system boot). The receiving end can infer timestamp format (since 1.1.1970 or since system boot) by checking for the magnitude of the number. (uint32_t) port : Servo output port (set of 8 outputs = 1 port). Flight stacks running on Pixhawk should use: 0 = MAIN, 1 = AUX. (uint8_t) servo1_raw : Servo output 1 value (uint16_t) servo2_raw : Servo output 2 value (uint16_t) @@ -4721,7 +5664,9 @@ Message encoding a mission item. This message is emitted to announce the presence of a mission item and to set a mission item on the system. The mission item can be either in x, y, z meters (type: LOCAL) or x:lat, y:lon, z:altitude. Local frame is Z-down, right handed -(NED), global frame is Z-up, right handed (ENU). See also +(NED), global frame is Z-up, right handed (ENU). NaN may be used to +indicate an optional/default value (e.g. to use the system's current +latitude or yaw rather than a specific value). See also https://mavlink.io/en/services/mission.html. target_system : System ID (uint8_t) @@ -5106,6 +6051,36 @@ mavlink10.messages.mission_request_int.prototype.pack = function(mav) { return mavlink10.message.prototype.pack.call(this, mav, this.crc_extra, jspack.Pack(this.format, [ this.seq, this.target_system, this.target_component])); } +/* +A broadcast message to notify any ground station or SDK if a mission, +geofence or safe points have changed on the vehicle. + + start_index : Start index for partial mission change (-1 for all items). (int16_t) + end_index : End index of a partial mission change. -1 is a synonym for the last mission item (i.e. selects all items from start_index). Ignore field if start_index=-1. (int16_t) + origin_sysid : System ID of the author of the new mission. (uint8_t) + origin_compid : Compnent ID of the author of the new mission. (uint8_t) + mission_type : Mission type. (uint8_t) + +*/ +mavlink10.messages.mission_changed = function(start_index, end_index, origin_sysid, origin_compid, mission_type) { + + this.format = '"+i+"==>"+args[i]+" -> "+JSON.stringify(this)); - } - }, this); -// then modify +mavlink20.message.prototype.set = function(args) { _.each(this.fieldnames, function(e, i) { this[e] = args[i]; }, this); }; -// trying to be the same-ish as the python function of the same name -mavlink20.message.prototype.sign_packet = function( mav) { - var crypto= require('crypto'); - var h = crypto.createHash('sha256'); - - //mav.signing.timestamp is a 48bit number, or 6 bytes. - - // due to js not being able to shift numbers more than 32, we'll use this instead.. - // js stores all its numbers as a 64bit float with 53 bits of mantissa, so have room for 48 ok. - // positive shifts left, negative shifts right - function shift(number, shift) { - return number * Math.pow(2, shift); - } - - var thigh = shift(mav.signing.timestamp,-32) // 2 bytes from the top, shifted right by 32 bits - var tlow = (mav.signing.timestamp & 0xfffffff ) // 4 bytes from the bottom - -// return jspack.Pack('HB', [ ((this.msgId & 0xFF) << 8) | ((this.msgId >> 8) & 0xFF), this.msgId>>16]); - -/* - // I means unsigned 4bytes, H means unsigned 2 bytes - var t = jspack.Unpack(' 1 && this._payload[plen-1] == 0) { - plen = plen - 1; - } - this._payload = this._payload.slice(0, plen); - // signing is our first incompat flag. - var incompat_flags = 0; - if (mav.signing.sign_outgoing){ - incompat_flags |= mavlink20.MAVLINK_IFLAG_SIGNED - } - // header - this._header = new mavlink20.header(this._id, this._payload.length, mav.seq, mav.srcSystem, mav.srcComponent, incompat_flags, 0,); - // payload - this._msgbuf = this._header.pack().concat(this._payload); - // crc - for now, assume always using crc_extra = True. TODO: check/fix this. - var crc = mavlink20.x25Crc(this._msgbuf.slice(1)); - crc = mavlink20.x25Crc([crc_extra], crc); - this._msgbuf = this._msgbuf.concat(jspack.Pack(' 1 && this.payload[plen-1] == 0) { + plen = plen - 1; + } + this.payload = this.payload.slice(0, plen); + var incompat_flags = 0; + this.header = new mavlink20.header(this.id, this.payload.length, mav.seq, mav.srcSystem, mav.srcComponent, incompat_flags, 0,); + this.msgbuf = this.header.pack().concat(this.payload); + var crc = mavlink20.x25Crc(this.msgbuf.slice(1)); - return this._msgbuf; + // For now, assume always using crc_extra = True. TODO: check/fix this. + crc = mavlink20.x25Crc([crc_extra], crc); + this.msgbuf = this.msgbuf.concat(jspack.Pack(' MAV. Also used to +return a point from MAV -> GCS. + + target_system : System ID. (uint8_t) + target_component : Component ID. (uint8_t) + idx : Point index (first point is 1, 0 is for return point). (uint8_t) + count : Total number of points (for sanity checking). (uint8_t) + lat : Latitude of point. (float) + lng : Longitude of point. (float) + +*/ +mavlink20.messages.fence_point = function(target_system, target_component, idx, count, lat, lng) { + + this.format = ' MAV. Also used to +return a point from MAV -> GCS. + + target_system : System ID. (uint8_t) + target_component : Component ID. (uint8_t) + idx : Point index (first point is 0). (uint8_t) + count : Total number of points (for sanity checking). (uint8_t) + lat : Latitude of point. (int32_t) + lng : Longitude of point. (int32_t) + alt : Transit / loiter altitude relative to home. (int16_t) + break_alt : Break altitude relative to home. (int16_t) + land_dir : Heading to aim for when landing. (uint16_t) + flags : Configuration flags. (uint8_t) + +*/ +mavlink20.messages.rally_point = function(target_system, target_component, idx, count, lat, lng, alt, break_alt, land_dir, flags) { + + this.format = ' MAV. Also used to -return a point from MAV -> GCS. +Camera vision based attitude and position deltas. - target_system : System ID. (uint8_t) - target_component : Component ID. (uint8_t) - idx : Point index (first point is 1, 0 is for return point). (uint8_t) - count : Total number of points (for sanity checking). (uint8_t) - lat : Latitude of point. (float) - lng : Longitude of point. (float) + time_usec : Timestamp (synced to UNIX time or since system boot). (uint64_t) + time_delta_usec : Time since the last reported camera frame. (uint64_t) + angle_delta : Defines a rotation vector [roll, pitch, yaw] to the current MAV_FRAME_BODY_FRD from the previous MAV_FRAME_BODY_FRD. (float) + position_delta : Change in position to the current MAV_FRAME_BODY_FRD from the previous FRAME_BODY_FRD rotated to the current MAV_FRAME_BODY_FRD. (float) + confidence : Normalised confidence value from 0 to 100. (float) */ - mavlink20.messages.fence_point = function(target_system, target_component, idx, count, lat, lng) { - - this._format = ' MAV. Also used to -return a point from MAV -> GCS. +Accept / deny control of this MAV - target_system : System ID. (uint8_t) - target_component : Component ID. (uint8_t) - idx : Point index (first point is 0). (uint8_t) - count : Total number of points (for sanity checking). (uint8_t) - lat : Latitude of point. (int32_t) - lng : Longitude of point. (int32_t) - alt : Transit / loiter altitude relative to home. (int16_t) - break_alt : Break altitude relative to home. (int16_t) - land_dir : Heading to aim for when landing. (uint16_t) - flags : Configuration flags. (uint8_t) + gcs_system_id : ID of the GCS this message (uint8_t) + control_request : 0: request control of this MAV, 1: Release control of this MAV (uint8_t) + ack : 0: ACK, 1: NACK: Wrong passkey, 2: NACK: Unsupported passkey encryption method, 3: NACK: Already under control (uint8_t) */ - mavlink20.messages.rally_point = function(target_system, target_component, idx, count, lat, lng, alt, break_alt, land_dir, flags) { - - this._format = ' value[float]. +This allows to send a parameter to any other component (such as the +GCS) without the need of previous knowledge of possible parameter +names. Thus the same GCS can store different parameters for different +autopilots. See also https://mavlink.io/en/services/parameter.html for +a full documentation of QGroundControl and IMU code. - time_usec : Image timestamp (since UNIX epoch), as passed in by CAMERA_STATUS message (or autopilot if no CCB). (uint64_t) - target_system : System ID. (uint8_t) - cam_idx : Camera ID. (uint8_t) - img_idx : Image index. (uint16_t) - lat : Latitude. (int32_t) - lng : Longitude. (int32_t) - alt_msl : Altitude (MSL). (float) - alt_rel : Altitude (Relative to HOME location). (float) - roll : Camera Roll angle (earth frame, +-180). (float) - pitch : Camera Pitch angle (earth frame, +-180). (float) - yaw : Camera Yaw (earth frame, 0-360, true). (float) - foc_len : Focal Length. (float) - flags : Feedback flags. (uint8_t) - completed_captures : Completed image captures. (uint16_t) + target_system : System ID (uint8_t) + target_component : Component ID (uint8_t) + param_id : Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string (char) + param_index : Parameter index. Send -1 to use the param ID field as identifier (else the param id will be ignored) (int16_t) */ - mavlink20.messages.camera_feedback = function(time_usec, target_system, cam_idx, img_idx, lat, lng, alt_msl, alt_rel, roll, pitch, yaw, foc_len, flags, completed_captures) { +mavlink20.messages.param_request_read = function(target_system, target_component, param_id, param_index) { - this._format = ' value[float]. -This allows to send a parameter to any other component (such as the -GCS) without the need of previous knowledge of possible parameter -names. Thus the same GCS can store different parameters for different -autopilots. See also https://mavlink.io/en/services/parameter.html for -a full documentation of QGroundControl and IMU code. +The RAW values of the RC channels sent to the MAV to override info +received from the RC radio. The standard PPM modulation is as follows: +1000 microseconds: 0%, 2000 microseconds: 100%. Individual +receivers/transmitters might violate this specification. Note +carefully the semantic differences between the first 8 channels and +the subsequent channels target_system : System ID (uint8_t) target_component : Component ID (uint8_t) - param_id : Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string (char) - param_index : Parameter index. Send -1 to use the param ID field as identifier (else the param id will be ignored) (int16_t) - -*/ - mavlink20.messages.param_request_read = function(target_system, target_component, param_id, param_index) { - - this._format = ' 0 indicates the interval at which it is sent. (int32_t) */ - mavlink20.messages.log_request_list = function(target_system, target_component, start, end) { - - this._format = ' 0 indicates the interval at which it is sent. (int32_t) + target_system : System ID (uint8_t) + target_component : Component ID (uint8_t) + param_id : Parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string (char) + param_index : Parameter index. Set to -1 to use the Parameter ID field as identifier (else param_id will be ignored) (int16_t) */ - mavlink20.messages.message_interval = function(message_id, interval_us) { - - this._format = '= 1 && this.buf[0] == this.protocol_marker ) { + // this.have_prefix_error = false; + //} } // Determine the length. Leaves buffer untouched. -// Although the 'len' of a packet is available as of the second byte, the third byte with 'incompat_flags' lets us know if we have signing -// enabled, which affects the real-world length by the signature-block length of 13 bytes -// once successful, 'this.expected_length' is correctly set for the whole packet. MAVLink20Processor.prototype.parseLength = function() { - if( this.buf.length >= 3 ) { - var unpacked = jspack.Unpack('BBB', this.buf.slice(0, 3)); - var magic = unpacked[0]; // stx ie fd or fe etc - this.expected_length = unpacked[1] + mavlink20.HEADER_LEN + 2 // length of message + header + CRC (ie non-signed length) - this.incompat_flags = unpacked[2]; - // mavlink2 only.. in mavlink1, incompat_flags var above is actually the 'seq', but for this test its ok. - if ((magic == mavlink20.PROTOCOL_MARKER_V2 ) && ( this.incompat_flags & mavlink20.MAVLINK_IFLAG_SIGNED )){ - this.expected_length += mavlink20.MAVLINK_SIGNATURE_BLOCK_LEN; - } + if( this.buf.length >= 2 ) { + var unpacked = jspack.Unpack('BB', this.buf.slice(0, 2)); + this.expected_length = unpacked[1] + mavlink20.HEADER_LEN + 2 // length of message + header + CRC } } -// input some data bytes, possibly returning a new message - python equiv function is called parse_char / __parse_char_legacy +// input some data bytes, possibly returning a new message MAVLink20Processor.prototype.parseChar = function(c) { var m = null; @@ -13082,9 +13195,8 @@ MAVLink20Processor.prototype.parseChar = function(c) { } - // emit a packet-specific message as well as a generic message, user/s can choose to use either or both of these. if(null != m) { - this.emit(m._name, m); + this.emit(m.name, m); this.emit('message', m); } @@ -13092,26 +13204,22 @@ MAVLink20Processor.prototype.parseChar = function(c) { } -// continuation of python's __parse_char_legacy MAVLink20Processor.prototype.parsePayload = function() { var m = null; - // tip: this.expected_length and this.incompat_flags both already set correctly by parseLength(..) above - - // If we have enough bytes to try and read it, read it. - // shortest packet is header+checksum(2) with no payload, so we need at least that many - // but once we have a longer 'expected length' we have to read all of it. - if(( this.expected_length >= mavlink20.HEADER_LEN+2) && (this.buf.length >= this.expected_length) ) { + // If we have enough bytes to try and read it, read it. + if( this.expected_length >= 8 && this.buf.length >= this.expected_length ) { // Slice off the expected packet length, reset expectation to be to find a header. var mbuf = this.buf.slice(0, this.expected_length); - // TODO: slicing off the buffer should depend on the error produced by the decode() function - // - if we find a well formed message, cut-off the expected_length + // - if a message we find a well formed message, cut-off the expected_length // - if the message is not well formed (correct prefix by accident), cut-off 1 char only this.buf = this.buf.slice(this.expected_length); - this.expected_length = mavlink20.HEADER_LEN; // after attempting a parse, we'll next expect to find just a header. + this.expected_length = 6; + + // w.info("Attempting to parse packet, message candidate buffer is ["+mbuf.toByteArray()+"]"); try { m = this.decode(mbuf); @@ -13153,141 +13261,14 @@ MAVLink20Processor.prototype.parseBuffer = function(s) { } -// from Buffer to ArrayBuffer -function toArrayBuffer(buf) { - var ab = new ArrayBuffer(buf.length); - var view = new Uint8Array(ab); - for (var i = 0; i < buf.length; ++i) { - view[i] = buf[i]; - } - return ab; -} -// and back -function toBuffer(ab) { - var buf = Buffer.alloc(ab.byteLength); - var view = new Uint8Array(ab); - for (var i = 0; i < buf.length; ++i) { - buf[i] = view[i]; - } - return buf; -} - -//check signature on incoming message -MAVLink20Processor.prototype.check_signature = function(msgbuf, srcSystem, srcComponent) { - - //if (isinstance(msgbuf, array.array)){ - // msgbuf = msgbuf.tostring() - //} - if ( Buffer.isBuffer(msgbuf) ) { - msgbuf = toArrayBuffer(msgbuf); - } - - //timestamp_buf = msgbuf[-12:-6] - var timestamp_buf= msgbuf.slice(-12,-6); - - //link_id = msgbuf[-13] - var link_id= new Buffer.from(msgbuf.slice(-13,-12)); // just a single byte really, but returned as a buffer - link_id = link_id[0]; // get the first byte. - - //self.mav_sign_unpacker = jspack.Unpack('> 8) & 0xFF); // first-two msgid bytes - var msgIDhigh = unpacked[8]; // the 3rd msgid byte - msgId = msgIDlow | (msgIDhigh<<16); // combined result. 0 - 16777215 24bit number + var msgIDlow = ((unpacked[7] & 0xFF) << 8) | ((unpacked[7] >> 8) & 0xFF); + var msgIDhigh = unpacked[8]; + msgId = msgIDlow | (msgIDhigh<<16); } catch(e) { throw new Error('Unable to unpack MAVLink header: ' + e.message); } - // TODO allow full parsing of 1.0 inside the 2.0 parser, this is just a start - if (magic == mavlink20.PROTOCOL_MARKER_V1){ - //headerlen = 6; - - // these two are in the same place in both v1 and v2 so no change needed: - //magic = magic; - //mlen = mlen; - - // grab mavlink-v1 header position info from v2 unpacked position - seq1 = incompat_flags; - srcSystem1 = compat_flags; - srcComponent1 = seq; - msgId1 = srcSystem; - // override the v1 vs v2 offsets so we get the correct data either way... - seq = seq1; - srcSystem = srcSystem1; - srcComponent = srcComponent1; - msgId = msgId1; - // don't exist in mavlink1, so zero-them - incompat_flags = 0; - compat_flags = 0; - signature_len = 0; - // todo add more v1 here and don't just return - return; - } - if (magic.charCodeAt(0) != this.protocol_marker) { throw new Error("Invalid MAVLink prefix ("+magic.charCodeAt(0)+")"); } - // is packet supposed to be signed? - if ( incompat_flags & mavlink20.MAVLINK_IFLAG_SIGNED ){ - signature_len = mavlink20.MAVLINK_SIGNATURE_BLOCK_LEN; - //console.log("incompat_flags:",incompat_flags,signature_len); - } else { - signature_len = 0; - } - - // header's declared len compared to packets actual len - var actual_len = (msgbuf.length - (mavlink20.HEADER_LEN + 2 + signature_len)); - var actual_len_nosign = (msgbuf.length - (mavlink20.HEADER_LEN + 2 )); - - //console.log("mavlink20.HEADER_LEN " , mavlink20.HEADER_LEN); - //console.log("signature_len " , signature_len); - //console.log("msgbuf.length " , msgbuf.length); - //console.log("actual_len " , actual_len); - //console.log("actual_len_nosign " , actual_len_nosign); - //console.log("mlen " , mlen); - - if ((mlen == actual_len) && (signature_len > 0)){ - var len_if_signed = mlen+signature_len; - //console.log("Packet appears signed && labled as signed, OK. msgId=" + msgId); - - } else if ((mlen == actual_len_nosign) && (signature_len > 0)){ - - var len_if_signed = mlen+signature_len; - throw new Error("Packet appears unsigned when labled as signed. Got actual_len "+actual_len_nosign+" expected " + len_if_signed + ", msgId=" + msgId); - - } else if( mlen != actual_len) { - throw new Error("Invalid MAVLink message length. Got " + (msgbuf.length - (mavlink20.HEADER_LEN + 2)) + " expected " + mlen + ", msgId=" + msgId); - - } - + if( mlen != msgbuf.length - (mavlink20.HEADER_LEN + 2)) { + throw new Error("Invalid MAVLink message length. Got " + (msgbuf.length - (mavlink20.HEADER_LEN + 2)) + " expected " + mlen + ", msgId=" + msgId); + } + if( false === _.has(mavlink20.map, msgId) ) { throw new Error("Unknown MAVLink message ID (" + msgId + ")"); } - // here's the 4 common chunks of packer we want to work with below.. - var headerBuf= msgbuf.slice(mavlink20.HEADER_LEN); // first10 - var sigBuf = msgbuf.slice(-signature_len); // last 13 or nothing - var crcBuf1 = msgbuf.slice(-2); // either last-2 or last-2-prior-to-signature - var crcBuf2 = msgbuf.slice(-15,-13); // either last-2 or last-2-prior-to-signature - var payloadBuf = msgbuf.slice(mavlink20.HEADER_LEN, -(signature_len+2)); // the remaining bit between the header and the crc - var crcCheckBuf = msgbuf.slice(1, -(signature_len+2)); // the part uses to calculate the crc - ie between the magic and signature, - // decode the payload // refs: (fmt, type, order_map, crc_extra) = mavlink20.map[msgId] var decoder = mavlink20.map[msgId]; - //console.log("signature_len:",signature_len); - //console.log("sigBuf:",sigBuf); - //console.log("msgbuf:",msgbuf); - //console.log("crcBuf-nosig:",crcBuf1); - //console.log("crcBuf-sig:",crcBuf2); - //console.log("payloadBuf:",payloadBuf); - //console.log("crcCheckBuf:",crcCheckBuf); - // decode the checksum - var receivedChecksum = undefined; - if ( signature_len == 0 ) { // unsigned - try { - receivedChecksum = jspack.Unpack(' payloadBuf.length) { - payloadBuf = Buffer.concat([payloadBuf, Buffer.alloc(paylen - payloadBuf.length)]); + //put any truncated 0's back in + if (paylen > payload.length) { + payload = Buffer.concat([payload, Buffer.alloc(paylen - payload.length)]); } // Decode the payload and reorder the fields to match the order map. try { - var t = jspack.Unpack(decoder.format, payloadBuf); + var t = jspack.Unpack(decoder.format, payload); } catch (e) { - throw new Error('Unable to unpack MAVLink payload type='+decoder.type+' format='+decoder.format+' payloadLength='+ payloadBuf +': '+ e.message); + throw new Error('Unable to unpack MAVLink payload type='+decoder.type+' format='+decoder.format+' payloadLength='+ payload +': '+ e.message); } // Need to check if the message contains arrays @@ -13536,19 +13390,15 @@ MAVLink20Processor.prototype.decode = function(msgbuf) { // construct the message object try { var m = new decoder.type(args); - m.set.call(m, args,false); + m.set.call(m, args); } catch (e) { throw new Error('Unable to instantiate MAVLink message of type '+decoder.type+' : ' + e.message); } - - m._signed = sig_ok; - if (m._signed) { m._link_id = msgbuf[-13]; } - - m._msgbuf = msgbuf; - m._payload = payloadBuf + m.msgbuf = msgbuf; + m.payload = payload m.crc = receivedChecksum; - m._header = new mavlink20.header(msgId, mlen, seq, srcSystem, srcComponent, incompat_flags, compat_flags); + m.header = new mavlink20.header(msgId, mlen, seq, srcSystem, srcComponent, incompat_flags, compat_flags); this.log(m); return m; } diff --git a/node_index.html b/node_index.html index 0fb431c..244337d 100644 --- a/node_index.html +++ b/node_index.html @@ -317,7 +317,7 @@
Pitch: degrees
-
+
Vehicle Type:
Yaw: degrees
diff --git a/static/img/copter.svg b/static/img/copter.svg new file mode 100644 index 0000000..8b0f38c --- /dev/null +++ b/static/img/copter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/copter_black.png b/static/img/copter_black.png new file mode 100644 index 0000000000000000000000000000000000000000..4d9c588cd7d098f0e64502ee3875a39e906af1cd GIT binary patch literal 26844 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 Yh$Z-#sg^nw1V>|_XQErCee22p0BIQ9E&u=k literal 0 HcmV?d00001 diff --git a/static/img/copter_blue.png b/static/img/copter_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..362b05c8018897b7a4ab8a21e09a45e83261f251 GIT binary patch literal 28563 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%0AlqC0Lb*+*tsk^QSWYr1U*f?Yw znrs5%fRsVV9Y-(WClhJ%HRhM=-WwB;RB%ed*N4ihwlq3a^N~KD?gkDBD-aIHPZ>JO z#ONiU01;4e(6anfGPBSqr4rRL^WW(m12AQpM~|d`3U|Pf0$hgEyU#mR6K`a>!*tHa zry2001)+#Gb#W#v6shxBEBmDN*kPA_s{MOEyT0J(;j-FG*Jh~T>jE6PqbFgP^V;K* zt3rmLPL}pJb?Hosl5+$O5_RTFa^RdFm2CwV)@mF2N&!!6f$n?XFOX2NSr^yFx|65Z zct7gstdX-~jObgAazWkJiaEyVsp@j|K#2n>H72F`XqqTai0d~dVR zs>XkhMMu*c^z^1S4JH&nTM?gj<3{BE;;19#?* znCg6qEFtHoyOyspfh%LK1pqeN&kx}92EUg?Y$+((7-?zLZC&6ps2B0~>_Z9LW}~96 zrzKBPa&asRIdyg3Unu8x3F)tF;B-m-moZeePs5n@UES%+ypr9_Z|^>ph1lp`!$$x* z`ZFryjqcE-dA{1Zr2^hnqSWHC#Fpn_BJCRi-Et?(?a#QZeWtulKanMu8Gt%7`&mpT zy|!=fqz&8tu~CaCzA4JT_xE%8j6RBpf?0hBBYKDvZ3&@+q^)ZQF#y$XuoVC63}{AX zOyh1}I*N{hjI*+OkTFm|i!o(i*t6wF)EqEZh88L_P)nyxPuio;ohy&u-0Ene*`UU? z)a(7E`~yPxhf@uJ7FjqRmG>X~g8V`Y7Vgof(2>4d6UMmf$$9*Y&SU#W?ZRiB`N&ZV z>%a`6(LNAIyIsut>`BsTR$^vp*7BQYopo(a{xi5yfHCuT1J*L9cyBnj|-0t2z6-$Ibt!fJ1jbv@A!pZ(3|J;F{M84$pJCN@h&{thk!|jX+rj{;WTO^wmd& zcJ5=tYtYE=hv!QbG3!}N;{!V`^q>O*@Qc1`YB5ka==OAF+W5UiKr*B=EK>9rQrRu! zqSpJn&wnZklIH7)ls0UZ*A|=^;)70_nTKtQG57{F%UZ+LM1J*QsX_C)5_*@4TC2f2->u`$!~60P+=hxF&fhdA&w& z*RHOLUeuUWko_Z*XI6D+mx3N|d^36zx^NRIh|i^|jMahHjyRbcGx0j-?%7Jux*IrL znw%%ZM9tGL`FK~yWq-E8LdDz4nl$Z9c9v1n=7PnYOiik8_x4p~0VI(v;u#u2hU-NyEGf+~JQ(?cp z_X3ppq%#K+i7hSHJT-4oMwt4P4v&-psn7elN=4~(s)y;Ltqf_e)06RkZ~>O3_8`W` zVbRL7J=JqGSQzcB^zI(y`=9_L)a-e+Bvl0)xP)6oLjA;g z^xO;9OY^>GY6!cV<^$IZ=gZQkx!4Suvs5urDW5dcp050TH^1U-BUk-<37;}_M+V}v zH4~K-X0q(vCQa@)w*2rc@4TF!T&E;b*g<0l(NeElVo<>MppO|xK zU6^)P7{r_6zQv;m?DZ6_Xj99Xt03Ec*FGG&@u%l{d$}i?JP2*XUK7k`QrRaQ2FMt! zn;2)G0t;KdaxzlxhMCtrz?t*g9f~?Y-Lm)3@yRi2?-skpz0RtH$IdQ|?vULt zOd=ONE*!0$hbS1>?7j9Ty2`zCBC>Ya=sR-nyfj&e5Dq6<5(y3thQ#wmp|y)b!GHJw zHBZFEOYL^l{Ze)Gb9q6~`(VEcM1bV_R9|K)EU9Liya*Vt{m?e<6&n-GLBp+Gf*%%| z)1%#E*h24X5Ga%DpB=)RcZwqm4xG80=`j6{+KX8Om_m6P6`42QHE_`pg)S~ zleT~TQPwW{qwpsg|46dxyUMYj1p1>agWJCE!{dEDHo;YC*xrvaAAYF8n z=!&jjG5)srwk!-b{sb3oSzeWbzAe$XWnIdDon1okon4}v2=%V~`z)$27*>t;_yEAx{4xNt{O|9768N74{wIO|4+%*BJce@1cl>A@3aG+g{z6_& Ku0-bjm;VDiJye1K literal 0 HcmV?d00001 diff --git a/static/img/copter_indigo.png b/static/img/copter_indigo.png new file mode 100644 index 0000000000000000000000000000000000000000..c5c07ea7301a500a99c7a9b7dca7f866c4797187 GIT binary patch literal 28725 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 literal 0 HcmV?d00001 diff --git a/static/img/copter_purple.png b/static/img/copter_purple.png new file mode 100644 index 0000000000000000000000000000000000000000..93a066edf71589d33f75405a1f3a575f9f31d123 GIT binary patch literal 28632 zcmeFZ^;=ZY_Beb96;PB$I+PNmOIid$I;2ZLKw3aLm5>HOr9%*qF6kJhhDN$U7`kD| z3FbZH{oMP*`!{^YhlhtVd#}BEt-aPdMrmm%5fjl80RTY!LRmov0PxAMKLj_yCuD}R zJ>ajKR;o%000#Rnx2-4{d_wqE*~kL`cpqSYaC{16y#Rn2c%kt0rO({nqIWCB`mF3< zr1D`~G$o~07cIG}6DKXsjoUM-3fcB^oV9r(?t{xB*}8%C$fGebgo z7ys+eujr;#V>U&AQ#Fcvx z3;yY1EQaIIdK0_gIk;Y^JPi;rM}7wW+{u4(vn*{&ErhnxR|R+zF-jjQLhi^e7dI`z z1_*b)iT|A*B|@It4)7pq15AIIs1_#w~l#|apU zRomiD_(<#G$_atTmSq?Ufyc&kVUM-GGo@aJJ+>2jEVV`hj)4ODrl-}AEpfgL458hi zQT}Ej*L*W600S#80#sNqCnv9q?vl{kB!KUP~jdqql%1OdLO;A z$wu>^u2amkVn684cBkSIp1TU@<~r-qB%A72qhp4x?~De~wl4w%UA4;=-S&Ony$pVj z8^VmkEIV{`7m5<~nthiw6PR4DZRW2nY(MsJuHKoBnmEAvi-pG@KJ&Qe$bE8;jlrmH zZrX075LI`MMK)P*nu)CK!rR=Q`@Q?=Puv&2`yfLTtQwq~du}q&Jx5317|m0RF}&_r zhBceam7nZp2afa{cT-z*eYkOZbvHWx7=>wN(8R#=eU7KdK{0&5mlHCT%3uic+`Fia zvqGv%Dzs45S?~SbE_Ur~A{ULbA200w=t28@J;x$Sl*T?-(22&AucY)R$`iaKdC z_&c`*l}%T_Fb%r&Pb-_%HmHjfD>UdDN`O!Vx7hqB1ZAh_@z>JYYTn$WOO$RRZeAlN zrOz+R4HGsa+ol?>%b-6?!vD4OPt?`AnYn)B>K%x5TxzNUDMTFf# zyJhRid6C;!tmiGAHa{GkGS^`yQu17bcJY4A4TYgE5b;pOii# z|Mo$I9K?3*JB!STfp-s|e>sD9f}x?Hi1hl@*=m#6W_Km#(lS8Y1r$PATGTd3lAo6& zO^fTKM1}Nua#Hc`uYu{|{WK z2QAcBb1-tcQua7$_g@iin4`34%wxO7 zSvHqoE0s*KHEJx7>-pk*rr4)}%{?N}fU?WwF(hik&0!sSyyS^jmI0bV?nL@Z`-4ZY zzs~7B7L|sDN3vF1#96C(^A_>P`3Vyg&uA(${NsJZgW6m_HrmWMg=0uf7#n!5ucvRg zjSt;262p0lE5{|=xfvHI6+dq`-uU;I7-bOKp8tz^aTk=ofJlLb?;nb1qEkbkVC>yg zyAv@SeAmXK1|3geVo?GYDCr6*4+~3NkR!d0Lak?g_qtr~9Z*0dJ>&B#^H`KdqN&@9 z8KBudk%jmBUoA?(`=bQ*a-CN@@XQTP^@NX3;sv(i8(?@WJXi<@LIIPF{;);K3@#t} zc*gNZ@$G@ek2D`mQ#?cLZls4op$s3r;lNzj9XfN$V86qG`+hs5+rlURRQOGVfms7N zd)MJT3#b{v4Tso6M3qEPpbnF|z~?{Bz8#9>s|!yhd#;deC4UL$FOup7uF9L-R*qXh z_YCrYif(oMx$J%DyHaZF=aV{nxI2MC@W$(Hn&X)t*Rk@rjEL3KmWsM!?mw8hHWR`Fhy1ono+o zup;UoaI_vK-{n+@H}#lX*z%rWZ))E9V8uBR5Oj3h zcYM@aNg=Kj@8>U1?>?G5rN(TqaDxB3#^}l3YEj-OjGIENC`h2jXs;Gp-q)ac%6)b7IAs87B=+9)Er?{3t

UQ=}@wQ)hwRf3?F`;NXJX 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 literal 0 HcmV?d00001 diff --git a/static/img/copter_red.png b/static/img/copter_red.png new file mode 100644 index 0000000000000000000000000000000000000000..7d30d06122256cac19a4e5688ef8d1174fb5132e GIT binary patch literal 28692 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

7L(prUF@|bqorqy%YP*=;M|dE^K}-34 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 literal 0 HcmV?d00001 diff --git a/static/js/leaflet-stuff.js b/static/js/leaflet-stuff.js index b0c0335..f8e3bae 100644 --- a/static/js/leaflet-stuff.js +++ b/static/js/leaflet-stuff.js @@ -23,16 +23,29 @@ var myIcons = L.Icon.extend({ } }); -// build icon list -blackIcon = new myIcons({iconUrl: '/static/img/plane_black.png'}), -greenIcon = new myIcons({iconUrl: '/static/img/plane_green.png'}), +// build icon list for planes +blackIcon = new myIcons({iconUrl: '/static/img/plane_black.png'}), +greenIcon = new myIcons({iconUrl: '/static/img/plane_green.png'}), indigoIcon = new myIcons({iconUrl: '/static/img/plane_indigo.png'}), orangeIcon = new myIcons({iconUrl: '/static/img/plane_orange.png'}), -blueIcon = new myIcons({iconUrl: '/static/img/plane.png'}), +blueIcon = new myIcons({iconUrl: '/static/img/plane.png'}), purpleIcon = new myIcons({iconUrl: '/static/img/plane_purple.png'}), -redIcon = new myIcons({iconUrl: '/static/img/plane_red.png'}); +redIcon = new myIcons({iconUrl: '/static/img/plane_red.png'}); iconlist = []; + + +// and copters +blackIcon2 = new myIcons({iconUrl: '/static/img/copter_black.png'}), +greenIcon2 = new myIcons({iconUrl: '/static/img/copter_green.png'}), +indigoIcon2 = new myIcons({iconUrl: '/static/img/copter_indigo.png'}), +orangeIcon2 = new myIcons({iconUrl: '/static/img/copter_orange.png'}), +blueIcon2 = new myIcons({iconUrl: '/static/img/copter_blue.png'}), +purpleIcon2 = new myIcons({iconUrl: '/static/img/copter_purple.png'}), +redIcon2 = new myIcons({iconUrl: '/static/img/copter_red.png'}); +iconlist2 = []; + iconlist.push(redIcon,blackIcon,blueIcon,greenIcon,indigoIcon,orangeIcon,purpleIcon); // so sysid0 is red, sysid1 is black, sysid2 is blue etc +iconlist2.push(redIcon2,blackIcon2,blueIcon2,greenIcon2,indigoIcon2,orangeIcon2,purpleIcon2); // so sysid0 is red, sysid1 is black, sysid2 is blue et // redefine standard L.i to point to my L.I ( case important ) L.icon = function (options) { diff --git a/static/js/main.js b/static/js/main.js index cc8ce66..bb15a09 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -198,8 +198,10 @@ $(document).ready(function () { // we instead / ALSO returns the array-of-chars as an array of mavlink packets, possibly 'none', [ p] single packet , or [p,p,p] packets. // here's where we store the sorce ip and port with each packet we just made, AFTER the now-useless 'emit' which can't easily do this.. - for (msg of packetlist){ - mavlink_incoming_parser_message_handler(msg,message[1],message[2],mavlinktype ); // [1] = ip and [2] = port + if (packetlist ) { + for (msg of packetlist){ + mavlink_incoming_parser_message_handler(msg,message[1],message[2],mavlinktype ); // [1] = ip and [2] = port + } } }); @@ -267,7 +269,7 @@ $(document).ready(function () { // store data from packet states[message.sysid].cs.mode = message.mode; // states already has human-readable mode, so just display it. - states[message.sysid].cs.vehicle_type = message.vehicle_type; + states[message.sysid].cs.vehicle_type = message.type; // 'Copter' or 'Plane' // redraw current_vehicle that's onscreen document.getElementById('status_mode').innerText = states[current_vehicle].cs.mode; document.getElementById('floating-mode-text').innerText = states[current_vehicle].cs.mode; @@ -383,7 +385,7 @@ $(document).ready(function () { states[message.sysid].cs.altitude_agl = parseFloat(message.altitude_agl).toFixed(2); - // create an initial marker with very little going on, in a default place. + // create an initial marker or 2 with very little going on, in a default place. if (!( "planeMarker" in states[message.sysid] )){ x = message.sysid%7; // pick a color from the 7 avail states[message.sysid].planeMarker = L.marker(defaultMapLocation, { @@ -391,6 +393,13 @@ $(document).ready(function () { title: "id:"+message.sysid //minimal mouse-over to start with, updated later elsewhere }).addTo(leafletmap); } + if (!( "copterMarker" in states[message.sysid] )){ + x = message.sysid%7; // pick a color from the 7 avail + states[message.sysid].copterMarker = L.marker(defaultMapLocation, { + icon: iconlist2[x], rotationOrigin: "center center", + title: "id:"+message.sysid //minimal mouse-over to start with, updated later elsewhere + }).addTo(leafletmap); + } // create an empty polygon for the flightpath to be filled later.. if (!( "flightPath" in states[message.sysid] )){ states[message.sysid].flightPath = L.polyline([], {color: 'red'}).addTo(leafletmap); @@ -616,19 +625,36 @@ $(document).ready(function () { states[current_vehicle].locationHistory.pop(); } - // Set our rotation - states[current_vehicle].planeMarker.setRotationAngle(states[current_vehicle].cs.heading); - - // Set our location - states[current_vehicle].planeMarker.setLatLng(states[current_vehicle].cs.location); - - // update the little bubble of text on the on-mouse-over of the planemarker. - states[current_vehicle].planeMarker.options.title = - String(Math.round(states[current_vehicle].cs.altitude_agl))+"m | " - +String(Math.round(states[current_vehicle].cs.airspeed))+"m/s | id: "+current_vehicle; - // a remove-and-add is required to get the options.title to re-render the planemarker - states[current_vehicle].planeMarker.remove(); - states[current_vehicle].planeMarker.addTo(leafletmap); + if ( states[current_vehicle].cs.vehicle_type == "Plane") { + // Set our rotation + states[current_vehicle].planeMarker.setRotationAngle(states[current_vehicle].cs.heading); + // Set our location + states[current_vehicle].planeMarker.setLatLng(states[current_vehicle].cs.location); + // update the little bubble of text on the on-mouse-over of the planemarker. + states[current_vehicle].planeMarker.options.title = + String(Math.round(states[current_vehicle].cs.altitude_agl))+"m | " + +String(Math.round(states[current_vehicle].cs.airspeed))+"m/s | id: "+current_vehicle; + // a remove-and-add is required to get the options.title to re-render the planemarker + states[current_vehicle].planeMarker.remove(); + states[current_vehicle].planeMarker.addTo(leafletmap); + // if the current vehicle type has changed from plane to copter etc, remove the other marker too + states[current_vehicle].copterMarker.remove(); + } + if ( states[current_vehicle].cs.vehicle_type == "Copter") { + // Set our rotation + states[current_vehicle].copterMarker.setRotationAngle(states[current_vehicle].cs.heading); + // Set our location + states[current_vehicle].copterMarker.setLatLng(states[current_vehicle].cs.location); + // update the little bubble of text on the on-mouse-over of the planemarker. + states[current_vehicle].copterMarker.options.title = + String(Math.round(states[current_vehicle].cs.altitude_agl))+"m | " + +String(Math.round(states[current_vehicle].cs.airspeed))+"m/s | id: "+current_vehicle; + // a remove-and-add is required to get the options.title to re-render the planemarker + states[current_vehicle].copterMarker.remove(); + states[current_vehicle].copterMarker.addTo(leafletmap); + // if the current vehicle type has changed from plane to copter etc, remove the other marker too + states[current_vehicle].planeMarker.remove(); + } // which plane is the center of our focus etc? initial_sysid = document.getElementById("update_connection_settings_sysid").value; @@ -675,6 +701,7 @@ $(document).ready(function () { document.getElementById('status_roll').innerText = String(states[current_vehicle].cs.attitude.roll); document.getElementById('status_yaw').innerText = String(states[current_vehicle].cs.attitude.yaw); document.getElementById('status_ap_type').innerText = String(states[current_vehicle].cs.ap_type); + document.getElementById('status_veh_type').innerText = String(states[current_vehicle].cs.vehicle_type); } setTimeout(updateStatusTab, 500); diff --git a/static/js/mav-stuff.js b/static/js/mav-stuff.js index fd21542..6f719c2 100644 --- a/static/js/mav-stuff.js +++ b/static/js/mav-stuff.js @@ -82,15 +82,17 @@ var mavlink_incoming_parser_message_handler = function(message,ip,port,mavlinkty if ( ! [ 'VFR_HUD','GPS_RAW_INT', 'ATTITUDE', 'SYS_STATUS', 'GLOBAL_POSITION_INT', 'HEARTBEAT','VIBRATION', 'BATTERY_STATUS', 'TERRAIN_REPORT', 'WIND', 'HWSTATUS', 'AHRS', 'AHRS2', 'AHRS3', 'SIMSTATE', 'RC_CHANNELS','RC_CHANNELS_RAW', 'SERVO_OUTPUT_RAW', 'LOCAL_POSITION_NED', - 'MEMINFO', 'POWER_STATUS', 'SCALED_PRESSURE', 'SCALED_IMU','SCALED_IMU2','SCALED_IMU3', 'RAW_IMU', + 'MEMINFO', 'POWER_STATUS', 'SCALED_PRESSURE', 'SCALED_PRESSURE2','SCALED_IMU','SCALED_IMU2','SCALED_IMU3', 'RAW_IMU', 'EKF_STATUS_REPORT', 'SYSTEM_TIME', 'MISSION_CURRENT' , 'SENSOR_OFFSETS', 'TIMESYNC', 'PARAM_VALUE', 'HOME_POSITION', 'POSITION_TARGET_GLOBAL_INT', 'NAV_CONTROLLER_OUTPUT', 'STATUSTEXT' , 'COMMAND_ACK' , 'MISSION_ITEM', 'MISSION_ITEM_INT','MISSION_COUNT','MISSION_REQUEST', 'MISSION_ACK', 'AIRSPEED_AUTOCAL', 'MISSION_ITEM_REACHED' , 'STAT_FLTTIME' ,'AUTOPILOT_VERSION' , - 'FENCE_STATUS' , 'AOA_SSA' , 'GPS_GLOBAL_ORIGIN', ].includes(message.name) ) { + 'FENCE_STATUS' , 'AOA_SSA' , 'GPS_GLOBAL_ORIGIN', 'SET_MODE', 'FILE_TRANSFER_PROTOCOL', + 'MISSION_REQUEST_INT' , 'MISSION_REQUEST_LIST', + 'PARAM_SET', ].includes(message.name) ) { - console.log("unhandled mavlink packet"+message); + console.log("unhandled mavlink packet"+JSON.stringify(message)); } @@ -171,8 +173,21 @@ var mavlink_incoming_parser_message_handler = function(message,ip,port,mavlinkty // this ensures the GUI render/s the current vehicle mode on-screen // arduplane uses heartbeatpacket.custom_mode to index into mode_mapping_apm - TODO copter uses acm - var _mode = mode_mapping_apm[message.custom_mode]; - var vehicle_type = 'Plane'; // todo handle non-plane things too. + var _mode = 'unknown-mode';// = mode_mapping_apm[message.custom_mode]; + var vehicle_type = 'unknown-type';// = 'Plane'; // todo handle non-plane things too. + + //copter or plane or something else? + if (message.type == mavlink20.MAV_TYPE_FIXED_WING ) { + // arduplane uses packet.custom_mode to index into mode_mapping_apm + _mode = mode_mapping_apm[message.custom_mode]; + vehicle_type = 'Plane'; + } + if (message.type == mavlink20.MAV_TYPE_QUADROTOR ) { + // arducopter uses packet.custom_mode to index into mode_mapping_acm + _mode = mode_mapping_acm[message.custom_mode]; + vehicle_type = 'Copter'; + } + //this matches the json format sent by the non-mavlink backend server/s: msghandler.emit('mode', { "sysid": message.header.srcSystem, "mode": _mode,