diff --git a/README.md b/README.md index 72bfaed8..d059ae41 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,6 @@ You can find code samples and tutorials each time that you connect a supported d This extension provides several commands in the Command Palette (F1 or Ctrl + Shift + P *or* Cmd + Shift + P) for working with `*.ino` files: - **Arduino: Board Manager**: Manage packages for boards. You can add 3rd party Arduino board by configuring `Additional Board Manager URLs` in the board manager. -- **Arduino: Change Baud Rate**: Change the baud rate of the selected serial port. - **Arduino: Change Board Type**: Change board type or platform. - **Arduino: Change Timestamp Format**: Change format of timestamp printed before each line of Serial Monitor output. - **Arduino: Close Serial Monitor**: Stop the serial monitor and release the serial port. @@ -67,7 +66,6 @@ This extension provides several commands in the Command Palette (F1 o - **Arduino: Library Manager**: Explore and manage libraries. - **Arduino: Open Serial Monitor**: Open the serial monitor in the integrated output window. - **Arduino: Select Serial Port**: Change the current serial port. -- **Arduino: Send Text to Serial Port**: Send a line of text via the current serial port. - **Arduino: Upload**: Build sketch and upload to Arduino board. - **Arduino: CLI Upload**: Upload complied code without building sketch (CLI only). - **Arduino: Upload Using Programmer**: Upload using an external programmer. @@ -93,8 +91,6 @@ This extension provides several commands in the Command Palette (F1 o | `arduino.enableUSBDetection` | Enable/disable USB detection from the VSCode Arduino extension. The default value is `true`. When your device is plugged in to your computer, it will pop up a message "`Detected board ****, Would you like to switch to this board type`". After clicking the `Yes` button, it will automatically detect which serial port (COM) is connected a USB device. If your device does not support this feature, please provide us with the PID/VID of your device; the code format is defined in `misc/usbmapping.json`.To learn more about how to list the vid/pid, use the following tools: https://github.com/EmergingTechnologyAdvisors/node-serialport `npm install -g serialport` `serialport-list -f jsonline`| | `arduino.disableTestingOpen` | Enable/disable automatic sending of a test message to the serial port for checking the open status. The default value is `false` (a test message will be sent). | | `arduino.skipHeaderProvider` | Enable/disable the extension providing completion items for headers. This functionality is included in newer versions of the C++ extension. The default value is `false`.| -| `arduino.defaultBaudRate` | Default baud rate for the serial port monitor. The default value is 115200. Supported values are 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400 and 250000 | -| `arduino.defaultTimestampFormat` | Format of timestamp printed before each line of Serial Monitor output. You can find list of all available placeholders [here](https://github.com/samsonjs/strftime#supported-specifiers). | | `arduino.disableIntelliSenseAutoGen` | When `true` vscode-arduino will not auto-generate an IntelliSense configuration (i.e. `.vscode/c_cpp_properties.json`) by analyzing Arduino's compiler output. | | `arduino.analyzeOnOpen` | When true, automatically run analysis when the project is opened. Only works when `arduino.analyzeOnSettingChange` is true. | | `arduino.analyzeOnSettingChange` | When true, automatically run analysis when board, configuration, or sketch settings are changed. | @@ -113,7 +109,6 @@ The following Visual Studio Code settings are available for the Arduino extensio "https://raw.githubusercontent.com/VSChina/azureiotdevkit_tools/master/package_azureboard_index.json", "http://arduino.esp8266.com/stable/package_esp8266com_index.json" ], - "arduino.defaultBaudRate": 115200 } ``` diff --git a/package-lock.json b/package-lock.json index 56fbfe85..9af1345b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { + "@microsoft/vscode-serial-monitor-api": "^0.1.5", "@vscode/extension-telemetry": "~0.6.2", "body-parser": "^1.16.1", "cocopa": "0.0.13", @@ -21,7 +22,6 @@ "iconv-lite": "^0.4.18", "impor": "^0.1.1", "properties": "^1.2.1", - "serialport": "^10.2.2", "strftime": "^0.9.2", "usb-detection": "^4.13.0", "uuid": "^3.0.1", @@ -2063,6 +2063,14 @@ "resolved": "https://registry.npmjs.org/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.7.tgz", "integrity": "sha512-SK3D3aVt+5vOOccKPnGaJWB5gQ8FuKfjboUJHedMP7gu54HqSCXX5iFXhktGD8nfJb0Go30eDvs/UDoTnR2kOA==" }, + "node_modules/@microsoft/vscode-serial-monitor-api": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@microsoft/vscode-serial-monitor-api/-/vscode-serial-monitor-api-0.1.5.tgz", + "integrity": "sha512-IQ9M4ma+E6nu7JMrIaL8Hx2P0+31NfPr6hJ6B7R0BzRxe8QQ/7o3/nPDh0HAxD+xPic2GjasiQrEFpe6eGxagQ==", + "engines": { + "vscode": "^1.22.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2098,170 +2106,6 @@ "node": ">= 8" } }, - "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==", - "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, - "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-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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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/@sindresorhus/is": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", @@ -11129,11 +10973,6 @@ "node": ">=10" } }, - "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==" - }, "node_modules/node-environment-flags": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", @@ -11178,16 +11017,6 @@ "node": ">= 6.0.0" } }, - "node_modules/node-gyp-build": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", - "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, "node_modules/node-gyp/node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -13382,33 +13211,6 @@ "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==", - "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/serve-static": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", @@ -17891,6 +17693,11 @@ "resolved": "https://registry.npmjs.org/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.7.tgz", "integrity": "sha512-SK3D3aVt+5vOOccKPnGaJWB5gQ8FuKfjboUJHedMP7gu54HqSCXX5iFXhktGD8nfJb0Go30eDvs/UDoTnR2kOA==" }, + "@microsoft/vscode-serial-monitor-api": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@microsoft/vscode-serial-monitor-api/-/vscode-serial-monitor-api-0.1.5.tgz", + "integrity": "sha512-IQ9M4ma+E6nu7JMrIaL8Hx2P0+31NfPr6hJ6B7R0BzRxe8QQ/7o3/nPDh0HAxD+xPic2GjasiQrEFpe6eGxagQ==" + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -17917,94 +17724,6 @@ "fastq": "^1.6.0" } }, - "@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" - } - }, - "@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==" - }, - "@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" - } - }, "@sindresorhus/is": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", @@ -25068,11 +24787,6 @@ "semver": "^7.3.5" } }, - "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==" - }, "node-environment-flags": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", @@ -25127,11 +24841,6 @@ } } }, - "node-gyp-build": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", - "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==" - }, "node-libs-browser": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", @@ -26837,27 +26546,6 @@ "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" - } - }, "serve-static": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", diff --git a/package.json b/package.json index 4531ba2d..d465f629 100644 --- a/package.json +++ b/package.json @@ -42,10 +42,8 @@ "onCommand:arduino.selectProgrammer", "onCommand:arduino.selectSerialPort", "onCommand:arduino.selectSketch", - "onCommand:arduino.changeBaudRate", - "onCommand:arduino.changeTimestampFormat", "onCommand:arduino.openSerialMonitor", - "onCommand:arduino.sendMessageToSerialPort", + "onCommand:arduino.changeTimestampFormat", "onCommand:arduino.closeSerialMonitor", "onCommand:arduino.changeBoardType", "onCommand:arduino.showBoardConfig", @@ -125,17 +123,13 @@ "title": "Arduino: Select Serial Port" }, { - "command": "arduino.changeBaudRate", - "title": "Arduino: Change Baud Rate" + "command": "arduino.openSerialMonitor", + "title": "Arduino: Open Serial Monitor" }, { "command": "arduino.changeTimestampFormat", "title": "Arduino: Change Timestamp Format" }, - { - "command": "arduino.openSerialMonitor", - "title": "Arduino: Open Serial Monitor" - }, { "command": "arduino.closeSerialMonitor", "title": "Arduino: Close Serial Monitor" @@ -527,20 +521,11 @@ "type": "boolean", "default": false }, - "arduino.defaultBaudRate": { - "type": "number", - "default": 115200 - }, "arduino.disableIntelliSenseAutoGen": { "type": "boolean", "default": false, "description": "When disabled vscode-arduino will not auto-generate an IntelliSense configuration (i.e. c_cpp_properties.json) by analyzing the compiler output." }, - "arduino.defaultTimestampFormat": { - "type": "string", - "default": "", - "markdownDescription": "Format of timestamp printed before each line of Serial Monitor output. You can find list of all available placeholders [here](https://github.com/samsonjs/strftime#supported-specifiers)." - }, "arduino.analyzeOnOpen": { "type": "boolean", "default": true, @@ -600,7 +585,8 @@ "test": "gulp test" }, "extensionDependencies": [ - "ms-vscode.cpptools" + "ms-vscode.cpptools", + "ms-vscode.vscode-serial-monitor" ], "devDependencies": { "@babel/core": "^7.15.5", @@ -646,6 +632,7 @@ "webpack": "^4.44.1" }, "dependencies": { + "@microsoft/vscode-serial-monitor-api": "^0.1.5", "@vscode/extension-telemetry": "~0.6.2", "body-parser": "^1.16.1", "cocopa": "0.0.13", @@ -657,7 +644,6 @@ "iconv-lite": "^0.4.18", "impor": "^0.1.1", "properties": "^1.2.1", - "serialport": "^10.2.2", "strftime": "^0.9.2", "usb-detection": "^4.13.0", "uuid": "^3.0.1", diff --git a/src/arduino/arduino.ts b/src/arduino/arduino.ts index a6135133..2fd0ea33 100644 --- a/src/arduino/arduino.ts +++ b/src/arduino/arduino.ts @@ -747,7 +747,7 @@ export class ArduinoApp { if (buildMode === BuildMode.Upload || buildMode === BuildMode.UploadProgrammer) { UsbDetector.getInstance().resumeListening(); if (restoreSerialMonitor) { - await SerialMonitor.getInstance().openSerialMonitor(); + await SerialMonitor.getInstance().openSerialMonitor(true); } } return ret; diff --git a/src/arduino/arduinoSettings.ts b/src/arduino/arduinoSettings.ts index 26bacaef..c23412c0 100644 --- a/src/arduino/arduinoSettings.ts +++ b/src/arduino/arduinoSettings.ts @@ -22,11 +22,9 @@ export interface IArduinoSettings { defaultLibPath: string; sketchbookPath: string; preferencePath: string; - defaultBaudRate: number; preferences: Map; useArduinoCli: boolean; usingBundledArduinoCli: boolean; - defaultTimestampFormat: string; analyzeOnSettingChange: boolean; reloadPreferences(): void; } @@ -40,14 +38,10 @@ export class ArduinoSettings implements IArduinoSettings { private _sketchbookPath: string; - private _defaultBaudRate: number; - private _preferences: Map; private _useArduinoCli: boolean; - private _defaultTimestampFormat: string; - private _usingBundledArduinoCli: boolean = false; private readonly bundledArduinoCliName: { [platform: string]: string } = { @@ -68,8 +62,6 @@ export class ArduinoSettings implements IArduinoSettings { this._commandPath = VscodeSettings.getInstance().commandPath; this._useArduinoCli = VscodeSettings.getInstance().useArduinoCli; await this.tryResolveArduinoPath(); - await this.tryGetDefaultBaudRate(); - await this.tryGetDefaultTimestampFormat(); if (platform === "win32") { await this.updateWindowsPath(); if (this._commandPath === "") { @@ -181,15 +173,6 @@ export class ArduinoSettings implements IArduinoSettings { public get usingBundledArduinoCli() { return this._usingBundledArduinoCli; } - - public get defaultBaudRate() { - return this._defaultBaudRate; - } - - public get defaultTimestampFormat() { - return this._defaultTimestampFormat; - } - public get analyzeOnSettingChange(): boolean { return VscodeSettings.getInstance().analyzeOnSettingChange; } @@ -278,23 +261,4 @@ export class ArduinoSettings implements IArduinoSettings { this._arduinoPath = configValue; } } - - private async tryGetDefaultBaudRate(): Promise { - const supportBaudRates = [300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 250000]; - const configValue = VscodeSettings.getInstance().defaultBaudRate; - if (!configValue || supportBaudRates.indexOf(configValue) === -1) { - this._defaultBaudRate = 0; - } else { - this._defaultBaudRate = configValue; - } - } - - private async tryGetDefaultTimestampFormat(): Promise { - const configValue = VscodeSettings.getInstance().defaultTimestampFormat; - if (!configValue) { - this._defaultTimestampFormat = ""; - } else { - this._defaultTimestampFormat = configValue; - } - } } diff --git a/src/arduino/vscodeSettings.ts b/src/arduino/vscodeSettings.ts index 54d43dfb..09e3a180 100644 --- a/src/arduino/vscodeSettings.ts +++ b/src/arduino/vscodeSettings.ts @@ -16,10 +16,8 @@ const configKeys = { DISABLE_TESTING_OPEN: "arduino.disableTestingOpen", IGNORE_BOARDS: "arduino.ignoreBoards", SKIP_HEADER_PROVIDER: "arduino.skipHeaderProvider", - DEFAULT_BAUD_RATE: "arduino.defaultBaudRate", USE_ARDUINO_CLI: "arduino.useArduinoCli", DISABLE_INTELLISENSE_AUTO_GEN: "arduino.disableIntelliSenseAutoGen", - DEFAULT_TIMESTAMP_FORMAT: "arduino.defaultTimestampFormat", ANALYZE_ON_OPEN: "arduino.analyzeOnOpen", ANALYZE_ON_SETTING_CHANGE: "arduino.analyzeOnSettingChange", }; @@ -35,10 +33,8 @@ export interface IVscodeSettings { disableTestingOpen: boolean; ignoreBoards: string[]; skipHeaderProvider: boolean; - defaultBaudRate: number; useArduinoCli: boolean; disableIntelliSenseAutoGen: boolean; - defaultTimestampFormat: string; analyzeOnOpen: boolean; analyzeOnSettingChange: boolean; updateAdditionalUrls(urls: string[]): void; @@ -119,10 +115,6 @@ export class VscodeSettings implements IVscodeSettings { this.setConfigValue(configKeys.IGNORE_BOARDS, value, true); } - public get defaultBaudRate(): number { - return this.getConfigValue(configKeys.DEFAULT_BAUD_RATE); - } - public get useArduinoCli(): boolean { return this.getConfigValue(configKeys.USE_ARDUINO_CLI); } @@ -139,10 +131,6 @@ export class VscodeSettings implements IVscodeSettings { return this.getConfigValue(configKeys.DISABLE_INTELLISENSE_AUTO_GEN); } - public get defaultTimestampFormat(): string { - return this.getConfigValue(configKeys.DEFAULT_TIMESTAMP_FORMAT); - } - public get analyzeOnOpen(): boolean { return this.getConfigValue(configKeys.ANALYZE_ON_OPEN); } diff --git a/src/common/constants.ts b/src/common/constants.ts index d3ed20b4..0589aa42 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -42,7 +42,6 @@ export const messages = { export const statusBarPriority = { PORT: 20, OPEN_PORT: 30, - BAUD_RATE: 40, TIMESTAMP_FORMAT: 50, BOARD: 60, ENDING: 70, diff --git a/src/extension.ts b/src/extension.ts index fafbd7a1..76515999 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -119,7 +119,7 @@ export async function activate(context: vscode.ExtensionContext) { } if (!SerialMonitor.getInstance().initialized) { - SerialMonitor.getInstance().initialize(); + SerialMonitor.getInstance().initialize(context); } const arduinoPath = arduinoContextModule.default.arduinoApp.settings.arduinoPath; @@ -148,7 +148,7 @@ export async function activate(context: vscode.ExtensionContext) { const registerNonArduinoCommand = (command: string, commandBody: (...args: any[]) => any, getUserData?: () => any): number => { return context.subscriptions.push(vscode.commands.registerCommand(command, async (...args: any[]) => { if (!SerialMonitor.getInstance().initialized) { - SerialMonitor.getInstance().initialize(); + SerialMonitor.getInstance().initialize(context); } await commandExecution(command, commandBody, args, getUserData); })); @@ -323,12 +323,10 @@ export async function activate(context: vscode.ExtensionContext) { // serial monitor commands const serialMonitor = SerialMonitor.getInstance(); context.subscriptions.push(serialMonitor); - registerNonArduinoCommand("arduino.selectSerialPort", () => serialMonitor.selectSerialPort(null, null)); + registerNonArduinoCommand("arduino.selectSerialPort", () => serialMonitor.selectSerialPort()); registerNonArduinoCommand("arduino.openSerialMonitor", () => serialMonitor.openSerialMonitor()); - registerNonArduinoCommand("arduino.changeBaudRate", () => serialMonitor.changeBaudRate()); registerNonArduinoCommand("arduino.changeTimestampFormat", () => serialMonitor.changeTimestampFormat()); - registerNonArduinoCommand("arduino.sendMessageToSerialPort", () => serialMonitor.sendMessageToSerialPort()); - registerNonArduinoCommand("arduino.closeSerialMonitor", (port, showWarning = true) => serialMonitor.closeSerialMonitor(port, showWarning)); + registerNonArduinoCommand("arduino.closeSerialMonitor", (port) => serialMonitor.closeSerialMonitor(port)); const completionProvider = new completionProviderModule.CompletionProvider(); context.subscriptions.push(vscode.languages.registerCompletionItemProvider(ARDUINO_MODE, completionProvider, "<", '"', ".")); @@ -344,7 +342,7 @@ export async function activate(context: vscode.ExtensionContext) { } if (!SerialMonitor.getInstance().initialized) { - SerialMonitor.getInstance().initialize(); + SerialMonitor.getInstance().initialize(context); } vscode.commands.executeCommand("setContext", "vscode-arduino:showExampleExplorer", true); })(); @@ -359,7 +357,7 @@ export async function activate(context: vscode.ExtensionContext) { await arduinoActivatorModule.default.activate(); } if (!SerialMonitor.getInstance().initialized) { - SerialMonitor.getInstance().initialize(); + SerialMonitor.getInstance().initialize(context); } vscode.commands.executeCommand("setContext", "vscode-arduino:showExampleExplorer", true); } @@ -453,14 +451,14 @@ export async function activate(context: vscode.ExtensionContext) { setTimeout(() => { // delay to detect usb - usbDetectorModule.UsbDetector.getInstance().initialize(context.extensionPath); + usbDetectorModule.UsbDetector.getInstance().initialize(context); usbDetectorModule.UsbDetector.getInstance().startListening(); }, 200); } export async function deactivate() { const monitor = SerialMonitor.getInstance(); - await monitor.closeSerialMonitor(null, false); + await monitor.closeSerialMonitor(null); usbDetectorModule.UsbDetector.getInstance().stopListening(); Logger.traceUserData("deactivate-extension"); } diff --git a/src/serialmonitor/outputBuffer.ts b/src/serialmonitor/outputBuffer.ts deleted file mode 100644 index c9099e98..00000000 --- a/src/serialmonitor/outputBuffer.ts +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -import { performance } from "perf_hooks"; -import * as vscode from "vscode"; - -export class BufferedOutputChannel implements vscode.Disposable { - private _buffer: string[]; - private _timer: NodeJS.Timer; - private _lastFlushTime: number; - - public constructor(private readonly outputCallback: (value: string) => void, private readonly flushIntervalMs: number) { - this._buffer = []; - this._timer = setInterval(() => this.tryFlush(), this.flushIntervalMs); - this._lastFlushTime = Number.NEGATIVE_INFINITY; - } - - public append(value: string) { - this.add(value); - } - - public appendLine(value: string) { - this.add(value + "\n"); - } - - public dispose() { - this.tryFlush(); - clearInterval(this._timer); - } - - private add(value: string) { - this._buffer.push(value); - this.tryFlush(); - } - - private tryFlush() { - const currentTime = performance.now(); - if (this._buffer.length > 0 && currentTime - this._lastFlushTime > this.flushIntervalMs) { - this.outputCallback(this._buffer.join("")); - this._lastFlushTime = currentTime; - this._buffer = []; - } - } -} diff --git a/src/serialmonitor/serialMonitor.ts b/src/serialmonitor/serialMonitor.ts index 9d1083ab..7967d90f 100644 --- a/src/serialmonitor/serialMonitor.ts +++ b/src/serialmonitor/serialMonitor.ts @@ -1,28 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. - +import { getSerialMonitorApi, LineEnding, Parity, Port, PortInformation, SerialMonitorApi, StopBits, Version } from "@microsoft/vscode-serial-monitor-api"; import * as vscode from "vscode"; -import ArduinoContext from "../arduinoContext"; import * as constants from "../common/constants"; import { DeviceContext } from "../deviceContext"; import * as Logger from "../logger/logger"; -import { BufferedOutputChannel } from "./outputBuffer"; -import { SerialPortCtrl } from "./serialportctrl"; - -export interface ISerialPortDetail { - port: string; - desc: string; - hwid: string; - vendorId: string; - productId: string; -} export class SerialMonitor implements vscode.Disposable { - - public static SERIAL_MONITOR: string = "Serial Monitor"; - - public static DEFAULT_BAUD_RATE: number = 115200; - public static DEFAULT_TIMESTAMP_FORMAT: string = ""; public static listBaudRates(): number[] { @@ -38,226 +22,145 @@ export class SerialMonitor implements vscode.Disposable { private static _serialMonitor: SerialMonitor = null; - private _currentPort: string; - - private _currentBaudRate: number; - - private _currentTimestampFormat: string; - - private _portsStatusBar: vscode.StatusBarItem; - - private _openPortStatusBar: vscode.StatusBarItem; + private serialMonitorApi: SerialMonitorApi | undefined; + private extensionContext: vscode.ExtensionContext; + private currentPort: string; + private activePort: Port | undefined; + private lastSelectedBaudRate: number = 115200; // Same default as Arduino. - private _baudRateStatusBar: vscode.StatusBarItem; + private openPortStatusBar: vscode.StatusBarItem; + private portsStatusBar: vscode.StatusBarItem; + private timestampFormatStatusBar: vscode.StatusBarItem; - private _timestampFormatStatusBar: vscode.StatusBarItem; + public async initialize(extensionContext: vscode.ExtensionContext) { + this.extensionContext = extensionContext; - private _serialPortCtrl: SerialPortCtrl = null; + this.portsStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.PORT); + this.portsStatusBar.command = "arduino.selectSerialPort"; + this.portsStatusBar.tooltip = "Select Serial Port"; + this.portsStatusBar.show(); - private _outputChannel: vscode.OutputChannel; + this.openPortStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.OPEN_PORT); + this.openPortStatusBar.command = "arduino.openSerialMonitor"; + this.openPortStatusBar.text = `$(plug)`; + this.openPortStatusBar.tooltip = "Open Serial Monitor"; + this.openPortStatusBar.show(); - private _bufferedOutputChannel: BufferedOutputChannel; - - public initialize() { - let defaultBaudRate; - if (ArduinoContext.arduinoApp && ArduinoContext.arduinoApp.settings && ArduinoContext.arduinoApp.settings.defaultBaudRate) { - defaultBaudRate = ArduinoContext.arduinoApp.settings.defaultBaudRate; - } else { - defaultBaudRate = SerialMonitor.DEFAULT_BAUD_RATE; - } - let defaultTimestampFormat; - if (ArduinoContext.arduinoApp && ArduinoContext.arduinoApp.settings && ArduinoContext.arduinoApp.settings.defaultTimestampFormat) { - defaultTimestampFormat = ArduinoContext.arduinoApp.settings.defaultTimestampFormat; - } else { - defaultTimestampFormat = SerialMonitor.DEFAULT_TIMESTAMP_FORMAT; - } - this._outputChannel = vscode.window.createOutputChannel(SerialMonitor.SERIAL_MONITOR); - this._bufferedOutputChannel = new BufferedOutputChannel(this._outputChannel.append, 300); - this._currentBaudRate = defaultBaudRate; - this._currentTimestampFormat = defaultTimestampFormat; - this._portsStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.PORT); - this._portsStatusBar.command = "arduino.selectSerialPort"; - this._portsStatusBar.tooltip = "Select Serial Port"; - this._portsStatusBar.show(); - - this._openPortStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.OPEN_PORT); - this._openPortStatusBar.command = "arduino.openSerialMonitor"; - this._openPortStatusBar.text = `$(plug)`; - this._openPortStatusBar.tooltip = "Open Serial Monitor"; - this._openPortStatusBar.show(); - - this._baudRateStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.BAUD_RATE); - this._baudRateStatusBar.command = "arduino.changeBaudRate"; - this._baudRateStatusBar.tooltip = "Baud Rate"; - this._baudRateStatusBar.text = defaultBaudRate.toString(); - - this._timestampFormatStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, + // This statusbar button will open the timestamp format setting in the serial monitor extension. + this.timestampFormatStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.TIMESTAMP_FORMAT); - this._timestampFormatStatusBar.command = "arduino.changeTimestampFormat"; - this._timestampFormatStatusBar.tooltip = `Timestamp Format: "${defaultTimestampFormat}"`; - this._timestampFormatStatusBar.text = `$(watch)`; + this.timestampFormatStatusBar.command = "arduino.changeTimestampFormat"; + this.timestampFormatStatusBar.tooltip = `Change timestamp format`; + this.timestampFormatStatusBar.text = `$(watch)`; + this.updatePortListStatus(); const dc = DeviceContext.getInstance(); dc.onChangePort(() => { this.updatePortListStatus(); }); - } - public get initialized(): boolean { - return !!this._outputChannel; + + this.serialMonitorApi = await getSerialMonitorApi(Version.latest, extensionContext); } - public dispose() { - if (this._serialPortCtrl && this._serialPortCtrl.isActive) { - return this._serialPortCtrl.stop(); - } - this._outputChannel.dispose(); - this._bufferedOutputChannel.dispose(); + public get initialized(): boolean { + return !!this.extensionContext; } - public async selectSerialPort(vid: string, pid: string) { - const lists = await SerialPortCtrl.list(); - if (!lists.length) { + public async selectSerialPort(): Promise { + const ports = await this.serialMonitorApi.listAvailablePorts(); + if (!ports.length) { vscode.window.showInformationMessage("No serial port is available."); return; } - if (vid && pid) { - const valueOfVid = parseInt(vid, 16); - const valueOfPid = parseInt(pid, 16); - const foundPort = lists.find((p) => { - // The pid and vid returned by SerialPortCtrl start with 0x prefix in Mac, but no 0x prefix in Win32. - // Should compare with decimal value to keep compatibility. - if (p.productId && p.vendorId) { - return parseInt(p.productId, 16) === valueOfPid && parseInt(p.vendorId, 16) === valueOfVid; - } - return false; - }); - if (foundPort && !(this._serialPortCtrl && this._serialPortCtrl.isActive)) { - this.updatePortListStatus(foundPort.port); - } - } else { - const chosen = await vscode.window.showQuickPick(lists.map((l: ISerialPortDetail): vscode.QuickPickItem => { - return { - description: l.desc, - label: l.port, - }; - }).sort((a, b): number => { - return a.label === b.label ? 0 : (a.label > b.label ? 1 : -1); - }), { placeHolder: "Select a serial port" }); - if (chosen && chosen.label) { - this.updatePortListStatus(chosen.label); - } - } - } + const chosen = await vscode.window.showQuickPick(ports.map((l: PortInformation): vscode.QuickPickItem => { + return { + description: l.friendlyName, + label: l.portName, + }; + }).sort((a, b): number => { + return a.label === b.label ? 0 : (a.label > b.label ? 1 : -1); + }), { placeHolder: "Select a serial port" }); - public async openSerialMonitor() { - if (!this._currentPort) { - const ans = await vscode.window.showInformationMessage("No serial port was selected, please select a serial port first", "Yes", "No"); - if (ans === "Yes") { - await this.selectSerialPort(null, null); - } - if (!this._currentPort) { - return; - } + if (chosen && chosen.label) { + this.currentPort = chosen.label; + this.updatePortListStatus(this.currentPort); + return chosen.label; } - if (this._serialPortCtrl) { - if (this._currentPort !== this._serialPortCtrl.currentPort) { - await this._serialPortCtrl.changePort(this._currentPort); - } else if (this._serialPortCtrl.isActive) { - vscode.window.showWarningMessage(`Serial monitor is already opened for ${this._currentPort}`); - return; - } - } else { - this._serialPortCtrl = new SerialPortCtrl( - this._currentPort, - this._currentBaudRate, - this._currentTimestampFormat, - this._bufferedOutputChannel, - this._outputChannel.show); - } - - if (!this._serialPortCtrl.currentPort) { - Logger.traceError("openSerialMonitorError", new Error(`Failed to open serial port ${this._currentPort}`)); - return; - } - - try { - await this._serialPortCtrl.open(); - this.updatePortStatus(true); - } catch (error) { - Logger.notifyUserWarning("openSerialMonitorError", error, - `Failed to open serial port ${this._currentPort} due to error: + ${error.toString()}`); - } + return undefined; } - public async sendMessageToSerialPort() { - if (this._serialPortCtrl && this._serialPortCtrl.isActive) { - const text = await vscode.window.showInputBox(); - try { - await this._serialPortCtrl.sendMessage(text); - } catch (error) { - Logger.notifyUserWarning("sendMessageToSerialPortError", error, constants.messages.FAILED_SEND_SERIALPORT); - } - } else { - Logger.notifyUserWarning("sendMessageToSerialPortError", new Error(constants.messages.SEND_BEFORE_OPEN_SERIALPORT)); - } + public async changeTimestampFormat(): Promise { + await vscode.commands.executeCommand("workbench.action.openSettings", "vscode-serial-monitor.timestampFormat"); } - public async changeBaudRate() { + public async selectBaudRate(): Promise { const rates = SerialMonitor.listBaudRates(); const chosen = await vscode.window.showQuickPick(rates.map((rate) => rate.toString())); if (!chosen) { - Logger.warn("No baud rate selected, keeping previous baud rate."); - return; + Logger.warn("No baud rate selected, keeping previous baud rate"); + return undefined; } if (!parseInt(chosen, 10)) { - Logger.warn("Invalid baud rate, keeping previous baud rate.", { value: chosen }); - return; - } - if (!this._serialPortCtrl) { - Logger.warn("Serial Monitor has not been started."); - return; + Logger.warn("Serial Monitor has not been started"); + return undefined; } const selectedRate: number = parseInt(chosen, 10); - await this._serialPortCtrl.changeBaudRate(selectedRate); - this._currentBaudRate = selectedRate; - this._baudRateStatusBar.text = chosen; + this.lastSelectedBaudRate = selectedRate; + return selectedRate; } - public async changeTimestampFormat() { - const timestampFormat = await vscode.window.showInputBox(); - if (!timestampFormat) { - Logger.warn("No timestamp format inputted, keeping previous timestamp format."); - return; - } - if (timestampFormat.indexOf("%") < 0) { - Logger.warn("Invalid timestamp format, keeping previous timestamp format.", { value: timestampFormat }); - return; + public async openSerialMonitor(restore: boolean = false): Promise { + if (!this.currentPort) { + const ans = await vscode.window.showInformationMessage("No serial port was selected, please select a serial port first", "Select", "Cancel"); + if (ans === "Select") { + if (await this.selectSerialPort() === undefined) { + return; + } + } + if (!this.currentPort) { + return; + } } - if (!this._serialPortCtrl) { - Logger.warn("Serial Monitor has not been started."); - return; + + // if we're restoring, we want to use the most recent baud rate selected, rather than popping UI. + const baudRate = restore ? this.lastSelectedBaudRate : await this.selectBaudRate() ?? this.lastSelectedBaudRate; + + try { + this.activePort = await this.serialMonitorApi.startMonitoringPort({ + port: this.currentPort, + baudRate, + lineEnding: LineEnding.None, + dataBits: 8, + stopBits: StopBits.One, + parity: Parity.None, + }); + this.activePort.onClosed(() => { + this.updatePortStatus(false); + this.activePort = undefined; + }); + this.updatePortStatus(true); + } catch (err) { + Logger.warn("Serial Monitor failed to open"); + vscode.window.showErrorMessage(`Error opening serial port: ${err.toString()}`); } - await this._serialPortCtrl.changeTimestampFormat(timestampFormat); - this._currentTimestampFormat = timestampFormat; - this._timestampFormatStatusBar.tooltip = `Timestamp Format: "${timestampFormat}"`; } - public async closeSerialMonitor(port: string, showWarning: boolean = true): Promise { - if (this._serialPortCtrl) { - if (port && port !== this._serialPortCtrl.currentPort) { - // Port is not opened - return false; - } - const result = await this._serialPortCtrl.stop(); - this.updatePortStatus(false); - return result; - } else if (!port && showWarning) { - Logger.notifyUserWarning("closeSerialMonitorError", new Error(constants.messages.SERIAL_PORT_NOT_STARTED)); - return false; + public async closeSerialMonitor(port?: string): Promise { + const portToClose = port ?? this.currentPort; + let closed = false; + if (portToClose) { + closed = await this.serialMonitorApi.stopMonitoringPort(port ?? this.currentPort); } + this.updatePortStatus(false); + + return closed; + } + + public dispose() { + this.serialMonitorApi.dispose(); } private updatePortListStatus(port?: string) { @@ -265,29 +168,26 @@ export class SerialMonitor implements vscode.Disposable { if (port) { dc.port = port; } - this._currentPort = dc.port; + this.currentPort = dc.port; if (dc.port) { - this._portsStatusBar.text = dc.port; + this.portsStatusBar.text = dc.port; } else { - this._portsStatusBar.text = ""; } } private updatePortStatus(isOpened: boolean) { if (isOpened) { - this._openPortStatusBar.command = "arduino.closeSerialMonitor"; - this._openPortStatusBar.text = `$(x)`; - this._openPortStatusBar.tooltip = "Close Serial Monitor"; - this._baudRateStatusBar.show(); - this._timestampFormatStatusBar.show(); + this.openPortStatusBar.command = "arduino.closeSerialMonitor"; + this.openPortStatusBar.text = `$(x)`; + this.openPortStatusBar.tooltip = "Close Serial Monitor"; + this.timestampFormatStatusBar.show(); } else { - this._openPortStatusBar.command = "arduino.openSerialMonitor"; - this._openPortStatusBar.text = `$(plug)`; - this._openPortStatusBar.tooltip = "Open Serial Monitor"; - this._baudRateStatusBar.hide(); - this._timestampFormatStatusBar.hide(); + this.openPortStatusBar.command = "arduino.openSerialMonitor"; + this.openPortStatusBar.text = `$(plug)`; + this.openPortStatusBar.tooltip = "Open Serial Monitor"; + this.timestampFormatStatusBar.hide(); } - } } diff --git a/src/serialmonitor/serialportctrl.ts b/src/serialmonitor/serialportctrl.ts deleted file mode 100644 index d7360e51..00000000 --- a/src/serialmonitor/serialportctrl.ts +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -import * as os from "os"; -import { SerialPort } from "serialport"; -import * as strftime from "strftime"; -import { BufferedOutputChannel } from "./outputBuffer"; - -interface ISerialPortDetail { - port: string; - desc: string; - vendorId: string; - productId: string; -} - -export class SerialPortCtrl { - -/** - * Check which external serial devices are connected. - * - * @returns An array of ISerialPortDetail from external serial devices. - * - */ - public static async list(): Promise { - return (await SerialPort.list()).map((port) => { - return { - port: port.path, - desc: (port as any).friendlyName ?? port.manufacturer, - vendorId: port.vendorId, - productId: port.productId, - }; - }); - } - - private _port?: SerialPort; - private _currentPort: string; - private _currentBaudRate: number; - private _currentTimestampFormat: string; - - public constructor( - port: string, - baudRate: number, - timestampFormat: string, - private _bufferedOutputChannel: BufferedOutputChannel, - private showOutputChannel: (preserveFocus?: boolean) => void) { - this._currentBaudRate = baudRate; - this._currentPort = port; - this._currentTimestampFormat = timestampFormat; - } - - public get isActive(): boolean { - return this._port?.isOpen ?? false; - } - - public get currentPort(): string { - return this._currentPort; - } - - public async open(): Promise { - this._bufferedOutputChannel.appendLine(`[Starting] Opening the serial port - ${this._currentPort}`); - this.showOutputChannel(); - - if (this.isActive) { await this.close(); } - - await new Promise((resolve, reject) => { - this._port = new SerialPort( - { autoOpen: false, path: this._currentPort, baudRate: this._currentBaudRate }, - (err) => { - if (err) { reject(err); } - }); - this._port.open((err) => { - if (err) { - reject(err); - } else { - // These pins are tied to boot and reset on some devices like the - // ESP32. We need to pull them high to avoid unexpected behavior when - // opening the serial monitor. - this._port.set({ dtr: true, cts: true, rts: true }, (err2) => { - if (err2) { - reject(err2); - } else { - resolve(); - } - }); - } - }); - }); - - let lastDataEndedWithNewline = true; - this._port.on("data", (data) => { - const text: string = data.toString("utf8"); - if (this._currentTimestampFormat) { - const timestamp = strftime(this._currentTimestampFormat); - this._bufferedOutputChannel.append( - // Timestamps should only be added at the beginning of a line. - // Look for newlines except at the very end of the string. - (lastDataEndedWithNewline ? timestamp : "") + - text.replace(/\n(?!$)/g, "\n" + timestamp), - ); - lastDataEndedWithNewline = text.endsWith("\n"); - } else { - this._bufferedOutputChannel.append(text); - } - }); - } - - public sendMessage(text: string): Promise { - return new Promise((resolve, reject) => { - if (!text || !this.isActive) { - resolve(); - return; - } - this._port.write(text + "\n", (error) => { - if (!error) { - resolve(); - } else { - return reject(error); - } - }); - }); - } - - public async changePort(newPort: string): Promise { - if (newPort === this._currentPort) { return; } - this._currentPort = newPort; - if (!this.isActive) { return; } - await this.close(); - } - - public async stop(): Promise { - if (!this.isActive) { return false; } - - await this.close(); - if (this._bufferedOutputChannel) { - this._bufferedOutputChannel.appendLine(`[Done] Closed the serial port ${os.EOL}`); - } - - return true; - } - - public async changeBaudRate(newRate: number): Promise { - this._currentBaudRate = newRate; - if (!this.isActive) { return; } - await this.stop(); - await this.open(); - } - - public async changeTimestampFormat(newTimestampFormat: string): Promise { - this._currentTimestampFormat = newTimestampFormat; - } - - private close(): Promise { - return new Promise((resolve, reject) => { - this._port.close((err) => { - if (err) { - reject(err); - } else { - this._port = undefined; - resolve(); - } - }) - }); - } -} diff --git a/src/serialmonitor/usbDetector.ts b/src/serialmonitor/usbDetector.ts index 9e1ec165..89d59ea6 100644 --- a/src/serialmonitor/usbDetector.ts +++ b/src/serialmonitor/usbDetector.ts @@ -35,11 +35,14 @@ export class UsbDetector { private _extensionRoot = null; + private _extensionContext = null; + private constructor() { } - public initialize(extensionRoot: string) { - this._extensionRoot = extensionRoot; + public initialize(extensionContext: vscode.ExtensionContext) { + this._extensionRoot = extensionContext.extensionPath; + this._extensionContext = extensionContext; } public async startListening() { @@ -74,7 +77,7 @@ export class UsbDetector { await ArduinoActivator.activate(); } if (!SerialMonitor.getInstance().initialized) { - SerialMonitor.getInstance().initialize(); + SerialMonitor.getInstance().initialize(this._extensionContext); } // TODO EW: this is board manager code which should be moved into board manager @@ -128,8 +131,6 @@ export class UsbDetector { } }); } else { - const monitor = SerialMonitor.getInstance(); - monitor.selectSerialPort(deviceDescriptor.vid, deviceDescriptor.pid); this.showReadMeAndExample(deviceDescriptor.readme); } } else { @@ -163,8 +164,6 @@ export class UsbDetector { private switchBoard(bd: IBoard, deviceDescriptor, showReadMe: boolean = true) { ArduinoContext.boardManager.doChangeBoardType(bd); - const monitor = SerialMonitor.getInstance(); - monitor.selectSerialPort(deviceDescriptor.vid, deviceDescriptor.pid); if (showReadMe) { this.showReadMeAndExample(deviceDescriptor.readme); } diff --git a/test/extension.test.ts b/test/extension.test.ts index 4ffee724..61753f64 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -47,9 +47,7 @@ suite("Arduino: Extension Tests", () => { "arduino.initialize", "arduino.selectSerialPort", "arduino.openSerialMonitor", - "arduino.changeBaudRate", "arduino.changeTimestampFormat", - "arduino.sendMessageToSerialPort", "arduino.closeSerialMonitor", "arduino.reloadExample", "arduino.showExampleExplorer", diff --git a/webpack.config.js b/webpack.config.js index b70989d0..efa354bd 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -11,10 +11,9 @@ function getEntry() { }); const mod = JSON.parse(npmListRes); const unbundledModule = ['impor', 'uuid', - // usb-native modules can not be bundled - // added debug, ms, node-gyp-build, and node-addon-api as a workaround a break in packaging + // usb-native modules can not be bundled // that caused the extension to not work. - 'usb-detection', '@serialport', 'bindings', 'serialport', 'debug', 'ms', 'node-gyp-build', 'node-addon-api']; + 'usb-detection', 'bindings']; for (const mod of unbundledModule) { const p = 'node_modules/' + mod; @@ -64,7 +63,6 @@ const config = { }, externals: { vscode: "commonjs vscode", - serialport: "serialport" }, resolve: { extensions: ['.js', '.json']