diff --git a/.gitignore b/.gitignore index 4bdda144..c47d0c82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ out /node_modules /webview/node_modules -/binary_modules/*/node_modules +/binary_modules/**/node_modules *.vsix .vscode-test .DS_Store diff --git a/.vscodeignore b/.vscodeignore index b54e6e44..9665623b 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -10,6 +10,6 @@ tsconfig.json vsc-extension-quickstart.md webpack.config.js node_modules -binary_modules/electron* +binary_modules !node_modules/@vscode/webview-ui-toolkit diff --git a/binary_modules/package-lock.json b/binary_modules/package-lock.json index 33314022..68b3781c 100644 --- a/binary_modules/package-lock.json +++ b/binary_modules/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "serialport": "^10.4.0" + "serialport": "^10.4.0", + "usb": "^2.14.0" }, "devDependencies": { "electron-rebuild": "^3.2.8" @@ -335,6 +336,12 @@ "@types/node": "*" } }, + "node_modules/@types/w3c-web-usb": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.10.tgz", + "integrity": "sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==", + "license": "MIT" + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -2044,6 +2051,30 @@ "node": ">= 10.0.0" } }, + "node_modules/usb": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/usb/-/usb-2.14.0.tgz", + "integrity": "sha512-I3lzVOH21BsO6qPYvx1C7Ji08lbuM0qmsEtNGAphqlhNME5cz/vExY+jIXZl+HQIRybI/sTxdyLab5tALsL69w==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@types/w3c-web-usb": "^1.0.6", + "node-addon-api": "^8.0.0", + "node-gyp-build": "^4.5.0" + }, + "engines": { + "node": ">=12.22.0 <13.0 || >=14.17.0" + } + }, + "node_modules/usb/node_modules/node-addon-api": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.1.0.tgz", + "integrity": "sha512-yBY+qqWSv3dWKGODD6OGE6GnTX7Q2r+4+DfpqxHSHh8x0B4EKP9+wVGLS6U/AM1vxSNNmUEuIV5EGhYwPpfOwQ==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -2361,6 +2392,11 @@ "@types/node": "*" } }, + "@types/w3c-web-usb": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.10.tgz", + "integrity": "sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -3637,6 +3673,23 @@ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true }, + "usb": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/usb/-/usb-2.14.0.tgz", + "integrity": "sha512-I3lzVOH21BsO6qPYvx1C7Ji08lbuM0qmsEtNGAphqlhNME5cz/vExY+jIXZl+HQIRybI/sTxdyLab5tALsL69w==", + "requires": { + "@types/w3c-web-usb": "^1.0.6", + "node-addon-api": "^8.0.0", + "node-gyp-build": "^4.5.0" + }, + "dependencies": { + "node-addon-api": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.1.0.tgz", + "integrity": "sha512-yBY+qqWSv3dWKGODD6OGE6GnTX7Q2r+4+DfpqxHSHh8x0B4EKP9+wVGLS6U/AM1vxSNNmUEuIV5EGhYwPpfOwQ==" + } + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/binary_modules/package.json b/binary_modules/package.json index cfd83917..e18d1d61 100644 --- a/binary_modules/package.json +++ b/binary_modules/package.json @@ -11,6 +11,7 @@ "electron-rebuild": "^3.2.8" }, "dependencies": { - "serialport": "^10.4.0" + "serialport": "^10.4.0", + "usb": "^2.14.0" } } diff --git a/debug_attributes.md b/debug_attributes.md index 30078505..a3ac46f1 100644 --- a/debug_attributes.md +++ b/debug_attributes.md @@ -88,8 +88,8 @@ If the type is marked as `{...}` it means that it is a complex item can have mul | swoConfig
.enabled | boolean | Both | Enable SWO decoding. | | swoConfig
.source | string | Both | Source for SWO data. Can either be "probe" to get directly from debug probe, or a serial port device to use a serial port external to the debug probe. | | swoConfig
.swoFrequency | number | Both | SWO frequency in Hz. | -| swoConfig
.swoPath | string | Both | Path name when source is "file" or "serial". Typically a /path-name or a serial-port-name | -| swoConfig
.swoPort | string | Both | When server is "external" && source is "socket", port to connect to. Format [host:]port | +| swoConfig
.swoPath | string | Both | Path name when source is "file" or "serial", device name regex match when source is "probe" for BMP. Typically a /path-name or a serial-port-name | +| swoConfig
.swoPort | string | Both | When server is "external" && source is "socket", port to connect to. Format [host:]port. For BMP, specifies the regex match of the USB interface contianing raw SWO data. | | symbolFiles | object[] | Both | Array of ELF files to load symbols from instead of the executable file. Each item in the array cab be a string or an object. Program information is ignored (see `loadFiles`). Can be an empty list to specify none. If this property does not exist, then the executable is used for symbols | | targetId | string | number | Both | On BMP this is the ID number that should be passed to the attach command (defaults to 1); for PyOCD this is the target identifier (only needed for custom hardware) | | targetProcessor | number | Both | The processor you want to debug. Zero based integer index. Must be less than 'numberOfProcessors' | diff --git a/package-lock.json b/package-lock.json index 6623fdf7..cd1d7919 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,9 +24,11 @@ "prebuild-install": "^7.0.1", "ringbufferjs": "^1.1.0", "safe-buffer": "^5.2.1", + "serialport": "^10.4.0", "stream-json": "^1.7.3", "tmp": "^0.2.1", "universal-analytics": "^0.5.3", + "usb": "^2.14.0", "uuid": "^8.3.2", "vscode-jsonrpc": "^6.0.0" }, @@ -259,6 +261,208 @@ "exenv-es6": "^1.1.1" } }, + "node_modules/@serialport/binding-mock": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-10.2.2.tgz", + "integrity": "sha512-HAFzGhk9OuFMpuor7aT5G1ChPgn5qSsklTFOTUX72Rl6p0xwcSVsRtG/xaGp6bxpN7fI9D/S8THLBWbBgS6ldw==", + "license": "MIT", + "dependencies": { + "@serialport/bindings-interface": "^1.2.1", + "debug": "^4.3.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@serialport/bindings-cpp": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/@serialport/bindings-cpp/-/bindings-cpp-10.7.0.tgz", + "integrity": "sha512-Xx1wA2UCG2loS32hxNvWJI4smCzGKhWqE85//fLRzHoGgE1lSLe3Nk7W40/ebrlGFHWRbQZmeaIF4chb2XLliA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@serialport/bindings-interface": "1.2.1", + "@serialport/parser-readline": "^10.2.1", + "debug": "^4.3.2", + "node-addon-api": "^4.3.0", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=12.17.0 <13.0 || >=14.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/bindings-cpp/node_modules/@serialport/bindings-interface": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@serialport/bindings-interface/-/bindings-interface-1.2.1.tgz", + "integrity": "sha512-63Dyqz2gtryRDDckFusOYqLYhR3Hq/M4sEdbF9i/VsvDb6T+tNVgoAKUZ+FMrXXKnCSu+hYbk+MTc0XQANszxw==", + "license": "MIT", + "engines": { + "node": "^12.22 || ^14.13 || >=16" + } + }, + "node_modules/@serialport/bindings-cpp/node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "license": "MIT" + }, + "node_modules/@serialport/bindings-interface": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@serialport/bindings-interface/-/bindings-interface-1.2.2.tgz", + "integrity": "sha512-CJaUd5bLvtM9c5dmO9rPBHPXTa9R2UwpkJ0wdh9JCYcbrPWsKz+ErvR0hBLeo7NPeiFdjFO4sonRljiw4d2XiA==", + "license": "MIT", + "engines": { + "node": "^12.22 || ^14.13 || >=16" + } + }, + "node_modules/@serialport/parser-byte-length": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-byte-length/-/parser-byte-length-10.3.0.tgz", + "integrity": "sha512-pJ/VoFemzKRRNDHLhFfPThwP40QrGaEnm9TtwL7o2GihEPwzBg3T0bN13ew5TpbbUYZdMpUtpm3CGfl6av9rUQ==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-cctalk": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-cctalk/-/parser-cctalk-10.3.0.tgz", + "integrity": "sha512-8ujmk8EvVbDPrNF4mM33bWvUYJOZ0wXbY3WCRazHRWvyCdL0VO0DQvW81ZqgoTpiDQZm5r8wQu9rmuemahF6vQ==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-delimiter": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-delimiter/-/parser-delimiter-10.3.0.tgz", + "integrity": "sha512-9E4Vj6s0UbbcCCTclwegHGPYjJhdm9qLCS0lowXQDEQC5naZnbsELemMHs93nD9jHPcyx1B4oXkMnVZLxX5TYw==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-inter-byte-timeout": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-inter-byte-timeout/-/parser-inter-byte-timeout-10.3.0.tgz", + "integrity": "sha512-wKP0QK85NHgvT6BBB1qBfKBBU4pf8kespNXAZBUYmFT+P4n8r8IZE2mqigCD+AiZcfWNQoAizwOsT/Jx/qeVig==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-packet-length": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-packet-length/-/parser-packet-length-10.3.0.tgz", + "integrity": "sha512-bj0cWzt8YSQj/E5fRQVYdi4TsfTlZQrXlXrUwjyTsCONv8IPOHzsz+yY0fw5SEMiJtaLyqvPkCHLsttOd/zFsg==", + "license": "MIT", + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/@serialport/parser-readline": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-readline/-/parser-readline-10.3.0.tgz", + "integrity": "sha512-ki3ATZ3/RAqnqGROBKE7k+OeZ0DZXZ53GTca4q71OU5RazbbNhTOBQLKLXD3v9QZXCMJdg4hGW/2Y0DuMUqMQg==", + "license": "MIT", + "dependencies": { + "@serialport/parser-delimiter": "10.3.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-ready": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-ready/-/parser-ready-10.3.0.tgz", + "integrity": "sha512-1owywJ4p592dJyVrEJZPIh6pUZ3/y/LN6kGTDH2wxdewRUITo/sGvDy0er5i2+dJD3yuowiAz0dOHSdz8tevJA==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-regex/-/parser-regex-10.3.0.tgz", + "integrity": "sha512-tIogTs7CvTH+UUFnsvE7i33MSISyTPTGPWlglWYH2/5coipXY503jlaYS1YGe818wWNcSx6YAjMZRdhTWwM39w==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-slip-encoder": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-slip-encoder/-/parser-slip-encoder-10.3.0.tgz", + "integrity": "sha512-JI0ILF5sylWn8f0MuMzHFBix/iMUTa79/Z95KaPZYnVaEdA7h7hh/o21Jmon/26P3RJwL1SNJCjZ81zfan+LtQ==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-spacepacket": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-spacepacket/-/parser-spacepacket-10.3.0.tgz", + "integrity": "sha512-PDF73ClEPsClD1FEJZHNuBevDKsJCkqy/XD5+S5eA6+tY5D4HLrVgSWsg+3qqB6+dlpwf2CzHe+uO8D3teuKHA==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/stream": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/stream/-/stream-10.3.0.tgz", + "integrity": "sha512-7sooi5fHogYNVEJwxVdg872xO6TuMgQd2E9iRmv+o8pk/1dbBnPkmH6Ka3st1mVE+0KnIJqVlgei+ncSsqXIGw==", + "license": "MIT", + "dependencies": { + "@serialport/bindings-interface": "1.2.1", + "debug": "^4.3.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/stream/node_modules/@serialport/bindings-interface": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@serialport/bindings-interface/-/bindings-interface-1.2.1.tgz", + "integrity": "sha512-63Dyqz2gtryRDDckFusOYqLYhR3Hq/M4sEdbF9i/VsvDb6T+tNVgoAKUZ+FMrXXKnCSu+hYbk+MTc0XQANszxw==", + "license": "MIT", + "engines": { + "node": "^12.22 || ^14.13 || >=16" + } + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -327,6 +531,12 @@ "integrity": "sha512-CQcY3+Fe5hNewHnOEAVYj4dd1do/QHliXaknAEYSXx2KEHUzFibDZSKptCon+HPgK55xx20pR+PBJjf0MomnBA==", "dev": true }, + "node_modules/@types/w3c-web-usb": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.10.tgz", + "integrity": "sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==", + "license": "MIT" + }, "node_modules/@ungap/promise-all-settled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", @@ -2458,6 +2668,26 @@ "node": ">=10" } }, + "node_modules/node-addon-api": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.1.0.tgz", + "integrity": "sha512-yBY+qqWSv3dWKGODD6OGE6GnTX7Q2r+4+DfpqxHSHh8x0B4EKP9+wVGLS6U/AM1vxSNNmUEuIV5EGhYwPpfOwQ==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", + "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-interval-tree": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/node-interval-tree/-/node-interval-tree-1.3.3.tgz", @@ -2935,6 +3165,34 @@ "randombytes": "^2.1.0" } }, + "node_modules/serialport": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/serialport/-/serialport-10.4.0.tgz", + "integrity": "sha512-PszPM5SnFMgSXom60PkKS2A9nMlNbHkuoyRBlzdSWw9rmgOn258+V0dYbWMrETJMM+TJV32vqBzjg5MmmUMwMw==", + "license": "MIT", + "dependencies": { + "@serialport/binding-mock": "10.2.2", + "@serialport/bindings-cpp": "10.7.0", + "@serialport/parser-byte-length": "10.3.0", + "@serialport/parser-cctalk": "10.3.0", + "@serialport/parser-delimiter": "10.3.0", + "@serialport/parser-inter-byte-timeout": "10.3.0", + "@serialport/parser-packet-length": "10.3.0", + "@serialport/parser-readline": "10.3.0", + "@serialport/parser-ready": "10.3.0", + "@serialport/parser-regex": "10.3.0", + "@serialport/parser-slip-encoder": "10.3.0", + "@serialport/parser-spacepacket": "10.3.0", + "@serialport/stream": "10.3.0", + "debug": "^4.3.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -3550,6 +3808,21 @@ "punycode": "^2.1.0" } }, + "node_modules/usb": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/usb/-/usb-2.14.0.tgz", + "integrity": "sha512-I3lzVOH21BsO6qPYvx1C7Ji08lbuM0qmsEtNGAphqlhNME5cz/vExY+jIXZl+HQIRybI/sTxdyLab5tALsL69w==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@types/w3c-web-usb": "^1.0.6", + "node-addon-api": "^8.0.0", + "node-gyp-build": "^4.5.0" + }, + "engines": { + "node": ">=12.22.0 <13.0 || >=14.17.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -4053,6 +4326,113 @@ "exenv-es6": "^1.1.1" } }, + "@serialport/binding-mock": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-10.2.2.tgz", + "integrity": "sha512-HAFzGhk9OuFMpuor7aT5G1ChPgn5qSsklTFOTUX72Rl6p0xwcSVsRtG/xaGp6bxpN7fI9D/S8THLBWbBgS6ldw==", + "requires": { + "@serialport/bindings-interface": "^1.2.1", + "debug": "^4.3.3" + } + }, + "@serialport/bindings-cpp": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/@serialport/bindings-cpp/-/bindings-cpp-10.7.0.tgz", + "integrity": "sha512-Xx1wA2UCG2loS32hxNvWJI4smCzGKhWqE85//fLRzHoGgE1lSLe3Nk7W40/ebrlGFHWRbQZmeaIF4chb2XLliA==", + "requires": { + "@serialport/bindings-interface": "1.2.1", + "@serialport/parser-readline": "^10.2.1", + "debug": "^4.3.2", + "node-addon-api": "^4.3.0", + "node-gyp-build": "^4.3.0" + }, + "dependencies": { + "@serialport/bindings-interface": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@serialport/bindings-interface/-/bindings-interface-1.2.1.tgz", + "integrity": "sha512-63Dyqz2gtryRDDckFusOYqLYhR3Hq/M4sEdbF9i/VsvDb6T+tNVgoAKUZ+FMrXXKnCSu+hYbk+MTc0XQANszxw==" + }, + "node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + } + } + }, + "@serialport/bindings-interface": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@serialport/bindings-interface/-/bindings-interface-1.2.2.tgz", + "integrity": "sha512-CJaUd5bLvtM9c5dmO9rPBHPXTa9R2UwpkJ0wdh9JCYcbrPWsKz+ErvR0hBLeo7NPeiFdjFO4sonRljiw4d2XiA==" + }, + "@serialport/parser-byte-length": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-byte-length/-/parser-byte-length-10.3.0.tgz", + "integrity": "sha512-pJ/VoFemzKRRNDHLhFfPThwP40QrGaEnm9TtwL7o2GihEPwzBg3T0bN13ew5TpbbUYZdMpUtpm3CGfl6av9rUQ==" + }, + "@serialport/parser-cctalk": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-cctalk/-/parser-cctalk-10.3.0.tgz", + "integrity": "sha512-8ujmk8EvVbDPrNF4mM33bWvUYJOZ0wXbY3WCRazHRWvyCdL0VO0DQvW81ZqgoTpiDQZm5r8wQu9rmuemahF6vQ==" + }, + "@serialport/parser-delimiter": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-delimiter/-/parser-delimiter-10.3.0.tgz", + "integrity": "sha512-9E4Vj6s0UbbcCCTclwegHGPYjJhdm9qLCS0lowXQDEQC5naZnbsELemMHs93nD9jHPcyx1B4oXkMnVZLxX5TYw==" + }, + "@serialport/parser-inter-byte-timeout": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-inter-byte-timeout/-/parser-inter-byte-timeout-10.3.0.tgz", + "integrity": "sha512-wKP0QK85NHgvT6BBB1qBfKBBU4pf8kespNXAZBUYmFT+P4n8r8IZE2mqigCD+AiZcfWNQoAizwOsT/Jx/qeVig==" + }, + "@serialport/parser-packet-length": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-packet-length/-/parser-packet-length-10.3.0.tgz", + "integrity": "sha512-bj0cWzt8YSQj/E5fRQVYdi4TsfTlZQrXlXrUwjyTsCONv8IPOHzsz+yY0fw5SEMiJtaLyqvPkCHLsttOd/zFsg==" + }, + "@serialport/parser-readline": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-readline/-/parser-readline-10.3.0.tgz", + "integrity": "sha512-ki3ATZ3/RAqnqGROBKE7k+OeZ0DZXZ53GTca4q71OU5RazbbNhTOBQLKLXD3v9QZXCMJdg4hGW/2Y0DuMUqMQg==", + "requires": { + "@serialport/parser-delimiter": "10.3.0" + } + }, + "@serialport/parser-ready": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-ready/-/parser-ready-10.3.0.tgz", + "integrity": "sha512-1owywJ4p592dJyVrEJZPIh6pUZ3/y/LN6kGTDH2wxdewRUITo/sGvDy0er5i2+dJD3yuowiAz0dOHSdz8tevJA==" + }, + "@serialport/parser-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-regex/-/parser-regex-10.3.0.tgz", + "integrity": "sha512-tIogTs7CvTH+UUFnsvE7i33MSISyTPTGPWlglWYH2/5coipXY503jlaYS1YGe818wWNcSx6YAjMZRdhTWwM39w==" + }, + "@serialport/parser-slip-encoder": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-slip-encoder/-/parser-slip-encoder-10.3.0.tgz", + "integrity": "sha512-JI0ILF5sylWn8f0MuMzHFBix/iMUTa79/Z95KaPZYnVaEdA7h7hh/o21Jmon/26P3RJwL1SNJCjZ81zfan+LtQ==" + }, + "@serialport/parser-spacepacket": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-spacepacket/-/parser-spacepacket-10.3.0.tgz", + "integrity": "sha512-PDF73ClEPsClD1FEJZHNuBevDKsJCkqy/XD5+S5eA6+tY5D4HLrVgSWsg+3qqB6+dlpwf2CzHe+uO8D3teuKHA==" + }, + "@serialport/stream": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@serialport/stream/-/stream-10.3.0.tgz", + "integrity": "sha512-7sooi5fHogYNVEJwxVdg872xO6TuMgQd2E9iRmv+o8pk/1dbBnPkmH6Ka3st1mVE+0KnIJqVlgei+ncSsqXIGw==", + "requires": { + "@serialport/bindings-interface": "1.2.1", + "debug": "^4.3.2" + }, + "dependencies": { + "@serialport/bindings-interface": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@serialport/bindings-interface/-/bindings-interface-1.2.1.tgz", + "integrity": "sha512-63Dyqz2gtryRDDckFusOYqLYhR3Hq/M4sEdbF9i/VsvDb6T+tNVgoAKUZ+FMrXXKnCSu+hYbk+MTc0XQANszxw==" + } + } + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -4118,6 +4498,11 @@ "integrity": "sha512-CQcY3+Fe5hNewHnOEAVYj4dd1do/QHliXaknAEYSXx2KEHUzFibDZSKptCon+HPgK55xx20pR+PBJjf0MomnBA==", "dev": true }, + "@types/w3c-web-usb": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.10.tgz", + "integrity": "sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==" + }, "@ungap/promise-all-settled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", @@ -5711,6 +6096,16 @@ "semver": "^7.3.5" } }, + "node-addon-api": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.1.0.tgz", + "integrity": "sha512-yBY+qqWSv3dWKGODD6OGE6GnTX7Q2r+4+DfpqxHSHh8x0B4EKP9+wVGLS6U/AM1vxSNNmUEuIV5EGhYwPpfOwQ==" + }, + "node-gyp-build": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", + "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==" + }, "node-interval-tree": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/node-interval-tree/-/node-interval-tree-1.3.3.tgz", @@ -6068,6 +6463,27 @@ "randombytes": "^2.1.0" } }, + "serialport": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/serialport/-/serialport-10.4.0.tgz", + "integrity": "sha512-PszPM5SnFMgSXom60PkKS2A9nMlNbHkuoyRBlzdSWw9rmgOn258+V0dYbWMrETJMM+TJV32vqBzjg5MmmUMwMw==", + "requires": { + "@serialport/binding-mock": "10.2.2", + "@serialport/bindings-cpp": "10.7.0", + "@serialport/parser-byte-length": "10.3.0", + "@serialport/parser-cctalk": "10.3.0", + "@serialport/parser-delimiter": "10.3.0", + "@serialport/parser-inter-byte-timeout": "10.3.0", + "@serialport/parser-packet-length": "10.3.0", + "@serialport/parser-readline": "10.3.0", + "@serialport/parser-ready": "10.3.0", + "@serialport/parser-regex": "10.3.0", + "@serialport/parser-slip-encoder": "10.3.0", + "@serialport/parser-spacepacket": "10.3.0", + "@serialport/stream": "10.3.0", + "debug": "^4.3.3" + } + }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -6506,6 +6922,16 @@ "punycode": "^2.1.0" } }, + "usb": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/usb/-/usb-2.14.0.tgz", + "integrity": "sha512-I3lzVOH21BsO6qPYvx1C7Ji08lbuM0qmsEtNGAphqlhNME5cz/vExY+jIXZl+HQIRybI/sTxdyLab5tALsL69w==", + "requires": { + "@types/w3c-web-usb": "^1.0.6", + "node-addon-api": "^8.0.0", + "node-gyp-build": "^4.5.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 11776e1a..074dfc7e 100644 --- a/package.json +++ b/package.json @@ -2493,12 +2493,12 @@ "swoPath": { "type": "string", "default": "", - "description": "Path name when source is \"file\" or \"serial\". Typically a /path-name or a serial-port-name" + "description": "Path name when source is \"file\" or \"serial\", device name regex match when source is \"probe\" for BMP. Typically a /path-name or a serial-port-name" }, "swoPort": { "type": "string", "default": "", - "description": "When server is \"external\" && source is \"socket\", port to connect to. Format [host:]port" + "description": "When server is \"external\" && source is \"socket\", port to connect to. Format [host:]port. For BMP, specifies the regex match of the USB interface contianing raw SWO data." }, "decoders": { "description": "SWO Decoder Configuration", @@ -3005,9 +3005,11 @@ "prebuild-install": "^7.0.1", "ringbufferjs": "^1.1.0", "safe-buffer": "^5.2.1", + "serialport": "^10.4.0", "stream-json": "^1.7.3", "tmp": "^0.2.1", "universal-analytics": "^0.5.3", + "usb": "^2.14.0", "uuid": "^8.3.2", "vscode-jsonrpc": "^6.0.0" }, @@ -3057,7 +3059,7 @@ "url": "https://github.com/Marus/cortex-debug/issues" }, "scripts": { - "vscode:prepublish": "npm run lint && webpack --mode production && node dist/docgen.js", + "vscode:prepublish": "npm run lint && webpack --mode production && node dist/docgen.js && npm ci -C binary_modules --omit dev && cp -a binary_modules/node_modules dist/", "watch": "webpack --mode development --watch", "compile": "webpack --mode development && node dist/docgen.js", "test-compile": "tsc -p ./", diff --git a/src/bmp.ts b/src/bmp.ts index 6b6bf34a..dfb72f0b 100644 --- a/src/bmp.ts +++ b/src/bmp.ts @@ -109,6 +109,10 @@ export class BMPServerController extends EventEmitter implements GDBServerContro ); commands.push(this.args.swoConfig.profile ? 'EnablePCSample' : 'DisablePCSample'); + + if (this.args.swoConfig.source === 'probe') { + commands.push('monitor traceswo'); + } return commands.map((c) => `interpreter-exec console "${c}"`); } @@ -131,13 +135,22 @@ export class BMPServerController extends EventEmitter implements GDBServerContro public serverLaunchStarted(): void {} public serverLaunchCompleted(): void { - if (this.args.swoConfig.enabled && this.args.swoConfig.source !== 'probe') { - this.emit('event', new SWOConfigureEvent({ - type: 'serial', - args: this.args, - device: this.args.swoConfig.source, - baudRate: this.args.swoConfig.swoFrequency - })); + if (this.args.swoConfig.enabled) { + if (this.args.swoConfig.source === 'probe') { + this.emit('event', new SWOConfigureEvent({ + type: 'usb', + args: this.args, + device: this.args.swoConfig.swoPath || 'Black Magic Probe', + port: this.args.swoConfig.swoPort || 'Black Magic Trace Capture' + })); + } else { + this.emit('event', new SWOConfigureEvent({ + type: 'serial', + args: this.args, + device: this.args.swoConfig.source, + baudRate: this.args.swoConfig.swoFrequency + })); + } } } diff --git a/src/frontend/configprovider.ts b/src/frontend/configprovider.ts index 8b359f2a..538c955a 100644 --- a/src/frontend/configprovider.ts +++ b/src/frontend/configprovider.ts @@ -622,12 +622,6 @@ export class CortexDebugConfigurationProvider implements vscode.DebugConfigurati return 'The Black Magic Probe GDB Server does not have support for the rtos option.'; } - if (config.swoConfig.enabled && config.swoConfig.source === 'probe') { - vscode.window.showWarningMessage('SWO support is not available from the probe when using the BMP GDB server. Disabling SWO.'); - config.swoConfig = { enabled: false, ports: [], cpuFrequency: 0, swoFrequency: 0 }; - config.graphConfig = []; - } - return null; } diff --git a/src/frontend/extension.ts b/src/frontend/extension.ts index 89212063..f445f917 100644 --- a/src/frontend/extension.ts +++ b/src/frontend/extension.ts @@ -16,6 +16,7 @@ import { JLinkSocketRTTSource, SocketRTTSource, SocketSWOSource, PeMicroSocketSo import { FifoSWOSource } from './swo/sources/fifo'; import { FileSWOSource } from './swo/sources/file'; import { SerialSWOSource } from './swo/sources/serial'; +import { UsbSWOSource } from './swo/sources/usb'; import { SymbolInformation, SymbolScope } from '../symbols'; import { RTTTerminal } from './rtt_terminal'; import { GDBServerConsole } from './server_console'; @@ -760,9 +761,13 @@ export class CortexDebugExtension { Reporting.sendEvent('SWO', 'Source', 'File'); } else if (e.body.type === 'serial') { - mySession.swoSource = new SerialSWOSource(e.body.device, e.body.baudRate, this.context.extensionPath); + mySession.swoSource = new SerialSWOSource(e.body.device, e.body.baudRate); Reporting.sendEvent('SWO', 'Source', 'Serial'); } + else if (e.body.type === 'usb') { + mySession.swoSource = new UsbSWOSource(e.body.device, e.body.port); + Reporting.sendEvent('SWO', 'Source', 'USB'); + } this.initializeSWO(e.session, e.body.args); } diff --git a/src/frontend/swo/sources/serial.ts b/src/frontend/swo/sources/serial.ts index 90c2ddd1..7f58a834 100644 --- a/src/frontend/swo/sources/serial.ts +++ b/src/frontend/swo/sources/serial.ts @@ -1,82 +1,17 @@ import { SWORTTSource } from './common'; import { EventEmitter } from 'events'; -import * as fs from 'fs'; -import * as os from 'os'; +import type { SerialPort } from 'serialport'; import * as vscode from 'vscode'; -import * as path from 'path'; - -export function findSerialPortModuleHelp(extensionPath: string) { - return 'Node/npm module "serialport" not found. You can install this in one of two ways\n' + - '1. Install "Serial Monitor" VSCode extension. https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-serial-monitor\n' + - '2. or, you can compile the serialport module locally on your computer. Follow these instructions on a shell prompt\n' + - ` cd ${extensionPath}/binary_modules\n` + - ` bash ./build.sh ${process.versions['electron']}\n` + - 'If you chose to compile locally, make sure NodeJS is installed on your system. Visit https://nodejs.org/en/download/'; -} - -export function findSerialPortModule(extensionPath: string, useModule) { - const paths = []; - const p = path.normalize(path.join(extensionPath, 'binary_modules', 'electron-' + process.versions['electron'], 'node_modules')); - if (fs.existsSync(p) && fs.existsSync(path.join(p, 'serialport'))) { - paths.push(p); - } else { - const serMonitorExt = 'ms-vscode.vscode-serial-monitor'; - const serialMonitor: vscode.Extension = vscode.extensions.getExtension(serMonitorExt); - if (serialMonitor) { - paths.push(path.join(serialMonitor.extensionPath, 'dist', 'node_modules')); - paths.push(path.join(serialMonitor.extensionPath, 'node_modules')); - } - } - - let added = false; - for (const p of paths) { - if (fs.existsSync(path.join(p, 'serialport'))) { - if (useModule.paths.indexOf(p) === -1) { - console.log(`Adding ${p} to module search path`); - useModule.paths.push(p); - } - added = true; - } - } - return added; -} - -declare function __webpack_require__(name: string): any; -declare function __non_webpack_require__(name: string): any; export class SerialSWOSource extends EventEmitter implements SWORTTSource { - private serialPort: any = null; + private serialPort: SerialPort = null; public connected: boolean = false; - constructor(private device: string, private baudRate: number, extensionPath: string) { + constructor(private device: string, private baudRate: number) { super(); - /* While this is a bit ugly - it works around WebPack's mangling of the require statements. eval('require.main') gets us - the main module in a non-mangled form (instead of the current module - but that is not important for our purposes here) - and allows us to modify the paths and load in the serial port from there. We have to wrap it in an eval statement to avoid - webpack mangling */ - // tslint:disable-next-line: no-eval - const mainModule = eval('require.main'); - const added = findSerialPortModule(extensionPath, mainModule); - if (!added) { - vscode.window.showErrorMessage(findSerialPortModuleHelp(extensionPath)); - return; - } - - let SerialPort; - try { - SerialPort = mainModule.require('serialport').SerialPort; - if (!SerialPort) { - vscode.window.showErrorMessage(findSerialPortModuleHelp(extensionPath)); - return; - } - } - catch (e) { - vscode.window.showErrorMessage(findSerialPortModuleHelp(extensionPath)); - return; - } - - this.serialPort = new SerialPort(device, { baudRate: baudRate, autoOpen: false }); + const { SerialPort } = require('serialport'); + this.serialPort = new SerialPort({ path: device, baudRate: baudRate, autoOpen: false }); this.serialPort.on('data', (buffer) => { this.emit('data', buffer); }); diff --git a/src/frontend/swo/sources/usb.ts b/src/frontend/swo/sources/usb.ts new file mode 100644 index 00000000..e94ba867 --- /dev/null +++ b/src/frontend/swo/sources/usb.ts @@ -0,0 +1,158 @@ +import { EventEmitter } from 'stream'; +import { SWORTTSource } from './common'; +import { promisify } from 'util'; +import * as vscode from 'vscode'; +import * as usb from 'usb'; + +/* + * NOTE: using legacy node-usb interface, because the modern + * WebUSB-compatible version doesn't contain a way to interrupt pending + * transfer, leading to problems with getting rid of the connection + */ + +export class UsbSWOSource extends EventEmitter implements SWORTTSource { + private dev?: usb.Device; + private iface?: usb.Interface; + private ep?: usb.InEndpoint; + + constructor( + private readonly device: string, + private readonly port: string + ) { + super(); + + this.start(); + } + + private async findDevice(): Promise< + | { + dev: usb.Device; + config: usb.ConfigDescriptor; + iface: usb.InterfaceDescriptor; + endpoint: usb.EndpointDescriptor; + productName: string + } + | undefined + > { + console.info('Looking for USB devices matching', this.device); + const devs = usb.getDeviceList(); + for (const dev of devs) { + dev.open(); + const { deviceDescriptor: dd } = dev; + const getStringDescriptor: (index: number) => Promise = + promisify(dev.getStringDescriptor).bind(dev); + const productName = await getStringDescriptor(dd.iProduct); + if (productName.match(this.device)) { + console.info( + 'Found device', + productName, + 'VID', + dd.idVendor.toString(16), + 'PID', + dd.idProduct.toString(16), + 'Serial', + await getStringDescriptor(dd.iSerialNumber) + ); + + for (const cfg of dev.allConfigDescriptors) { + for (const iface of cfg.interfaces) { + for (const alt of iface) { + const interfaceName = await getStringDescriptor(alt.iInterface); + if (interfaceName?.match(this.port)) { + for (const ep of alt.endpoints) { + if ((ep.bmAttributes & 3) === usb.usb.LIBUSB_TRANSFER_TYPE_BULK && + ep.bEndpointAddress & usb.usb.LIBUSB_ENDPOINT_IN) { + console.info( + 'Matched config', + cfg.bConfigurationValue, + 'interface', + alt.bInterfaceNumber, + 'alternate', + alt.bAlternateSetting, + 'endpoint', + ep.bEndpointAddress + ); + return { + dev, + config: cfg, + iface: alt, + endpoint: ep, + productName + }; + } + } + } + } + } + } + + console.warn('Couldn\'t match interface named', this.port); + } + dev.close(); + } + console.warn('Matching device not found'); + return undefined; + } + + public async start() { + const { dev, config, iface, endpoint, productName } = (await this.findDevice()) ?? {}; + if (!dev) { + vscode.window.showErrorMessage( + `Couldn't find a device matching '${this.device}' with interface '${this.port}` + ); + return; + } + + console.debug('Connecting to', productName); + await dev.open(); + this.dev = dev; + console.debug('Selecting configuration', config.bConfigurationValue); + await promisify(dev.setConfiguration).bind(dev)(config.bConfigurationValue); + console.debug('Claiming interface', iface.bInterfaceNumber); + this.iface = dev.interface(iface.bInterfaceNumber); + this.iface.claim(); + if (iface.bAlternateSetting) { + console.debug('Selecting alternate', iface.bAlternateSetting); + await dev.interface(iface.iInterface).setAltSettingAsync(iface.bAlternateSetting); + } + console.debug('Reading from endpoint', endpoint.bEndpointAddress); + + this.ep = this.iface.endpoint(endpoint.bEndpointAddress) as usb.InEndpoint; + this.ep.on('data', (buffer: Buffer) => { + console.debug(buffer.length, 'bytes received'); + this.emit('data', buffer); + }); + this.ep.on('error', (error) => { + console.error('Unexpected polling error', error); + }); + this.ep.startPoll(); + + this.emit('connected'); + } + + public get connected() { + return !!this.ep; + } + + public async dispose() { + if (this.ep) { + console.debug('Stopping polling...'); + await promisify(this.ep.stopPoll).bind(this.ep)(); + this.ep = undefined; + console.debug('Polling stopped'); + } + if (this.iface) { + console.debug('Releasing interface...'); + await this.iface.releaseAsync(); + this.iface = undefined; + console.debug('Interface released'); + } + if (this.dev) { + console.debug('Closing device...'); + this.dev.close(); + this.dev = undefined; + console.debug('Device closed'); + } + this.emit('disconnected'); + } +} diff --git a/test/suite/serialport.test.ts b/test/suite/serialport.test.ts index af5f8342..b750934c 100644 --- a/test/suite/serialport.test.ts +++ b/test/suite/serialport.test.ts @@ -1,17 +1,6 @@ import * as assert from 'assert'; -import * as vscode from 'vscode'; -import { findSerialPortModule, findSerialPortModuleHelp } from '../../src/frontend/swo/sources/serial'; suite('Serial Port tests', () => { - const extensionPath = vscode.extensions.getExtension('marus25.cortex-debug').extensionPath; - const added = findSerialPortModule(extensionPath, module); - // console.log(findSerialPortModuleHelp(extensionPath)); - test('Serial Port exists', async () => { - if (!added) { - console.log(findSerialPortModuleHelp(extensionPath)); - assert.fail('Could not find serialport module'); - } - }); test('Serial Port list', async () => { let SerialPort; try { diff --git a/webpack.config.js b/webpack.config.js index 3cba17b5..e62f4867 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -25,7 +25,8 @@ const extensionConfig = { devtool: 'source-map', externals: { vscode: 'vscode', - serialport: 'serialport' + serialport: 'serialport', + usb: 'usb' }, resolve: { extensions: ['.ts', '.js'] @@ -57,7 +58,8 @@ const adapterConfig = { devtool: 'source-map', externals: { vscode: 'vscode', - serialport: 'serialport' + serialport: 'serialport', + usb: 'usb', }, resolve: { extensions: ['.ts', '.js']