add mavlink sigining and wss support

This commit is contained in:
Huibean
2025-08-14 09:56:58 +08:00
parent c3c4eb64f0
commit 7bffe34f54
8 changed files with 1816 additions and 8375 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@ dist
mav.parm mav.parm
mav.tlog mav.tlog
mav.tlog.raw mav.tlog.raw
deploy.sh

226
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "dronecan-configurator", "name": "dronecan-webtools",
"version": "1.0.0", "version": "1.0.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "dronecan-configurator", "name": "dronecan-webtools",
"version": "1.0.0", "version": "1.0.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/core": "^7.26.7", "@babel/core": "^7.26.7",
@@ -20,6 +20,7 @@
"buffer": "^6.0.3", "buffer": "^6.0.3",
"crypto-browserify": "^3.12.1", "crypto-browserify": "^3.12.1",
"html-webpack-plugin": "^5.6.3", "html-webpack-plugin": "^5.6.3",
"jspack": "^0.0.4",
"long": "^5.2.4", "long": "^5.2.4",
"process": "^0.11.10", "process": "^0.11.10",
"react": "^18.3.1", "react": "^18.3.1",
@@ -52,14 +53,14 @@
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.26.2", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-validator-identifier": "^7.25.9", "@babel/helper-validator-identifier": "^7.27.1",
"js-tokens": "^4.0.0", "js-tokens": "^4.0.0",
"picocolors": "^1.0.0" "picocolors": "^1.1.1"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -320,18 +321,18 @@
} }
}, },
"node_modules/@babel/helper-string-parser": { "node_modules/@babel/helper-string-parser": {
"version": "7.25.9", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/helper-validator-identifier": { "node_modules/@babel/helper-validator-identifier": {
"version": "7.25.9", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -361,25 +362,25 @@
} }
}, },
"node_modules/@babel/helpers": { "node_modules/@babel/helpers": {
"version": "7.26.7", "version": "7.28.2",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz",
"integrity": "sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A==", "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/template": "^7.25.9", "@babel/template": "^7.27.2",
"@babel/types": "^7.26.7" "@babel/types": "^7.28.2"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.26.7", "version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
"integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==", "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/types": "^7.26.7" "@babel/types": "^7.28.0"
}, },
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@@ -1510,26 +1511,23 @@
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.26.7", "version": "7.28.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz",
"integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==", "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==",
"license": "MIT", "license": "MIT",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.25.9", "version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
"integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.25.9", "@babel/code-frame": "^7.27.1",
"@babel/parser": "^7.25.9", "@babel/parser": "^7.27.2",
"@babel/types": "^7.25.9" "@babel/types": "^7.27.1"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -1554,13 +1552,13 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.26.7", "version": "7.28.2",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz",
"integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==", "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.25.9", "@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.25.9" "@babel/helper-validator-identifier": "^7.27.1"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -2192,9 +2190,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/http-proxy": { "node_modules/@types/http-proxy": {
"version": "1.17.15", "version": "1.17.16",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz",
"integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/node": "*" "@types/node": "*"
@@ -3288,16 +3286,16 @@
} }
}, },
"node_modules/compression": { "node_modules/compression": {
"version": "1.7.5", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
"integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"bytes": "3.1.2", "bytes": "3.1.2",
"compressible": "~2.0.18", "compressible": "~2.0.18",
"debug": "2.6.9", "debug": "2.6.9",
"negotiator": "~0.6.4", "negotiator": "~0.6.4",
"on-headers": "~1.0.2", "on-headers": "~1.1.0",
"safe-buffer": "5.2.1", "safe-buffer": "5.2.1",
"vary": "~1.1.2" "vary": "~1.1.2"
}, },
@@ -4342,9 +4340,9 @@
} }
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.15.9", "version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@@ -4789,9 +4787,9 @@
} }
}, },
"node_modules/http-proxy-middleware": { "node_modules/http-proxy-middleware": {
"version": "2.0.7", "version": "2.0.9",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz",
"integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/http-proxy": "^1.17.8", "@types/http-proxy": "^1.17.8",
@@ -5301,6 +5299,11 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/jspack": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/jspack/-/jspack-0.0.4.tgz",
"integrity": "sha512-DC/lSTXYDDdYWzyY/9A1kMzp6Ov9mCRhZQ1cGg4te2w3y4/aKZTSspvbYN4LUsvSzMCb/H8z4TV9mYYW/bs3PQ=="
},
"node_modules/kind-of": { "node_modules/kind-of": {
"version": "6.0.3", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@@ -5701,9 +5704,9 @@
} }
}, },
"node_modules/on-headers": { "node_modules/on-headers": {
"version": "1.0.2", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -5899,21 +5902,53 @@
} }
}, },
"node_modules/pbkdf2": { "node_modules/pbkdf2": {
"version": "3.1.2", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.3.tgz",
"integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "integrity": "sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"create-hash": "^1.1.2", "create-hash": "~1.1.3",
"create-hmac": "^1.1.4", "create-hmac": "^1.1.7",
"ripemd160": "^2.0.1", "ripemd160": "=2.0.1",
"safe-buffer": "^5.0.1", "safe-buffer": "^5.2.1",
"sha.js": "^2.4.8" "sha.js": "^2.4.11",
"to-buffer": "^1.2.0"
}, },
"engines": { "engines": {
"node": ">=0.12" "node": ">=0.12"
} }
}, },
"node_modules/pbkdf2/node_modules/create-hash": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
"integrity": "sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==",
"license": "MIT",
"dependencies": {
"cipher-base": "^1.0.1",
"inherits": "^2.0.1",
"ripemd160": "^2.0.0",
"sha.js": "^2.4.0"
}
},
"node_modules/pbkdf2/node_modules/hash-base": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz",
"integrity": "sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.1"
}
},
"node_modules/pbkdf2/node_modules/ripemd160": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
"integrity": "sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==",
"license": "MIT",
"dependencies": {
"hash-base": "^2.0.0",
"inherits": "^2.0.1"
}
},
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -6323,12 +6358,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"license": "MIT"
},
"node_modules/regenerator-transform": { "node_modules/regenerator-transform": {
"version": "0.15.2", "version": "0.15.2",
"resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz",
@@ -7159,6 +7188,26 @@
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/to-buffer": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz",
"integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==",
"license": "MIT",
"dependencies": {
"isarray": "^2.0.5",
"safe-buffer": "^5.2.1",
"typed-array-buffer": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/to-buffer/node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
"license": "MIT"
},
"node_modules/to-regex-range": { "node_modules/to-regex-range": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -7215,6 +7264,20 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/typed-array-buffer": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"is-typed-array": "^1.1.14"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/underscore": { "node_modules/underscore": {
"version": "1.13.7", "version": "1.13.7",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
@@ -7522,14 +7585,15 @@
} }
}, },
"node_modules/webpack-dev-server": { "node_modules/webpack-dev-server": {
"version": "5.2.0", "version": "5.2.2",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.0.tgz", "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.2.tgz",
"integrity": "sha512-90SqqYXA2SK36KcT6o1bvwvZfJFcmoamqeJY7+boioffX9g9C0wjjJRGUrQIuh43pb0ttX7+ssavmj/WN2RHtA==", "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/bonjour": "^3.5.13", "@types/bonjour": "^3.5.13",
"@types/connect-history-api-fallback": "^1.5.4", "@types/connect-history-api-fallback": "^1.5.4",
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"@types/express-serve-static-core": "^4.17.21",
"@types/serve-index": "^1.9.4", "@types/serve-index": "^1.9.4",
"@types/serve-static": "^1.15.5", "@types/serve-static": "^1.15.5",
"@types/sockjs": "^0.3.36", "@types/sockjs": "^0.3.36",
@@ -7542,7 +7606,7 @@
"connect-history-api-fallback": "^2.0.0", "connect-history-api-fallback": "^2.0.0",
"express": "^4.21.2", "express": "^4.21.2",
"graceful-fs": "^4.2.6", "graceful-fs": "^4.2.6",
"http-proxy-middleware": "^2.0.7", "http-proxy-middleware": "^2.0.9",
"ipaddr.js": "^2.1.0", "ipaddr.js": "^2.1.0",
"launch-editor": "^2.6.1", "launch-editor": "^2.6.1",
"open": "^10.0.3", "open": "^10.0.3",
@@ -7577,6 +7641,18 @@
} }
} }
}, },
"node_modules/webpack-dev-server/node_modules/@types/express-serve-static-core": {
"version": "4.19.6",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz",
"integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==",
"license": "MIT",
"dependencies": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*",
"@types/send": "*"
}
},
"node_modules/webpack-merge": { "node_modules/webpack-merge": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz",

View File

@@ -1,6 +1,6 @@
{ {
"name": "dronecan-webtools", "name": "dronecan-webtools",
"version": "1.0.1", "version": "1.0.2",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
@@ -22,6 +22,7 @@
"buffer": "^6.0.3", "buffer": "^6.0.3",
"crypto-browserify": "^3.12.1", "crypto-browserify": "^3.12.1",
"html-webpack-plugin": "^5.6.3", "html-webpack-plugin": "^5.6.3",
"jspack": "^0.0.4",
"long": "^5.2.4", "long": "^5.2.4",
"process": "^0.11.10", "process": "^0.11.10",
"react": "^18.3.1", "react": "^18.3.1",

View File

@@ -1,13 +1,15 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { import {
Dialog, DialogTitle, DialogContent, DialogActions, Dialog, DialogTitle, DialogContent,
Button, FormControl, InputLabel, Select, MenuItem, Button, FormControl, InputLabel, Select, MenuItem,
Typography, Box, Divider, RadioGroup, FormControlLabel, Radio, Chip, Typography, Box, Divider, Chip,
TextField, Tabs, Tab, Paper, IconButton TextField, Paper, IconButton
} from '@mui/material'; } from '@mui/material';
import RefreshIcon from '@mui/icons-material/Refresh'; import RefreshIcon from '@mui/icons-material/Refresh';
import UsbIcon from '@mui/icons-material/Usb'; import UsbIcon from '@mui/icons-material/Usb';
import CloseIcon from '@mui/icons-material/Close'; import CloseIcon from '@mui/icons-material/Close';
import Visibility from '@mui/icons-material/Visibility';
import VisibilityOff from '@mui/icons-material/VisibilityOff';
import WebSerial from './web_serial'; import WebSerial from './web_serial';
// Add this constant at the top of your file, outside the component // Add this constant at the top of your file, outside the component
@@ -74,6 +76,11 @@ const ConnectionSettingsModal = ({
selectedBus, // New prop selectedBus, // New prop
onBusChange // New prop onBusChange // New prop
}) => { }) => {
// State for showing/hiding mavlink signing
const [showMavlinkSigning, setShowMavlinkSigning] = useState(false);
const handleToggleMavlinkSigning = () => {
setShowMavlinkSigning((show) => !show);
};
// Port and connection management // Port and connection management
const [ports, setPorts] = useState([]); const [ports, setPorts] = useState([]);
const [selectedPort, setSelectedPort] = useState(null); const [selectedPort, setSelectedPort] = useState(null);
@@ -88,11 +95,13 @@ const ConnectionSettingsModal = ({
const [activeConnection, setActiveConnection] = useState(null); // null, 'serial', or 'websocket' const [activeConnection, setActiveConnection] = useState(null); // null, 'serial', or 'websocket'
// Add these state variables after your other state declarations // Add these state variables after your other state declarations
const [ipError, setIpError] = useState(''); const [hostError, setHostError] = useState('');
const [portError, setPortError] = useState(''); const [portError, setPortError] = useState('');
// Add nodeId state to use the prop value // Add nodeId state to use the prop value
const [nodeId, setNodeId] = useState(127); const [nodeId, setNodeId] = useState(127);
// Add mavlink signing state
const [mavlinkSigning, setMavlinkSigning] = useState('');
// Add state for the forwarding interval // Add state for the forwarding interval
const [forwardingInterval, setForwardingInterval] = useState(null); const [forwardingInterval, setForwardingInterval] = useState(null);
@@ -315,29 +324,22 @@ const ConnectionSettingsModal = ({
return ''; return '';
} }
// Check for IPv4 format // If input matches IPv4 pattern, validate as IPv4, else treat as hostname/domain
if (input.includes('.')) { const ipv4Pattern = /^\d{1,3}(\.\d{1,3}){3}$/;
if (ipv4Pattern.test(input)) {
const octets = input.split('.'); const octets = input.split('.');
// An IPv4 address must have exactly 4 octets
if (octets.length !== 4) {
return 'Invalid IPv4 format';
}
// Each octet must be a number between 0 and 255
for (const octet of octets) { for (const octet of octets) {
const num = parseInt(octet, 10); const num = parseInt(octet, 10);
if (isNaN(num) || num < 0 || num > 255 || octet !== num.toString()) { if (isNaN(num) || num < 0 || num > 255 || octet !== num.toString()) {
return 'Each part must be a number between 0-255'; return 'Each part must be a number between 0-255';
} }
} }
// Valid IPv4
return ''; return '';
} }
// Check for hostname format // Check for hostname or domain (including subdomains)
const hostnamePattern = /^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])(\.[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])*$/; // Allow domains like 'support.ardupilot.org', 'foo.local', etc.
const hostnamePattern = /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)*[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?$/;
if (hostnamePattern.test(input)) { if (hostnamePattern.test(input)) {
return ''; return '';
@@ -377,11 +379,16 @@ const ConnectionSettingsModal = ({
} }
}; };
// Handler for Mavlink Signing input
const handleMavlinkSigningChange = (e) => {
setMavlinkSigning(e.target.value);
};
// Update the ws host/port change handlers // Update the ws host/port change handlers
const handleWsHostChange = (e) => { const handleWsHostChange = (e) => {
const value = e.target.value; const value = e.target.value;
setWsHost(value); setWsHost(value);
setIpError(validateIpAddress(value)); setHostError(validateIpAddress(value));
}; };
const handleWsPortChange = (e) => { const handleWsPortChange = (e) => {
@@ -396,54 +403,48 @@ const ConnectionSettingsModal = ({
if (activeConnection === 'websocket') { if (activeConnection === 'websocket') {
// Force close the connection // Force close the connection
window.mavlinkSession.close(); window.mavlinkSession.close();
// Always update the UI state regardless of actual connection state
setActiveConnection(null); setActiveConnection(null);
onConnectionStatusChange(false); onConnectionStatusChange(false);
showMessage('WebSocket connection closed', 'info'); showMessage('WebSocket connection closed', 'info');
// Clear the forwarding interval
if (forwardingInterval) { if (forwardingInterval) {
clearInterval(forwardingInterval); clearInterval(forwardingInterval);
setForwardingInterval(null); setForwardingInterval(null);
} }
} else { } else {
// Set in-progress state before attempting to connect
setConnectionInProgress(true); setConnectionInProgress(true);
const hostErr = validateIpAddress(wsHost);
// Validate both fields before connecting const portErr = validatePort(wsPort);
const hostError = validateIpAddress(wsHost); setHostError(hostErr);
const portError = validatePort(wsPort); setPortError(portErr);
if (!hostErr && !portErr) {
setIpError(hostError);
setPortError(portError);
// Only connect if both validations pass
if (!hostError && !portError) {
if (activeConnection) { if (activeConnection) {
window.mavlinkSession.close(); window.mavlinkSession.close();
// Clear any existing interval
if (forwardingInterval) { if (forwardingInterval) {
clearInterval(forwardingInterval); clearInterval(forwardingInterval);
} }
} }
// Use window.mavlinkSession consistently // Use wss if signing is present, else ws
window.mavlinkSession.initWebSocketConnection(wsHost, parseInt(wsPort, 10)); const wsProtocol = mavlinkSigning ? 'wss' : 'ws';
// Compose the full URL for the websocket
const wsUrl = `${wsProtocol}://${wsHost}:${wsPort}`;
if (window.mavlinkSession.initWebSocketConnection.length === 1) {
// If the function expects a URL
window.mavlinkSession.initWebSocketConnection(wsUrl);
} else {
// Fallback to old signature (host, port)
window.mavlinkSession.initWebSocketConnection(wsHost, parseInt(wsPort, 10), mavlinkSigning);
}
window.mavlinkSession.addWebSocketOpenHandler(() => { window.mavlinkSession.addWebSocketOpenHandler(() => {
console.log('WebSocket connection open'); console.log('WebSocket connection open');
// Set Node ID and Bus for the local node
window.localNode.setNodeId(parseInt(nodeId, 10)); window.localNode.setNodeId(parseInt(nodeId, 10));
window.localNode.setBus(selectedBus); window.localNode.setBus(selectedBus);
// Start the mavlinkCanForward interval
const intervalId = setInterval(() => { const intervalId = setInterval(() => {
if (window.mavlinkSession) { if (window.mavlinkSession) {
window.mavlinkSession.enableMavlinkCanForward(window.localNode.bus); window.mavlinkSession.enableMavlinkCanForward(window.localNode.bus);
} }
}, 1000); }, 1000);
setForwardingInterval(intervalId); setForwardingInterval(intervalId);
setActiveConnection('websocket'); setActiveConnection('websocket');
onConnectionStatusChange(true); onConnectionStatusChange(true);
@@ -453,20 +454,13 @@ const ConnectionSettingsModal = ({
window.mavlinkSession.addWebSocketErrorHandler((error) => { window.mavlinkSession.addWebSocketErrorHandler((error) => {
console.error('WebSocket error:', error); console.error('WebSocket error:', error);
// Clear any existing interval
if (forwardingInterval) { if (forwardingInterval) {
clearInterval(forwardingInterval); clearInterval(forwardingInterval);
setForwardingInterval(null); setForwardingInterval(null);
} }
setActiveConnection(null); setActiveConnection(null);
onConnectionStatusChange(false); onConnectionStatusChange(false);
// Reset in-progress state on error
setConnectionInProgress(false); setConnectionInProgress(false);
// Show error message using App's showMessage function
let errorMsg = 'Connection failed'; let errorMsg = 'Connection failed';
if (error && error.message) { if (error && error.message) {
errorMsg = `Connection failed: ${error.message}`; errorMsg = `Connection failed: ${error.message}`;
@@ -478,14 +472,12 @@ const ConnectionSettingsModal = ({
window.mavlinkSession.webSocketConnect(); window.mavlinkSession.webSocketConnect();
} else { } else {
// If validation fails, reset the in-progress state
setConnectionInProgress(false); setConnectionInProgress(false);
} }
} }
} catch (error) { } catch (error) {
console.error('Error with WebSocket connection:', error); console.error('Error with WebSocket connection:', error);
showMessage(`WebSocket error: ${error.message || 'Unknown error'}`, 'error'); showMessage(`WebSocket error: ${error.message || 'Unknown error'}`, 'error');
// Reset in-progress state on any error
setConnectionInProgress(false); setConnectionInProgress(false);
} }
}; };
@@ -650,8 +642,8 @@ const ConnectionSettingsModal = ({
disabled={activeConnection !== null} disabled={activeConnection !== null}
size="small" size="small"
sx={{ flex: 3 }} sx={{ flex: 3 }}
error={!!ipError} error={!!hostError}
helperText={ipError} helperText={hostError}
/> />
<TextField <TextField
label="Port" label="Port"
@@ -673,7 +665,7 @@ const ConnectionSettingsModal = ({
variant="contained" variant="contained"
disabled={ disabled={
connectionInProgress || // Disable when connection attempt is in progress connectionInProgress || // Disable when connection attempt is in progress
!!ipError || !!hostError ||
!!portError || !!portError ||
!wsHost || !wsHost ||
!wsPort || !wsPort ||
@@ -691,7 +683,7 @@ const ConnectionSettingsModal = ({
<Divider /> <Divider />
{/* Bus Selection */} {/* Bus Selection and Mavlink Signing */}
<Box> <Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}> <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<TextField <TextField
@@ -708,6 +700,29 @@ const ConnectionSettingsModal = ({
error={validateNodeId(nodeId) !== ''} error={validateNodeId(nodeId) !== ''}
helperText={validateNodeId(nodeId)} helperText={validateNodeId(nodeId)}
/> />
<TextField
label="Mavlink Signing"
value={mavlinkSigning}
onChange={handleMavlinkSigningChange}
disabled={activeConnection !== null}
size="small"
placeholder="Secret Key"
type={showMavlinkSigning ? 'text' : 'password'}
sx={{ flex: 1 }}
InputProps={{
endAdornment: (
<IconButton
aria-label={showMavlinkSigning ? 'Hide secret' : 'Show secret'}
onClick={handleToggleMavlinkSigning}
edge="end"
size="small"
tabIndex={-1}
>
{showMavlinkSigning ? <VisibilityOff fontSize="small" /> : <Visibility fontSize="small" />}
</IconButton>
),
}}
/>
</Box> </Box>
</Box> </Box>
</Box> </Box>

View File

@@ -0,0 +1,270 @@
/*!
* Copyright © 2008 Fair Oaks Labs, Inc.
* All rights reserved.
*/
// Utility object: Encode/Decode C-style binary primitives to/from octet arrays
function JSPack()
{
// Module-level (private) variables
var el, bBE = false, m = this;
// Raw byte arrays
m._DeArray = function (a, p, l)
{
return [a.slice(p,p+l)];
};
m._EnArray = function (a, p, l, v)
{
for (var i = 0; i < l; a[p+i] = v[i]?v[i]:0, i++);
};
// ASCII characters
m._DeChar = function (a, p)
{
return String.fromCharCode(a[p]);
};
m._EnChar = function (a, p, v)
{
a[p] = v.charCodeAt(0);
};
// Little-endian (un)signed N-byte integers
m._DeInt = function (a, p)
{
var lsb = bBE?(el.len-1):0, nsb = bBE?-1:1, stop = lsb+nsb*el.len, rv, i, f;
for (rv = 0, i = lsb, f = 1; i != stop; rv+=(a[p+i]*f), i+=nsb, f*=256);
if (el.bSigned && (rv & Math.pow(2, el.len*8-1))) { rv -= Math.pow(2, el.len*8); }
return rv;
};
m._EnInt = function (a, p, v)
{
var lsb = bBE?(el.len-1):0, nsb = bBE?-1:1, stop = lsb+nsb*el.len, i;
v = (v<el.min)?el.min:(v>el.max)?el.max:v;
for (i = lsb; i != stop; a[p+i]=v&0xff, i+=nsb, v>>=8);
};
// ASCII character strings
m._DeString = function (a, p, l)
{
for (var rv = new Array(l), i = 0; i < l; rv[i] = String.fromCharCode(a[p+i]), i++);
return rv.join('');
};
m._EnString = function (a, p, l, v)
{
for (var t, i = 0; i < l; a[p+i] = (t=v.charCodeAt(i))?t:0, i++);
};
// Little-endian N-bit IEEE 754 floating point
m._De754 = function (a, p)
{
var s, e, m, i, d, nBits, mLen, eLen, eBias, eMax;
mLen = el.mLen, eLen = el.len*8-el.mLen-1, eMax = (1<<eLen)-1, eBias = eMax>>1;
i = bBE?0:(el.len-1); d = bBE?1:-1; s = a[p+i]; i+=d; nBits = -7;
for (e = s&((1<<(-nBits))-1), s>>=(-nBits), nBits += eLen; nBits > 0; e=e*256+a[p+i], i+=d, nBits-=8);
for (m = e&((1<<(-nBits))-1), e>>=(-nBits), nBits += mLen; nBits > 0; m=m*256+a[p+i], i+=d, nBits-=8);
switch (e)
{
case 0:
// Zero, or denormalized number
e = 1-eBias;
break;
case eMax:
// NaN, or +/-Infinity
return m?NaN:((s?-1:1)*Infinity);
default:
// Normalized number
m = m + Math.pow(2, mLen);
e = e - eBias;
break;
}
return (s?-1:1) * m * Math.pow(2, e-mLen);
};
m._En754 = function (a, p, v)
{
var s, e, m, i, d, c, mLen, eLen, eBias, eMax;
mLen = el.mLen, eLen = el.len*8-el.mLen-1, eMax = (1<<eLen)-1, eBias = eMax>>1;
s = v<0?1:0;
v = Math.abs(v);
if (isNaN(v) || (v == Infinity))
{
m = isNaN(v)?1:0;
e = eMax;
}
else
{
e = Math.floor(Math.log(v)/Math.LN2); // Calculate log2 of the value
if (v*(c = Math.pow(2, -e)) < 1) { e--; c*=2; } // Math.log() isn't 100% reliable
// Round by adding 1/2 the significand's LSD
if (e+eBias >= 1) { v += el.rt/c; } // Normalized: mLen significand digits
else { v += el.rt*Math.pow(2, 1-eBias); } // Denormalized: <= mLen significand digits
if (v*c >= 2) { e++; c/=2; } // Rounding can increment the exponent
if (e+eBias >= eMax)
{
// Overflow
m = 0;
e = eMax;
}
else if (e+eBias >= 1)
{
// Normalized - term order matters, as Math.pow(2, 52-e) and v*Math.pow(2, 52) can overflow
m = (v*c-1)*Math.pow(2, mLen);
e = e + eBias;
}
else
{
// Denormalized - also catches the '0' case, somewhat by chance
m = v*Math.pow(2, eBias-1)*Math.pow(2, mLen);
e = 0;
}
}
for (i = bBE?(el.len-1):0, d=bBE?-1:1; mLen >= 8; a[p+i]=m&0xff, i+=d, m/=256, mLen-=8);
for (e=(e<<mLen)|m, eLen+=mLen; eLen > 0; a[p+i]=e&0xff, i+=d, e/=256, eLen-=8);
a[p+i-d] |= s*128;
};
// 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 (a, p) {
var start = bBE ? 0 : 7, nsb = bBE ? 1 : -1, stop = start + nsb * 8, rv = [0,0, !el.bSigned], i, f, rvi;
for (i = start, rvi = 1, f = 0;
i != stop;
rv[rvi] = (((rv[rvi]<<8)>>>0) + a[p + i]), i += nsb, f++, rvi = (f < 4 ? 1 : 0));
return rv;
};
m._EnInt64 = function (a, p, v) {
var start = bBE ? 0 : 7, nsb = bBE ? 1 : -1, stop = start + nsb * 8, i, f, rvi, s;
for (i = start, rvi = 1, f = 0, s = 24;
i != stop;
a[p + i] = v[rvi]>>s & 0xff, i += nsb, f++, rvi = (f < 4 ? 1 : 0), s = 24 - (8 * (f % 4)));
};
// Class data
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._elLut = { '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},
'Q': {en:m._EnInt64, de:m._DeInt64, bSigned:false}};
// Unpack a series of n elements of size s from array a at offset p with fxn
m._UnpackSeries = function (n, s, a, p)
{
for (var fxn = el.de, rv = [], i = 0; i < n; rv.push(fxn(a, p+i*s)), i++);
return rv;
};
// 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 (n, s, a, p, v, i)
{
for (var fxn = el.en, o = 0; o < n; fxn(a, p+o*s, v[i+o]), o++);
};
// Unpack the octet array a, beginning at offset p, according to the fmt string
m.Unpack = function (fmt, a, p)
{
// Set the private bBE flag based on the format string - assume big-endianness
bBE = (fmt.charAt(0) != '<');
p = p?p:0;
var re = new RegExp(this._sPattern, 'g'), m, n, s, rv = [];
while (m = re.exec(fmt))
{
n = ((m[1]==undefined)||(m[1]==''))?1:parseInt(m[1]);
s = this._lenLut[m[2]];
if ((p + n*s) > a.length)
{
return undefined;
}
switch (m[2])
{
case 'A': case 's':
rv.push(this._elLut[m[2]].de(a, p, 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._elLut[m[2]];
rv.push(this._UnpackSeries(n, s, a, p));
break;
}
p += n*s;
}
return Array.prototype.concat.apply([], rv);
};
// Pack the supplied values into the octet array a, beginning at offset p, according to the fmt string
m.PackTo = function (fmt, a, p, values)
{
// Set the private bBE flag based on the format string - assume big-endianness
bBE = (fmt.charAt(0) != '<');
var re = new RegExp(this._sPattern, 'g'), m, n, s, i = 0, j;
while (m = re.exec(fmt))
{
n = ((m[1]==undefined)||(m[1]==''))?1:parseInt(m[1]);
s = this._lenLut[m[2]];
if ((p + n*s) > a.length)
{
return false;
}
switch (m[2])
{
case 'A': case 's':
if ((i + 1) > values.length) { return false; }
this._elLut[m[2]].en(a, p, n, values[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':
el = this._elLut[m[2]];
if ((i + n) > values.length) { return false; }
this._PackSeries(n, s, a, p, values, i);
i += n;
break;
case 'x':
for (j = 0; j < n; j++) { a[p+j] = 0; }
break;
}
p += n*s;
}
return a;
};
// Pack the supplied values into a new octet array, according to the fmt string
m.Pack = function (fmt, values)
{
return this.PackTo(fmt, new Array(this.CalcLength(fmt)), 0, values);
};
// Determine the number of bytes represented by the format string
m.CalcLength = function (fmt)
{
var re = new RegExp(this._sPattern, 'g'), m, sum = 0;
while (m = re.exec(fmt))
{
sum += (((m[1]==undefined)||(m[1]==''))?1:parseInt(m[1])) * this._lenLut[m[2]];
}
return sum;
};
};
exports.jspack = new JSPack();

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import WebSocketClient from './ws_client'; import WebSocketClient from './ws_client';
import WebSerial from './web_serial'; import WebSerial from './web_serial';
import { mavlink20, MAVLink20Processor } from './mavlink';
import dronecan from './dronecan'; import dronecan from './dronecan';
import './mavlink';
class MavlinkSession extends EventEmitter { class MavlinkSession extends EventEmitter {
constructor() { constructor() {
@@ -27,8 +27,17 @@ class MavlinkSession extends EventEmitter {
} }
} }
initWebSocketConnection(ip, port) { initWebSocketConnection(ip, port, mavlinkSigning='') {
if (mavlinkSigning) {
const enc = new TextEncoder();
const data = enc.encode(mavlinkSigning);
const hash = mavlink20.sha256(data);
this.mavlinkProcessor.signing.secret_key = new Uint8Array(hash);
this.mavlinkProcessor.signing.sign_outgoing = true;
this.wsClient = new WebSocketClient(`wss://${ip}:${port}`);
} else {
this.wsClient = new WebSocketClient(`ws://${ip}:${port}`); this.wsClient = new WebSocketClient(`ws://${ip}:${port}`);
}
this.mavlinkProcessor.file = this.wsClient; this.mavlinkProcessor.file = this.wsClient;
this.wsClient.addMessageHandler((buffer) => { this.wsClient.addMessageHandler((buffer) => {

View File

@@ -12,6 +12,7 @@ class WebSocketClient {
connect() { connect() {
// Reset connected status before attempting a new connection // Reset connected status before attempting a new connection
this.connected = false; this.connected = false;
console.log(`Connecting to WebSocket at ${this.url}`);
this.socket = new WebSocket(this.url); this.socket = new WebSocket(this.url);
this.socket.addEventListener('open', (event) => { this.socket.addEventListener('open', (event) => {