From 49e314820624690143baa54c1653e46c8e6899c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Wed, 21 Feb 2018 20:18:17 +0300 Subject: [PATCH 01/35] add simple serial plotter --- package-lock.json | 980 +++++++++++++++++- package.json | 5 +- src/arduino/arduinoContentProvider.ts | 11 + src/arduino/localWebServer.ts | 10 + src/common/constants.ts | 2 + src/extension.ts | 3 + src/serialmonitor/serialMonitor.ts | 25 + src/serialmonitor/serialPlotter.ts | 83 ++ src/serialmonitor/serialportctrl.ts | 19 +- src/views/app/WebSocketMiddleware.ts | 24 + src/views/app/components/SerialPlotter.tsx | 106 ++ src/views/app/index.tsx | 7 +- src/views/app/reducers/index.ts | 2 + .../app/reducers/serialPlotterReducer.ts | 51 + src/views/package-lock.json | 946 ++++++++++++++++- src/views/package.json | 12 +- 16 files changed, 2254 insertions(+), 32 deletions(-) create mode 100644 src/serialmonitor/serialPlotter.ts create mode 100644 src/views/app/WebSocketMiddleware.ts create mode 100644 src/views/app/components/SerialPlotter.tsx create mode 100644 src/views/app/reducers/serialPlotterReducer.ts diff --git a/package-lock.json b/package-lock.json index a0825eca..d7319c22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,12 @@ "through2": "2.0.3" } }, + "@types/events": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-1.1.0.tgz", + "integrity": "sha512-y3bR98mzYOo0pAZuiLari+cQyiKk3UXRuT45h1RjhfeCzqkjaVsfZJNaxdgtk7/3tzOm1ozLTqEqMP3VbI48jw==", + "dev": true + }, "@types/mocha": { "version": "2.2.41", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.41.tgz", @@ -45,6 +51,16 @@ "integrity": "sha1-kdZxDlNtNFucmwF8V0z2qNpkxRg=", "dev": true }, + "@types/ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-4.0.1.tgz", + "integrity": "sha512-J56Wn8j7ovzmlrkUSPXnVRH+YXUCGoVokiB49QIjz+yq0234guOrBvF/HHrqrJjnY4p5oq+q6xAxT/7An6SeWQ==", + "dev": true, + "requires": { + "@types/events": "1.1.0", + "@types/node": "6.0.85" + } + }, "accepts": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", @@ -325,6 +341,11 @@ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", "dev": true }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -738,6 +759,7 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", + "fsevents": "1.1.3", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -2201,6 +2223,910 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", + "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.8.0", + "node-pre-gyp": "0.6.39" + }, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.9" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true, + "dev": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "1.1.1", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true, + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "mime-db": { + "version": "1.27.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.39", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "1.0.2", + "hawk": "3.1.3", + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.0", + "rc": "1.2.1", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "tar-pack": "3.4.0" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.0", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true, + "dev": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "dev": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.1", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + } + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.8", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.2.9", + "rimraf": "2.6.1", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "uuid": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "extsprintf": "1.0.2" + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + } + } + }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", @@ -4522,6 +5448,11 @@ "lodash.escape": "3.2.0" } }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", @@ -4812,6 +5743,13 @@ "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", "dev": true }, + "nan": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", + "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=", + "dev": true, + "optional": true + }, "natives": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz", @@ -5840,8 +6778,7 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "semver": { "version": "5.4.1", @@ -6166,15 +7103,6 @@ "integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8=", "dev": true }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -6186,6 +7114,15 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", @@ -6593,6 +7530,11 @@ "dev": true, "optional": true }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", @@ -7194,9 +8136,9 @@ "integrity": "sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs=" }, "winston": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/winston/-/winston-2.3.1.tgz", - "integrity": "sha1-C0hCDZeMAYBM8CMLZIhhWYIloRk=", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.0.tgz", + "integrity": "sha1-gIBQuT1SZh7Z+2wms/DIJnCLCu4=", "requires": { "async": "1.0.0", "colors": "1.0.3", @@ -7247,6 +8189,16 @@ "slide": "1.1.6" } }, + "ws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.0.0.tgz", + "integrity": "sha512-QYslsH44bH8O7/W2815u5DpnCpXWpEK44FmaHffNwgJI4JMaSZONgPBTOfrxJ29mXKbXak+LsJ2uAkDTYq2ptQ==", + "requires": { + "async-limiter": "1.0.0", + "safe-buffer": "5.1.1", + "ultron": "1.1.1" + } + }, "xdg-basedir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", diff --git a/package.json b/package.json index 0a1eca21..548377f1 100644 --- a/package.json +++ b/package.json @@ -486,6 +486,7 @@ "@types/mocha": "^2.2.32", "@types/node": "^6.0.40", "@types/winreg": "^1.2.30", + "@types/ws": "^4.0.1", "del": "^2.2.2", "eslint": "^3.19.0", "eslint-config-standard": "^10.2.1", @@ -514,10 +515,12 @@ "express": "^4.14.1", "glob": "^7.1.1", "iconv-lite": "^0.4.18", + "lodash.throttle": "^4.1.1", "properties": "^1.2.1", "uuid": "^3.0.1", "vscode-extension-telemetry": "0.0.6", "winreg": "^1.2.3", - "winston": "^2.3.1" + "winston": "^2.3.1", + "ws": "^4.0.0" } } diff --git a/src/arduino/arduinoContentProvider.ts b/src/arduino/arduinoContentProvider.ts index d21beb52..5111dc79 100644 --- a/src/arduino/arduinoContentProvider.ts +++ b/src/arduino/arduinoContentProvider.ts @@ -4,9 +4,11 @@ import * as path from "path"; import * as Uuid from "uuid/v4"; import * as vscode from "vscode"; +import * as WebSocket from "ws"; import ArduinoActivator from "../arduinoActivator"; import ArduinoContext from "../arduinoContext"; import * as Constants from "../common/constants"; +import { SERIAL_PLOTTER_URI } from "../common/constants"; import * as JSONHelper from "../common/cycle"; import * as Logger from "../logger/logger"; import LocalWebServer from "./localWebServer"; @@ -50,9 +52,16 @@ export class ArduinoContentProvider implements vscode.TextDocumentContentProvide this.addHandlerWithLogger("load-examples", "/api/examples", async (req, res) => await this.getExamples(req, res)); this.addHandlerWithLogger("open-example", "/api/openexample", (req, res) => this.openExample(req, res), true); + // Serial Plotter + this.addHandlerWithLogger("show-serialplotter", "/serialplotter", (req, res) => this.getHtmlView(req, res)); + this._webserver.start(); } + public getWebSocketServer(): WebSocket.Server { + return this._webserver.getWebSocketServer(); + } + public async provideTextDocumentContent(uri: vscode.Uri): Promise { if (!ArduinoContext.initialized) { await ArduinoActivator.activate(); @@ -66,6 +75,8 @@ export class ArduinoContentProvider implements vscode.TextDocumentContentProvide type = "boardConfig"; } else if (uri.toString() === Constants.EXAMPLES_URI.toString()) { type = "examples"; + } else if (uri.toString() === Constants.SERIAL_PLOTTER_URI.toString()) { + type = "serialplotter"; } const timeNow = new Date().getTime(); diff --git a/src/arduino/localWebServer.ts b/src/arduino/localWebServer.ts index 3d1f316c..12bd6436 100644 --- a/src/arduino/localWebServer.ts +++ b/src/arduino/localWebServer.ts @@ -5,16 +5,19 @@ import * as bodyParser from "body-parser"; import * as express from "express"; import * as http from "http"; import * as path from "path"; +import * as WebSocket from "ws"; export default class LocalWebServer { private app = express(); private server; + private wss; private _serverPort: string; constructor(private _extensionPath: string) { this.app.use("/", express.static(path.join(this._extensionPath, "./out/views"))); this.app.use(bodyParser.json()); this.server = http.createServer(this.app); + this.wss = new WebSocket.Server({ server: this.server }); } public getServerUrl(): string { @@ -23,6 +26,9 @@ export default class LocalWebServer { public getEndpointUri(type: string): string { return `http://localhost:${this._serverPort}/${type}`; } + public getWebSocketUri(): string { + return `ws://localhost:${this._serverPort}`; + } public addHandler(url: string, handler: (req, res) => void): void { this.app.get(url, handler); @@ -32,6 +38,10 @@ export default class LocalWebServer { this.app.post(url, handler); } + public getWebSocketServer(): WebSocket.Server { + return this.wss; + } + public start(): void { const port = this.server.listen(0).address().port; // tslint:disable-next-line diff --git a/src/common/constants.ts b/src/common/constants.ts index 825cd332..8eaabdfb 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -18,6 +18,7 @@ export const BOARD_MANAGER_URI = vscode.Uri.parse("arduino-manager://arduino/ard export const LIBRARY_MANAGER_URI = vscode.Uri.parse("arduino-manager://arduino/arduino-librariesmanager"); export const BOARD_CONFIG_URI = vscode.Uri.parse("arduino-manager://arduino/arduino-config"); export const EXAMPLES_URI = vscode.Uri.parse("arduino-manager://arduino/arduino-examples"); +export const SERIAL_PLOTTER_URI = vscode.Uri.parse("arduino-manager://arduino/arduino-serialplotter"); export const messages = { ARDUINO_FILE_ERROR: "The arduino.json file format is not correct.", @@ -32,5 +33,6 @@ export const statusBarPriority = { PORT: 2, OPEN_PORT: 3, BAUD_RATE: 4, + OPEN_SERIAL_PLOTTER: 5, BOARD: 6, }; diff --git a/src/extension.ts b/src/extension.ts index c0df24ee..975848be 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -167,8 +167,11 @@ export async function activate(context: vscode.ExtensionContext) { // serial monitor commands const serialMonitor = SerialMonitor.getInstance(); context.subscriptions.push(serialMonitor); + serialMonitor.serialPlotter.setWebSocketServer(arduinoManagerProvider.getWebSocketServer()); + registerNonArduinoCommand("arduino.selectSerialPort", () => serialMonitor.selectSerialPort(null, null)); registerNonArduinoCommand("arduino.openSerialMonitor", () => serialMonitor.openSerialMonitor()); + registerNonArduinoCommand("arduino.openSerialPlotter", () => serialMonitor.openSerialPlotter()); registerNonArduinoCommand("arduino.changeBaudRate", () => serialMonitor.changeBaudRate()); registerNonArduinoCommand("arduino.sendMessageToSerialPort", () => serialMonitor.sendMessageToSerialPort()); registerNonArduinoCommand("arduino.closeSerialMonitor", (port) => serialMonitor.closeSerialMonitor(port)); diff --git a/src/serialmonitor/serialMonitor.ts b/src/serialmonitor/serialMonitor.ts index ea17f771..4711e9d4 100644 --- a/src/serialmonitor/serialMonitor.ts +++ b/src/serialmonitor/serialMonitor.ts @@ -5,6 +5,7 @@ import * as vscode from "vscode"; import * as constants from "../common/constants"; import { DeviceContext } from "../deviceContext"; import * as Logger from "../logger/logger"; +import { SerialPlotter } from "./serialPlotter"; import { SerialPortCtrl } from "./serialportctrl"; export interface ISerialPortDetail { @@ -33,6 +34,8 @@ export class SerialMonitor implements vscode.Disposable { private static _serialMonitor: SerialMonitor = null; + private _serialPlotter: SerialPlotter = null; + private _currentPort: string; private _currentBaudRate: number; @@ -43,11 +46,15 @@ export class SerialMonitor implements vscode.Disposable { private _baudRateStatusBar: vscode.StatusBarItem; + private _openPlotterStatusBar: vscode.StatusBarItem; + private _serialPortCtrl: SerialPortCtrl = null; private _outputChannel: vscode.OutputChannel; private constructor() { + this._serialPlotter = new SerialPlotter(); + const dc = DeviceContext.getInstance(); dc.onDidChange(() => { if (dc.port) { @@ -77,12 +84,23 @@ export class SerialMonitor implements vscode.Disposable { this._baudRateStatusBar.command = "arduino.changeBaudRate"; this._baudRateStatusBar.tooltip = "Baud Rate"; this._baudRateStatusBar.text = SerialMonitor.DEFAULT_BAUD_RATE.toString(); + + this._openPlotterStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.OPEN_SERIAL_PLOTTER); + this._openPlotterStatusBar.command = "arduino.openSerialPlotter"; + this._openPlotterStatusBar.tooltip = "Open Serial Plotter"; + this._openPlotterStatusBar.text = "Plotter"; + this._openPlotterStatusBar.show(); + this.updatePortListStatus(null); } public get initialized(): boolean { return !!this._outputChannel; } + public get serialPlotter() { + return this._serialPlotter; + } + public dispose() { if (this._serialPortCtrl && this._serialPortCtrl.isActive) { return this._serialPortCtrl.stop(); @@ -161,6 +179,13 @@ export class SerialMonitor implements vscode.Disposable { } } + public async openSerialPlotter() { + // TODO: check if monitor active + + this._serialPlotter.setSerialPortCtrl(this._serialPortCtrl); + this._serialPlotter.open(); + } + public async sendMessageToSerialPort() { if (this._serialPortCtrl && this._serialPortCtrl.isActive) { const text = await vscode.window.showInputBox(); diff --git a/src/serialmonitor/serialPlotter.ts b/src/serialmonitor/serialPlotter.ts new file mode 100644 index 00000000..1c27a1a8 --- /dev/null +++ b/src/serialmonitor/serialPlotter.ts @@ -0,0 +1,83 @@ +import * as throttle from "lodash.throttle"; +import * as vscode from "vscode"; +import * as WebSocket from "ws"; + +import { SERIAL_PLOTTER_URI } from "../common/constants"; +import { SerialPortCtrl } from "./serialportctrl"; + +export class SerialPlotter implements vscode.Disposable { + private _wss: WebSocket.Server; + private _throttling: number = 100; + private sendCurrentStateThrottled; + + private _currentState: { + time?: number, + [field: string]: number, + }; + + constructor() { + this.setThrottling(this._throttling); + } + + public open() { + vscode.commands.executeCommand("vscode.previewHtml", SERIAL_PLOTTER_URI, vscode.ViewColumn.Two, "Serial Plotter"); + } + + public dispose() {} + + public setWebSocketServer(wss: WebSocket.Server) { + this._wss = wss; + } + + public setSerialPortCtrl(serialPortCtrl: SerialPortCtrl) { + serialPortCtrl.onData(this.handleSerialData.bind(this)); + } + + public setThrottling(throttling: number): void { + this._throttling = throttling; + this.sendCurrentStateThrottled = throttle(this.sendCurrentState, this._throttling, { leading: false }); + } + + private sendCurrentState() { + if (!this._wss) { + return; + } + + this._wss.clients.forEach((client) => { + if (client.readyState === WebSocket.OPEN) { + client.send(JSON.stringify(this._currentState)); + } + }); + + this._currentState = undefined; + } + + private handleSerialData(line: string): void { + if (line.length === 0) { + return; + } + + if (line.indexOf("PLOT") === -1) { + return; + } + + const startIdx = line.indexOf("["); + const timeDelimeterIdx = line.indexOf(";"); + const endIdx = line.indexOf("]"); + const equalityIdx = line.indexOf("="); + + const timeStr = line.slice(startIdx + 1, timeDelimeterIdx); + const time = parseInt(timeStr, 10); + const field = line.slice(timeDelimeterIdx + 1, equalityIdx); + const valueStr = line.slice(equalityIdx + 1, endIdx); + const value = parseFloat(valueStr); + + this._currentState = { + ...this._currentState, + [field]: value, + time, + }; + + this.sendCurrentStateThrottled(); + } +} diff --git a/src/serialmonitor/serialportctrl.ts b/src/serialmonitor/serialportctrl.ts index c8c9abaa..e04c3fe8 100644 --- a/src/serialmonitor/serialportctrl.ts +++ b/src/serialmonitor/serialportctrl.ts @@ -3,6 +3,7 @@ import * as os from "os"; import { OutputChannel, QuickPickItem, StatusBarAlignment, StatusBarItem, window } from "vscode"; +import * as vscode from 'vscode'; interface ISerialPortDetail { comName: string; @@ -36,10 +37,12 @@ export class SerialPortCtrl { private _currentPort: string; private _currentBaudRate: number; private _currentSerialPort = null; + private _dataEmitter: vscode.EventEmitter; public constructor(port: string, baudRate: number, private _outputChannel: OutputChannel) { this._currentBaudRate = baudRate; this._currentPort = port; + this._dataEmitter = new vscode.EventEmitter(); } public get isActive(): boolean { @@ -50,6 +53,10 @@ export class SerialPortCtrl { return this._currentPort; } + public onData(listener: (string) => {}): vscode.Disposable { + return this._dataEmitter.event(listener); + } + public open(): Promise { this._outputChannel.appendLine(`[Starting] Opening the serial port - ${this._currentPort}`); return new Promise((resolve, reject) => { @@ -66,7 +73,10 @@ export class SerialPortCtrl { }); }); } else { - this._currentSerialPort = new SerialPortCtrl.serialport(this._currentPort, { baudRate: this._currentBaudRate }); + this._currentSerialPort = new SerialPortCtrl.serialport(this._currentPort, { + baudRate: this._currentBaudRate, + parser: SerialPortCtrl.serialport.parsers.readline(/\r?\n/, 'utf8'), + }); this._outputChannel.show(); this._currentSerialPort.on("open", () => { this._currentSerialPort.write("TestingOpen", (err) => { @@ -81,12 +91,13 @@ export class SerialPortCtrl { }); }); - this._currentSerialPort.on("data", (_event) => { - this._outputChannel.append(_event.toString()); + this._currentSerialPort.on("data", (line) => { + this._outputChannel.appendLine(line); + this._dataEmitter.fire(line); }); this._currentSerialPort.on("error", (_error) => { - this._outputChannel.appendLine("[Error]" + _error.toString()); + this._outputChannel.appendLine("[Error]" + _error.toString()); }); } }); diff --git a/src/views/app/WebSocketMiddleware.ts b/src/views/app/WebSocketMiddleware.ts new file mode 100644 index 00000000..f019a8d3 --- /dev/null +++ b/src/views/app/WebSocketMiddleware.ts @@ -0,0 +1,24 @@ +import { Action, Dispatch, Middleware, MiddlewareAPI } from "redux"; + +export enum ActionTypes { + DATA_RECEIVED, +} + +export function createSocketMiddleware(): Middleware { + const ws = new WebSocket(`ws://${window.location.host}`); + + return (store: MiddlewareAPI) => { + ws.onmessage = (e: MessageEvent) => { + store.dispatch({ + type: ActionTypes.DATA_RECEIVED, + payload: JSON.parse(e.data), + }); + }; + + return (next: Dispatch) => (action: A) => { + return next(action); + } + } +} + + diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx new file mode 100644 index 00000000..820a1679 --- /dev/null +++ b/src/views/app/components/SerialPlotter.tsx @@ -0,0 +1,106 @@ +import * as React from "react"; +import { Button, Checkbox, DropdownButton, MenuItem } from "react-bootstrap"; +import * as ReactList from "react-list"; +import { connect } from "react-redux"; +import SearchInput, { createFilter } from "react-search-input"; +import * as actions from "../actions"; +import { versionCompare } from "../utils/util"; +import LibraryItemView from "./LibraryItemView"; +import { + HighchartsChart, Chart, withHighcharts, XAxis, YAxis, Title, Legend, LineSeries, Tooltip + } from "react-jsx-highcharts"; +import * as Highcharts from "highcharts"; + +interface ISerialPlotterProps extends React.Props { + plotData: { + [field: string]: number[][] + }; +} + +interface ISerialPlotterState extends React.Props {} + +const mapStateToProps = store => { + return { + plotData: store.serialPlotterStore.data, + }; +}; + +const mapDispatchToProps = dispatch => { + return {}; +}; + +class SerialPlotter extends React.Component { + private fieldColorMap: { + [field: string]: string, + } = {}; + + constructor(props) { + super(props); + } + + public render() { + const lines = Object.keys(this.props.plotData).map((field) => ( + + )); + + const plotOptions = { + series: { + marker: { + enabled: false, + } + } + }; + + return ( +
+
+ + + Serial Plotter + + + Legend + + + + + + Time + + + + Value + {...lines} + + +
+
+ ); + } + + private getColorForField(field: string) { + if (!this.fieldColorMap[field]) { + this.fieldColorMap[field] = getRandomColor(); + } + + const fieldColor = this.fieldColorMap[field]; + return fieldColor; + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(withHighcharts(SerialPlotter, Highcharts)); + + +function getRandomColor() { + const letters = "0123456789ABCDEF"; + let color = "#"; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; + } diff --git a/src/views/app/index.tsx b/src/views/app/index.tsx index e2fb3c8b..0a136d21 100644 --- a/src/views/app/index.tsx +++ b/src/views/app/index.tsx @@ -10,9 +10,10 @@ import BoardConfig from "./components/BoardConfig"; import BoardManager from "./components/BoardManager"; import ExampleTreeView from "./components/ExampleTreeView"; import LibraryManager from "./components/LibraryManager"; +import SerialPlotter from "./components/SerialPlotter"; import reducer from "./reducers"; - import "./styles"; +import { createSocketMiddleware } from "./WebSocketMiddleware"; class App extends React.Component<{}, {}> { public render() { @@ -24,7 +25,8 @@ class App extends React.Component<{}, {}> { } } -const createStoreWithMiddleware = applyMiddleware()(createStore); +const webSocketMiddleware = createSocketMiddleware(); +const createStoreWithMiddleware = applyMiddleware(webSocketMiddleware)(createStore); const store = createStoreWithMiddleware(reducer); ReactDOM.render( @@ -35,6 +37,7 @@ ReactDOM.render( + , diff --git a/src/views/app/reducers/index.ts b/src/views/app/reducers/index.ts index f9af3f9a..2b85c861 100644 --- a/src/views/app/reducers/index.ts +++ b/src/views/app/reducers/index.ts @@ -6,12 +6,14 @@ import boardConfigReducer from "./boardConfigReducer"; import boardManagerReducer from "./boardManagerReducer"; import exampleReducer from "./exampleReducer"; import libraryManagerReducer from "./libraryManagerReducer"; +import serialPlotterReducer from "./serialPlotterReducer"; const rootReducer = combineReducers({ boardManagerStore: boardManagerReducer, boardConfigStore: boardConfigReducer, exampleStore: exampleReducer, libraryManagerStore: libraryManagerReducer, + serialPlotterStore: serialPlotterReducer, }); export default rootReducer; diff --git a/src/views/app/reducers/serialPlotterReducer.ts b/src/views/app/reducers/serialPlotterReducer.ts new file mode 100644 index 00000000..5b455d79 --- /dev/null +++ b/src/views/app/reducers/serialPlotterReducer.ts @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +import * as actions from "../actions"; +import * as util from "../utils/util"; +import { ActionTypes } from "../WebSocketMiddleware"; + +interface IState { + data: { + [field: string]: Array<[number, number]>, + }; +} + +const initalState: IState = { + data: {}, +}; + +export default function serialPlotterReducer(state = initalState, action) { + switch (action.type) { + case ActionTypes.DATA_RECEIVED: + return onDataReceive(state, action); + default: + return state; + } +} + +function onDataReceive(state, action) { + const currentPlotState = action.payload; + const time = currentPlotState.time; + + for (const field of Object.keys(currentPlotState)) { + if (field === "time") { + continue; + } + const fieldData = state.data[field]; + const value = currentPlotState[field]; + + const newFieldData = fieldData ? [...fieldData] : []; + newFieldData.push([time, value]); + + state.data = { + ...state.data, + [field]: newFieldData, + }; + } + + return { + ...state, + data: {...state.data}, + }; +} diff --git a/src/views/package-lock.json b/src/views/package-lock.json index 007ebcdc..14ff6bd7 100644 --- a/src/views/package-lock.json +++ b/src/views/package-lock.json @@ -670,6 +670,7 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", + "fsevents": "1.1.3", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -1533,6 +1534,910 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", + "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.7.0", + "node-pre-gyp": "0.6.39" + }, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.9" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true, + "dev": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "1.1.1", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true, + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "mime-db": { + "version": "1.27.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.39", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "1.0.2", + "hawk": "3.1.3", + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.0", + "rc": "1.2.1", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "tar-pack": "3.4.0" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.0", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true, + "dev": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "dev": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.1", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + } + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.8", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.2.9", + "rimraf": "2.6.1", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "uuid": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "extsprintf": "1.0.2" + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + } + } + }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", @@ -1736,6 +2641,12 @@ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, + "highcharts": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/highcharts/-/highcharts-6.0.7.tgz", + "integrity": "sha512-LR1gArvVqegc0Gf1bAESm6scmCV5CuyIS0UZTqXKQs5mxMXYXES+xJl5htV3P2GqzleDrp1dsTqDdL9u4DF5Qw==", + "dev": true + }, "history": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/history/-/history-3.3.0.tgz", @@ -1885,6 +2796,12 @@ "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", "dev": true }, + "immutable-is": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/immutable-is/-/immutable-is-3.7.6.tgz", + "integrity": "sha1-762LzyFEM5JALhD6CLeqkbZfbDA=", + "dev": true + }, "in-publish": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", @@ -2039,6 +2956,12 @@ "is-extglob": "1.0.0" } }, + "is-immutable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-immutable/-/is-immutable-1.0.1.tgz", + "integrity": "sha1-C3JJnSE0wDRP07TiTz8KASW3AUg=", + "dev": true + }, "is-number": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", @@ -3875,6 +4798,17 @@ "prop-types": "15.6.0" } }, + "react-jsx-highcharts": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/react-jsx-highcharts/-/react-jsx-highcharts-2.1.0.tgz", + "integrity": "sha512-CnE3qkcSXEk2B9FIKnmEZQCO+X4z6xePFSvpkcGwoGG3pFoMSYNB16wRz9e1k46saIkHl8UfjrDGmrKkjO6z/g==", + "dev": true, + "requires": { + "immutable-is": "3.7.6", + "is-immutable": "1.0.1", + "lodash": "4.17.4" + } + }, "react-list": { "version": "0.8.8", "resolved": "https://registry.npmjs.org/react-list/-/react-list-0.8.8.tgz", @@ -4646,12 +5580,6 @@ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "dev": true }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -4663,6 +5591,12 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", diff --git a/src/views/package.json b/src/views/package.json index 3d47725b..b9e48483 100644 --- a/src/views/package.json +++ b/src/views/package.json @@ -20,9 +20,9 @@ "html-webpack-plugin": "^2.28.0", "node-sass": "^4.5.0", "rc-tree": "~1.4.5", - "react": "^15.4.2", + "react": "^15.6.2", "react-bootstrap": "^0.30.7", - "react-dom": "^15.4.2", + "react-dom": "^15.6.2", "react-list": "^0.8.4", "react-redux": "^5.0.2", "react-router": "^3.0.2", @@ -34,7 +34,9 @@ "style-loader": "^0.13.1", "svg-url-loader": "^2.0.2", "ts-loader": "^2.0.0", - "webpack": "^2.2.1" - }, - "dependencies": {} + "webpack": "^2.2.1", + "highcharts": "^6.0.7", + "prop-types": "^15.6.0", + "react-jsx-highcharts": "^2.1.0" + } } From e5bae201c0382098c6ab508dc94162290b9e8cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Sun, 30 Sep 2018 17:13:42 +0300 Subject: [PATCH 02/35] fix buffer by line splitting --- src/serialmonitor/serialportctrl.ts | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/serialmonitor/serialportctrl.ts b/src/serialmonitor/serialportctrl.ts index 7ddb417a..c4ea77bd 100644 --- a/src/serialmonitor/serialportctrl.ts +++ b/src/serialmonitor/serialportctrl.ts @@ -46,13 +46,15 @@ export class SerialPortCtrl { private _currentBaudRate: number; private _currentSerialPort = null; private _ending: SerialPortEnding; - private _dataEmitter: vscode.EventEmitter; + private _lineEmitter: vscode.EventEmitter; + private _lineBuffer: Buffer; public constructor(port: string, baudRate: number, ending: SerialPortEnding, private _outputChannel: OutputChannel) { this._currentBaudRate = baudRate; this._currentPort = port; this._ending = ending; - this._dataEmitter = new vscode.EventEmitter(); + this._lineEmitter = new vscode.EventEmitter(); + this._lineBuffer = Buffer.alloc(0); } public get isActive(): boolean { @@ -63,8 +65,8 @@ export class SerialPortCtrl { return this._currentPort; } - public onData(listener: (string) => {}): vscode.Disposable { - return this._dataEmitter.event(listener); + public onLine(listener: (string) => {}): vscode.Disposable { + return this._lineEmitter.event(listener); } public open(): Promise { @@ -105,7 +107,8 @@ export class SerialPortCtrl { this._currentSerialPort.on("data", (_event) => { this._outputChannel.append(_event.toString()); - this._dataEmitter.fire(_event.toString()); + + this.readLines(_event).forEach(line => this._lineEmitter.fire(line)); }); this._currentSerialPort.on("error", (_error) => { @@ -192,4 +195,15 @@ export class SerialPortCtrl { public changeEnding(newEnding: SerialPortEnding) { this._ending = newEnding; } + + private readLines(buf: Buffer): Array { + this._lineBuffer = Buffer.concat([this._lineBuffer, buf]); + + const lastEndingIdx = this._lineBuffer.lastIndexOf("\r\n"); + const lines = this._lineBuffer.slice(0, lastEndingIdx).toString().split("\r\n"); + + this._lineBuffer = this._lineBuffer.slice(lastEndingIdx + 1); + + return lines; + } } From 42189c68cbc6e60e0ffc5d285fe92bf35cd0e14e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Sun, 30 Sep 2018 17:13:50 +0300 Subject: [PATCH 03/35] refactor --- src/serialmonitor/serialPlotter.ts | 35 +++++++--------------- src/views/app/components/SerialPlotter.tsx | 2 +- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/src/serialmonitor/serialPlotter.ts b/src/serialmonitor/serialPlotter.ts index 1c27a1a8..0cd702fb 100644 --- a/src/serialmonitor/serialPlotter.ts +++ b/src/serialmonitor/serialPlotter.ts @@ -7,7 +7,7 @@ import { SerialPortCtrl } from "./serialportctrl"; export class SerialPlotter implements vscode.Disposable { private _wss: WebSocket.Server; - private _throttling: number = 100; + private _throttling: number = 50; private sendCurrentStateThrottled; private _currentState: { @@ -17,6 +17,7 @@ export class SerialPlotter implements vscode.Disposable { constructor() { this.setThrottling(this._throttling); + this._currentState = {}; } public open() { @@ -30,7 +31,7 @@ export class SerialPlotter implements vscode.Disposable { } public setSerialPortCtrl(serialPortCtrl: SerialPortCtrl) { - serialPortCtrl.onData(this.handleSerialData.bind(this)); + serialPortCtrl.onLine(this.handleSerialLine.bind(this)); } public setThrottling(throttling: number): void { @@ -48,36 +49,20 @@ export class SerialPlotter implements vscode.Disposable { client.send(JSON.stringify(this._currentState)); } }); - - this._currentState = undefined; } - private handleSerialData(line: string): void { - if (line.length === 0) { - return; - } + private handleSerialLine(line: string): void { + const match = line.match(/^PLOT\[(\d+)\]\[(.+?)=(.+?)\]/) - if (line.indexOf("PLOT") === -1) { + if (!match) { return; } - const startIdx = line.indexOf("["); - const timeDelimeterIdx = line.indexOf(";"); - const endIdx = line.indexOf("]"); - const equalityIdx = line.indexOf("="); - - const timeStr = line.slice(startIdx + 1, timeDelimeterIdx); - const time = parseInt(timeStr, 10); - const field = line.slice(timeDelimeterIdx + 1, equalityIdx); - const valueStr = line.slice(equalityIdx + 1, endIdx); - const value = parseFloat(valueStr); - - this._currentState = { - ...this._currentState, - [field]: value, - time, - }; + const [, time, field, value] = match + this._currentState.time = parseInt(time) + this._currentState[field] = parseFloat(value) + this.sendCurrentStateThrottled(); } } diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx index 820a1679..490aa429 100644 --- a/src/views/app/components/SerialPlotter.tsx +++ b/src/views/app/components/SerialPlotter.tsx @@ -96,7 +96,7 @@ class SerialPlotter extends React.Component Date: Sun, 30 Sep 2018 19:21:51 +0300 Subject: [PATCH 04/35] improve performance --- src/serialmonitor/serialPlotter.ts | 2 +- src/views/app/WebSocketMiddleware.ts | 24 ---- src/views/app/components/SerialPlotter.tsx | 126 +++++++++--------- src/views/app/components/chartConfig.ts | 72 ++++++++++ src/views/app/index.tsx | 4 +- .../app/reducers/serialPlotterReducer.ts | 29 ---- src/views/package-lock.json | 29 +--- src/views/package.json | 5 +- 8 files changed, 139 insertions(+), 152 deletions(-) delete mode 100644 src/views/app/WebSocketMiddleware.ts create mode 100644 src/views/app/components/chartConfig.ts diff --git a/src/serialmonitor/serialPlotter.ts b/src/serialmonitor/serialPlotter.ts index 0cd702fb..ba129bcf 100644 --- a/src/serialmonitor/serialPlotter.ts +++ b/src/serialmonitor/serialPlotter.ts @@ -7,7 +7,7 @@ import { SerialPortCtrl } from "./serialportctrl"; export class SerialPlotter implements vscode.Disposable { private _wss: WebSocket.Server; - private _throttling: number = 50; + private _throttling: number = 100; private sendCurrentStateThrottled; private _currentState: { diff --git a/src/views/app/WebSocketMiddleware.ts b/src/views/app/WebSocketMiddleware.ts deleted file mode 100644 index f019a8d3..00000000 --- a/src/views/app/WebSocketMiddleware.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Action, Dispatch, Middleware, MiddlewareAPI } from "redux"; - -export enum ActionTypes { - DATA_RECEIVED, -} - -export function createSocketMiddleware(): Middleware { - const ws = new WebSocket(`ws://${window.location.host}`); - - return (store: MiddlewareAPI) => { - ws.onmessage = (e: MessageEvent) => { - store.dispatch({ - type: ActionTypes.DATA_RECEIVED, - payload: JSON.parse(e.data), - }); - }; - - return (next: Dispatch) =>
(action: A) => { - return next(action); - } - } -} - - diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx index 490aa429..5bcf4ee4 100644 --- a/src/views/app/components/SerialPlotter.tsx +++ b/src/views/app/components/SerialPlotter.tsx @@ -1,106 +1,100 @@ import * as React from "react"; -import { Button, Checkbox, DropdownButton, MenuItem } from "react-bootstrap"; -import * as ReactList from "react-list"; -import { connect } from "react-redux"; -import SearchInput, { createFilter } from "react-search-input"; -import * as actions from "../actions"; -import { versionCompare } from "../utils/util"; -import LibraryItemView from "./LibraryItemView"; -import { - HighchartsChart, Chart, withHighcharts, XAxis, YAxis, Title, Legend, LineSeries, Tooltip - } from "react-jsx-highcharts"; -import * as Highcharts from "highcharts"; +import { connect, ReactNode } from "react-redux"; +import * as Highcharts from "highcharts/highstock"; +import * as boost from "highcharts/modules/boost"; +import { chartConfig } from "./chartConfig"; + +boost(Highcharts); interface ISerialPlotterProps extends React.Props { plotData: { - [field: string]: number[][] + [field: string]: number[][]; }; } interface ISerialPlotterState extends React.Props {} const mapStateToProps = store => { - return { - plotData: store.serialPlotterStore.data, - }; + return {}; }; const mapDispatchToProps = dispatch => { return {}; }; -class SerialPlotter extends React.Component { - private fieldColorMap: { - [field: string]: string, - } = {}; +class SerialPlotter extends React.Component< + ISerialPlotterProps, + ISerialPlotterState +> { + private _chartRef: HTMLElement; + private _chart: Highcharts; + private _ws: WebSocket; constructor(props) { super(props); } - public render() { - const lines = Object.keys(this.props.plotData).map((field) => ( - - )); - - const plotOptions = { - series: { - marker: { - enabled: false, - } - } - }; + public componentDidMount() { + this.initWebSocket(); + this.initChart(); + } + public render() { return (
-
- - - Serial Plotter - - - Legend - - - - - - Time - - - - Value - {...lines} - - -
+
(this._chartRef = el)} />
); } - private getColorForField(field: string) { - if (!this.fieldColorMap[field]) { - this.fieldColorMap[field] = getRandomColor(); + private initChart() { + this._chart = Highcharts.stockChart(this._chartRef, chartConfig); + } + + private addFrame(frame) { + const time = frame.time; + + for (const field of Object.keys(frame)) { + if (field === "time") { + continue; + } + + const point = [time, frame[field]]; + const series = this._chart.get(field); + + if (series) { + series.addPoint(point, true, false, false); + } else { + this._chart.addSeries({ + id: field, + name: field, + data: [point], + color: getRandomColor(), + type: "line" + }); + } } + } - const fieldColor = this.fieldColorMap[field]; - return fieldColor; + private initWebSocket() { + this._ws = new WebSocket(`ws://${window.location.host}`); + + this._ws.onmessage = (e: MessageEvent) => { + this.addFrame(JSON.parse(e.data)); + }; } } -export default connect(mapStateToProps, mapDispatchToProps)(withHighcharts(SerialPlotter, Highcharts)); - +export default connect( + mapStateToProps, + mapDispatchToProps +)(SerialPlotter); function getRandomColor(): string { const letters = "0123456789ABCDEF"; let color = "#"; for (let i = 0; i < 6; i++) { - color += letters[Math.floor(Math.random() * 16)]; + color += letters[Math.floor(Math.random() * 16)]; } return color; - } +} diff --git a/src/views/app/components/chartConfig.ts b/src/views/app/components/chartConfig.ts new file mode 100644 index 00000000..93a6ef2a --- /dev/null +++ b/src/views/app/components/chartConfig.ts @@ -0,0 +1,72 @@ +export const chartConfig = { + chart: { + zoomType: "x" + }, + title: { + text: "Serial Plotter" + }, + boost: { + enabled: true, + useGPUTranslations: true, + }, + xAxis: { + type: "datetime", + crosshair: true, + title: { + text: "Time" + } + }, + yAxis: { + title: { + text: "Value" + } + }, + series: { + marker: { + enabled: false + } + }, + tooltip: { + animation: false, + split: true, + xDateFormat: "%H:%M:%S.%L" + }, + legend: { + layout: "vertical", + align: "right", + verticalAlign: "middle", + title: { + text: "Legend" + } + }, + plotOptions: { + series: { + showInNavigator: true + } + }, + rangeSelector: { + buttons: [ + { + count: 10, + type: "second", + text: "10s" + }, + { + count: 30, + type: "second", + text: "30s" + }, + { + count: 1, + type: "minute", + text: "1m" + }, + { + type: "all", + text: "All" + } + ], + inputEnabled: false, + selected: 0 + } +}; diff --git a/src/views/app/index.tsx b/src/views/app/index.tsx index 0a136d21..7b19fbf7 100644 --- a/src/views/app/index.tsx +++ b/src/views/app/index.tsx @@ -13,7 +13,6 @@ import LibraryManager from "./components/LibraryManager"; import SerialPlotter from "./components/SerialPlotter"; import reducer from "./reducers"; import "./styles"; -import { createSocketMiddleware } from "./WebSocketMiddleware"; class App extends React.Component<{}, {}> { public render() { @@ -25,8 +24,7 @@ class App extends React.Component<{}, {}> { } } -const webSocketMiddleware = createSocketMiddleware(); -const createStoreWithMiddleware = applyMiddleware(webSocketMiddleware)(createStore); +const createStoreWithMiddleware = applyMiddleware()(createStore); const store = createStoreWithMiddleware(reducer); ReactDOM.render( diff --git a/src/views/app/reducers/serialPlotterReducer.ts b/src/views/app/reducers/serialPlotterReducer.ts index 5b455d79..bbad741c 100644 --- a/src/views/app/reducers/serialPlotterReducer.ts +++ b/src/views/app/reducers/serialPlotterReducer.ts @@ -3,7 +3,6 @@ import * as actions from "../actions"; import * as util from "../utils/util"; -import { ActionTypes } from "../WebSocketMiddleware"; interface IState { data: { @@ -17,35 +16,7 @@ const initalState: IState = { export default function serialPlotterReducer(state = initalState, action) { switch (action.type) { - case ActionTypes.DATA_RECEIVED: - return onDataReceive(state, action); default: return state; } } - -function onDataReceive(state, action) { - const currentPlotState = action.payload; - const time = currentPlotState.time; - - for (const field of Object.keys(currentPlotState)) { - if (field === "time") { - continue; - } - const fieldData = state.data[field]; - const value = currentPlotState[field]; - - const newFieldData = fieldData ? [...fieldData] : []; - newFieldData.push([time, value]); - - state.data = { - ...state.data, - [field]: newFieldData, - }; - } - - return { - ...state, - data: {...state.data}, - }; -} diff --git a/src/views/package-lock.json b/src/views/package-lock.json index 5ed40f37..e5f2349a 100644 --- a/src/views/package-lock.json +++ b/src/views/package-lock.json @@ -2630,9 +2630,9 @@ "dev": true }, "highcharts": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/highcharts/-/highcharts-6.0.7.tgz", - "integrity": "sha512-LR1gArvVqegc0Gf1bAESm6scmCV5CuyIS0UZTqXKQs5mxMXYXES+xJl5htV3P2GqzleDrp1dsTqDdL9u4DF5Qw==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/highcharts/-/highcharts-6.1.4.tgz", + "integrity": "sha512-m7uK2dvDmop4wAgB7RQjODS894HqNrxRUJh+Px7n1PsNyb7+aO22cRxx2rhvjmy1R8Q3Tf5I03AbjN5oAYyWSw==", "dev": true }, "history": { @@ -2778,12 +2778,6 @@ "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", "dev": true }, - "immutable-is": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/immutable-is/-/immutable-is-3.7.6.tgz", - "integrity": "sha1-762LzyFEM5JALhD6CLeqkbZfbDA=", - "dev": true - }, "in-publish": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", @@ -2938,12 +2932,6 @@ "is-extglob": "^1.0.0" } }, - "is-immutable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-immutable/-/is-immutable-1.0.1.tgz", - "integrity": "sha1-C3JJnSE0wDRP07TiTz8KASW3AUg=", - "dev": true - }, "is-number": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", @@ -4789,17 +4777,6 @@ "prop-types": "^15.5.8" } }, - "react-jsx-highcharts": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/react-jsx-highcharts/-/react-jsx-highcharts-2.1.0.tgz", - "integrity": "sha512-CnE3qkcSXEk2B9FIKnmEZQCO+X4z6xePFSvpkcGwoGG3pFoMSYNB16wRz9e1k46saIkHl8UfjrDGmrKkjO6z/g==", - "dev": true, - "requires": { - "immutable-is": "^3.7.6", - "is-immutable": "^1.0.1", - "lodash": "^4.17.4" - } - }, "react-list": { "version": "0.8.8", "resolved": "https://registry.npmjs.org/react-list/-/react-list-0.8.8.tgz", diff --git a/src/views/package.json b/src/views/package.json index e0d4d74b..6ceca880 100644 --- a/src/views/package.json +++ b/src/views/package.json @@ -35,8 +35,7 @@ "svg-url-loader": "^2.0.2", "ts-loader": "^2.0.0", "webpack": "^2.2.1", - "highcharts": "^6.0.7", - "prop-types": "^15.6.0", - "react-jsx-highcharts": "^2.1.0" + "highcharts": "^6.1.4", + "prop-types": "^15.6.0" } } From c9a9d5bc206d25b5f86a07e27b1591f5d3409fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Sun, 30 Sep 2018 20:43:45 +0300 Subject: [PATCH 05/35] add refresh rate input --- src/views/app/components/SerialPlotter.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx index 5bcf4ee4..7bb0a723 100644 --- a/src/views/app/components/SerialPlotter.tsx +++ b/src/views/app/components/SerialPlotter.tsx @@ -1,5 +1,13 @@ import * as React from "react"; import { connect, ReactNode } from "react-redux"; +import { + FormGroup, + FormControl, + Col, + Button, + InputGroup, + ControlLabel +} from "react-bootstrap"; import * as Highcharts from "highcharts/highstock"; import * as boost from "highcharts/modules/boost"; import { chartConfig } from "./chartConfig"; @@ -43,6 +51,17 @@ class SerialPlotter extends React.Component< return (
(this._chartRef = el)} /> +
+ + + Refresh rate + + + + + + +
); } From 6f07b896070d29406d06bdaf10971d6c8bb2be55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Sun, 30 Sep 2018 20:43:59 +0300 Subject: [PATCH 06/35] start monitor if not started --- src/serialmonitor/serialMonitor.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/serialmonitor/serialMonitor.ts b/src/serialmonitor/serialMonitor.ts index 846355d3..ea2fcf97 100644 --- a/src/serialmonitor/serialMonitor.ts +++ b/src/serialmonitor/serialMonitor.ts @@ -59,9 +59,7 @@ export class SerialMonitor implements vscode.Disposable { private _ending: SerialPortEnding; - private constructor() { - this._serialPlotter = new SerialPlotter(); - + private constructor() { const dc = DeviceContext.getInstance(); dc.onDidChange(() => { if (dc.port) { @@ -193,7 +191,13 @@ export class SerialMonitor implements vscode.Disposable { } public async openSerialPlotter() { - // TODO: check if monitor active + if(!this._serialPlotter) { + this._serialPlotter = new SerialPlotter(); + } + + if(!this._serialPortCtrl || !this._serialPortCtrl.isActive) { + await this.openSerialMonitor() + } this._serialPlotter.setSerialPortCtrl(this._serialPortCtrl); this._serialPlotter.open(); From 2cec6d54cc23010c021be49052526e4b98ea3bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Sun, 30 Sep 2018 21:19:22 +0300 Subject: [PATCH 07/35] allow to update plot refresh rate from UI --- src/arduino/arduinoContentProvider.ts | 22 +++++++++++- src/serialmonitor/serialMonitor.ts | 6 ++-- src/views/app/actions/api.ts | 6 ++++ src/views/app/components/SerialPlotter.tsx | 41 +++++++++++++++++----- 4 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/arduino/arduinoContentProvider.ts b/src/arduino/arduinoContentProvider.ts index ef6312d0..306eedcc 100644 --- a/src/arduino/arduinoContentProvider.ts +++ b/src/arduino/arduinoContentProvider.ts @@ -13,6 +13,7 @@ import * as JSONHelper from "../common/cycle"; import * as Logger from "../logger/logger"; import LocalWebServer from "./localWebServer"; import { VscodeSettings } from "./vscodeSettings"; +import { SerialMonitor } from "../serialmonitor/serialMonitor"; export class ArduinoContentProvider implements vscode.TextDocumentContentProvider { private _webserver: LocalWebServer; @@ -52,8 +53,9 @@ export class ArduinoContentProvider implements vscode.TextDocumentContentProvide this.addHandlerWithLogger("load-examples", "/api/examples", async (req, res) => await this.getExamples(req, res)); this.addHandlerWithLogger("open-example", "/api/openexample", (req, res) => this.openExample(req, res), true); - // Serial Plotter + // Arduino Serial Plotter this.addHandlerWithLogger("show-serialplotter", "/serialplotter", (req, res) => this.getHtmlView(req, res)); + this.addHandlerWithLogger("update-plot-refresh-rate", "/api/update-plot-refresh-rate", (req, res) => this.updatePlotRefreshRate(req, res), true); this._webserver.start(); } @@ -304,6 +306,24 @@ export class ArduinoContentProvider implements vscode.TextDocumentContentProvide } } + public updatePlotRefreshRate(req, res) { + if (!req.body.rate) { + return res.status(400).send("BAD Request! Missing parameters!"); + } else { + try { + const serialMonitor = SerialMonitor.getInstance(); + + serialMonitor.serialPlotter.setThrottling(req.body.rate); + + return res.json({ + status: "OK", + }); + } catch (error) { + return res.status(500).send(`Update plot refresh rate failed with message "code:${error.code}, err:${error.stderr}"`); + } + } + } + private addHandlerWithLogger(handlerName: string, url: string, handler: (req, res) => void, post: boolean = false): void { const wrappedHandler = async (req, res) => { const guid = Uuid().replace(/-/g, ""); diff --git a/src/serialmonitor/serialMonitor.ts b/src/serialmonitor/serialMonitor.ts index ea2fcf97..5ad0819e 100644 --- a/src/serialmonitor/serialMonitor.ts +++ b/src/serialmonitor/serialMonitor.ts @@ -60,6 +60,8 @@ export class SerialMonitor implements vscode.Disposable { private _ending: SerialPortEnding; private constructor() { + this._serialPlotter = new SerialPlotter(); + const dc = DeviceContext.getInstance(); dc.onDidChange(() => { if (dc.port) { @@ -191,10 +193,6 @@ export class SerialMonitor implements vscode.Disposable { } public async openSerialPlotter() { - if(!this._serialPlotter) { - this._serialPlotter = new SerialPlotter(); - } - if(!this._serialPortCtrl || !this._serialPortCtrl.isActive) { await this.openSerialMonitor() } diff --git a/src/views/app/actions/api.ts b/src/views/app/actions/api.ts index 0fa1547c..ee538df3 100644 --- a/src/views/app/actions/api.ts +++ b/src/views/app/actions/api.ts @@ -95,3 +95,9 @@ export function openExample(examplePath) { examplePath, }).then((response) => response.json()); } + +export function updatePlotRefreshRate(rate) { + return postHTTP("/api/update-plot-refresh-rate", { + rate, + }).then((response) => response.json()); +} diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx index 7bb0a723..a1a5eb23 100644 --- a/src/views/app/components/SerialPlotter.tsx +++ b/src/views/app/components/SerialPlotter.tsx @@ -11,16 +11,15 @@ import { import * as Highcharts from "highcharts/highstock"; import * as boost from "highcharts/modules/boost"; import { chartConfig } from "./chartConfig"; +import * as API from "../actions/api"; boost(Highcharts); -interface ISerialPlotterProps extends React.Props { - plotData: { - [field: string]: number[][]; - }; -} +interface ISerialPlotterProps extends React.Props {} -interface ISerialPlotterState extends React.Props {} +interface ISerialPlotterState extends React.Props { + rate: string; +} const mapStateToProps = store => { return {}; @@ -38,6 +37,10 @@ class SerialPlotter extends React.Component< private _chart: Highcharts; private _ws: WebSocket; + public state = { + rate: '100' + }; + constructor(props) { super(props); } @@ -55,9 +58,15 @@ class SerialPlotter extends React.Component< Refresh rate - + - + @@ -102,6 +111,22 @@ class SerialPlotter extends React.Component< this.addFrame(JSON.parse(e.data)); }; } + + private updatePlotRefreshRate = async () => { + const rate = parseInt(this.state.rate); + + if (!Number.isFinite(rate)) { + return; + } + + await API.updatePlotRefreshRate(rate); + }; + + private onRateChange = e => { + this.setState({ + rate: e.target.value + }); + }; } export default connect( From 52c3eab91a962ae53c4ad741dd138776380d8e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Sun, 30 Sep 2018 21:38:33 +0300 Subject: [PATCH 08/35] add reset and play/pause controls --- src/serialmonitor/serialMonitor.ts | 1 + src/serialmonitor/serialPlotter.ts | 10 +++- src/views/app/components/SerialPlotter.tsx | 69 +++++++++++++++++++++- 3 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/serialmonitor/serialMonitor.ts b/src/serialmonitor/serialMonitor.ts index 5ad0819e..705cd806 100644 --- a/src/serialmonitor/serialMonitor.ts +++ b/src/serialmonitor/serialMonitor.ts @@ -186,6 +186,7 @@ export class SerialMonitor implements vscode.Disposable { try { await this._serialPortCtrl.open(); this.updatePortStatus(true); + this._serialPlotter.reset(); } catch (error) { Logger.notifyUserWarning("openSerialMonitorError", error, `Failed to open serial port ${this._currentPort} due to error: + ${error.toString()}`); diff --git a/src/serialmonitor/serialPlotter.ts b/src/serialmonitor/serialPlotter.ts index ba129bcf..0d6fab57 100644 --- a/src/serialmonitor/serialPlotter.ts +++ b/src/serialmonitor/serialPlotter.ts @@ -24,6 +24,10 @@ export class SerialPlotter implements vscode.Disposable { vscode.commands.executeCommand("vscode.previewHtml", SERIAL_PLOTTER_URI, vscode.ViewColumn.Two, "Serial Plotter"); } + public reset() { + this.sendMessage({action: 'RESET'}); + } + public dispose() {} public setWebSocketServer(wss: WebSocket.Server) { @@ -40,13 +44,17 @@ export class SerialPlotter implements vscode.Disposable { } private sendCurrentState() { + this.sendMessage(this._currentState); + } + + private sendMessage(msg: {}) { if (!this._wss) { return; } this._wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { - client.send(JSON.stringify(this._currentState)); + client.send(JSON.stringify(msg)); } }); } diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx index a1a5eb23..17667b13 100644 --- a/src/views/app/components/SerialPlotter.tsx +++ b/src/views/app/components/SerialPlotter.tsx @@ -15,10 +15,20 @@ import * as API from "../actions/api"; boost(Highcharts); +interface DataFrame { + time: number; + [field: string]: number; +} + +interface DataAction { + action: string; +} + interface ISerialPlotterProps extends React.Props {} interface ISerialPlotterState extends React.Props { rate: string; + active: boolean; } const mapStateToProps = store => { @@ -38,7 +48,8 @@ class SerialPlotter extends React.Component< private _ws: WebSocket; public state = { - rate: '100' + rate: "100", + active: false }; constructor(props) { @@ -69,6 +80,18 @@ class SerialPlotter extends React.Component< + + + + + + + + + + + +
@@ -79,7 +102,7 @@ class SerialPlotter extends React.Component< this._chart = Highcharts.stockChart(this._chartRef, chartConfig); } - private addFrame(frame) { + private addFrame(frame: DataFrame) { const time = frame.time; for (const field of Object.keys(frame)) { @@ -104,12 +127,52 @@ class SerialPlotter extends React.Component< } } + private doAction(action: DataAction) { + if (action.action === "RESET") { + this.reset(); + } + } + + private play = () => { + this.setState({ + active: true + }); + }; + + private pause = () => { + this.setState({ + active: false + }); + }; + + private reset = () => { + while (this._chart.series.length > 0) { + this._chart.series[0].remove(false); + } + + this._chart.redraw(); + }; + private initWebSocket() { this._ws = new WebSocket(`ws://${window.location.host}`); this._ws.onmessage = (e: MessageEvent) => { - this.addFrame(JSON.parse(e.data)); + if(!this.state.active) { + return + } + + const data = JSON.parse(e.data); + + if (data.time) { + this.addFrame(data); + } else if (data.action) { + this.doAction(data); + } }; + + this.setState({ + active: true + }); } private updatePlotRefreshRate = async () => { From 644cb588e66a275ef249d35f32267b705b4332dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Sun, 30 Sep 2018 21:56:10 +0300 Subject: [PATCH 09/35] fix current frame merging --- src/serialmonitor/serialPlotter.ts | 36 ++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/serialmonitor/serialPlotter.ts b/src/serialmonitor/serialPlotter.ts index 0d6fab57..3107b4cc 100644 --- a/src/serialmonitor/serialPlotter.ts +++ b/src/serialmonitor/serialPlotter.ts @@ -5,19 +5,22 @@ import * as WebSocket from "ws"; import { SERIAL_PLOTTER_URI } from "../common/constants"; import { SerialPortCtrl } from "./serialportctrl"; +interface DataFrame { + time?: number, + [field: string]: number, +} + export class SerialPlotter implements vscode.Disposable { private _wss: WebSocket.Server; private _throttling: number = 100; - private sendCurrentStateThrottled; + private sendCurrentFrameThrottled; - private _currentState: { - time?: number, - [field: string]: number, - }; + private _currentFrame: DataFrame; + private _lastSentTime: number; constructor() { this.setThrottling(this._throttling); - this._currentState = {}; + this._currentFrame = {}; } public open() { @@ -40,11 +43,17 @@ export class SerialPlotter implements vscode.Disposable { public setThrottling(throttling: number): void { this._throttling = throttling; - this.sendCurrentStateThrottled = throttle(this.sendCurrentState, this._throttling, { leading: false }); + this.sendCurrentFrameThrottled = throttle(this.sendCurrentFrame, this._throttling, { leading: false }); } - private sendCurrentState() { - this.sendMessage(this._currentState); + private sendCurrentFrame() { + if(this._lastSentTime >= this._currentFrame.time) { + return + } + + this.sendMessage(this._currentFrame); + this._lastSentTime = this._currentFrame.time; + this._currentFrame = {} } private sendMessage(msg: {}) { @@ -68,9 +77,12 @@ export class SerialPlotter implements vscode.Disposable { const [, time, field, value] = match - this._currentState.time = parseInt(time) - this._currentState[field] = parseFloat(value) + this._currentFrame = { + ...this._currentFrame, + [field]: parseFloat(value), + time: parseInt(time), + } - this.sendCurrentStateThrottled(); + this.sendCurrentFrameThrottled(); } } From 57fe335874fb9bb3a569309b169088b4cdbcdca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Sun, 30 Sep 2018 22:16:24 +0300 Subject: [PATCH 10/35] fix linting --- src/arduino/arduinoContentProvider.ts | 6 +- src/serialmonitor/serialMonitor.ts | 20 ++--- src/serialmonitor/serialPlotter.ts | 26 +++--- src/serialmonitor/serialportctrl.ts | 8 +- src/views/app/actions/api.ts | 2 +- src/views/app/components/SerialPlotter.tsx | 81 ++++++++----------- src/views/app/components/chartConfig.ts | 40 ++++----- src/views/app/reducers/index.ts | 2 - .../app/reducers/serialPlotterReducer.ts | 22 ----- 9 files changed, 84 insertions(+), 123 deletions(-) delete mode 100644 src/views/app/reducers/serialPlotterReducer.ts diff --git a/src/arduino/arduinoContentProvider.ts b/src/arduino/arduinoContentProvider.ts index 306eedcc..0fb5eb98 100644 --- a/src/arduino/arduinoContentProvider.ts +++ b/src/arduino/arduinoContentProvider.ts @@ -11,9 +11,9 @@ import * as Constants from "../common/constants"; import { SERIAL_PLOTTER_URI } from "../common/constants"; import * as JSONHelper from "../common/cycle"; import * as Logger from "../logger/logger"; +import { SerialMonitor } from "../serialmonitor/serialMonitor"; import LocalWebServer from "./localWebServer"; import { VscodeSettings } from "./vscodeSettings"; -import { SerialMonitor } from "../serialmonitor/serialMonitor"; export class ArduinoContentProvider implements vscode.TextDocumentContentProvider { private _webserver: LocalWebServer; @@ -55,7 +55,7 @@ export class ArduinoContentProvider implements vscode.TextDocumentContentProvide // Arduino Serial Plotter this.addHandlerWithLogger("show-serialplotter", "/serialplotter", (req, res) => this.getHtmlView(req, res)); - this.addHandlerWithLogger("update-plot-refresh-rate", "/api/update-plot-refresh-rate", (req, res) => this.updatePlotRefreshRate(req, res), true); + this.addHandlerWithLogger("updateplotrate", "/api/updateplotrate", (req, res) => this.updatePlotRefreshRate(req, res), true); this._webserver.start(); } @@ -312,7 +312,7 @@ export class ArduinoContentProvider implements vscode.TextDocumentContentProvide } else { try { const serialMonitor = SerialMonitor.getInstance(); - + serialMonitor.serialPlotter.setThrottling(req.body.rate); return res.json({ diff --git a/src/serialmonitor/serialMonitor.ts b/src/serialmonitor/serialMonitor.ts index 705cd806..2195b914 100644 --- a/src/serialmonitor/serialMonitor.ts +++ b/src/serialmonitor/serialMonitor.ts @@ -6,8 +6,8 @@ import ArduinoContext from "../arduinoContext"; import * as constants from "../common/constants"; import { DeviceContext } from "../deviceContext"; import * as Logger from "../logger/logger"; -import { SerialPortCtrl, SerialPortEnding } from "./serialportctrl"; import { SerialPlotter } from "./serialPlotter"; +import { SerialPortCtrl, SerialPortEnding } from "./serialportctrl"; export interface ISerialPortDetail { comName: string; @@ -51,7 +51,7 @@ export class SerialMonitor implements vscode.Disposable { private _endingStatusBar: vscode.StatusBarItem; - private _openPlotterStatusBar: vscode.StatusBarItem; + private _openPlotStatusBar: vscode.StatusBarItem; private _serialPortCtrl: SerialPortCtrl = null; @@ -59,7 +59,7 @@ export class SerialMonitor implements vscode.Disposable { private _ending: SerialPortEnding; - private constructor() { + private constructor() { this._serialPlotter = new SerialPlotter(); const dc = DeviceContext.getInstance(); @@ -100,11 +100,11 @@ export class SerialMonitor implements vscode.Disposable { this._endingStatusBar.tooltip = "Serial Port Line Ending"; this._endingStatusBar.text = `No line ending`; - this._openPlotterStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.OPEN_SERIAL_PLOTTER); - this._openPlotterStatusBar.command = "arduino.openSerialPlotter"; - this._openPlotterStatusBar.tooltip = "Open Serial Plotter"; - this._openPlotterStatusBar.text = "Plotter"; - this._openPlotterStatusBar.show(); + this._openPlotStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.OPEN_SERIAL_PLOTTER); + this._openPlotStatusBar.command = "arduino.openSerialPlotter"; + this._openPlotStatusBar.tooltip = "Open Serial Plotter"; + this._openPlotStatusBar.text = "Plotter"; + this._openPlotStatusBar.show(); } public get initialized(): boolean { return !!this._outputChannel; @@ -194,8 +194,8 @@ export class SerialMonitor implements vscode.Disposable { } public async openSerialPlotter() { - if(!this._serialPortCtrl || !this._serialPortCtrl.isActive) { - await this.openSerialMonitor() + if (!this._serialPortCtrl || !this._serialPortCtrl.isActive) { + await this.openSerialMonitor(); } this._serialPlotter.setSerialPortCtrl(this._serialPortCtrl); diff --git a/src/serialmonitor/serialPlotter.ts b/src/serialmonitor/serialPlotter.ts index 3107b4cc..4397800b 100644 --- a/src/serialmonitor/serialPlotter.ts +++ b/src/serialmonitor/serialPlotter.ts @@ -5,9 +5,9 @@ import * as WebSocket from "ws"; import { SERIAL_PLOTTER_URI } from "../common/constants"; import { SerialPortCtrl } from "./serialportctrl"; -interface DataFrame { - time?: number, - [field: string]: number, +interface IDataFrame { + time?: number; + [field: string]: number; } export class SerialPlotter implements vscode.Disposable { @@ -15,7 +15,7 @@ export class SerialPlotter implements vscode.Disposable { private _throttling: number = 100; private sendCurrentFrameThrottled; - private _currentFrame: DataFrame; + private _currentFrame: IDataFrame; private _lastSentTime: number; constructor() { @@ -28,7 +28,7 @@ export class SerialPlotter implements vscode.Disposable { } public reset() { - this.sendMessage({action: 'RESET'}); + this.sendMessage({action: "RESET"}); } public dispose() {} @@ -47,13 +47,13 @@ export class SerialPlotter implements vscode.Disposable { } private sendCurrentFrame() { - if(this._lastSentTime >= this._currentFrame.time) { - return + if (this._lastSentTime >= this._currentFrame.time) { + return; } this.sendMessage(this._currentFrame); this._lastSentTime = this._currentFrame.time; - this._currentFrame = {} + this._currentFrame = {}; } private sendMessage(msg: {}) { @@ -69,20 +69,20 @@ export class SerialPlotter implements vscode.Disposable { } private handleSerialLine(line: string): void { - const match = line.match(/^PLOT\[(\d+)\]\[(.+?)=(.+?)\]/) + const match = line.match(/^PLOT\[(\d+)\]\[(.+?)=(.+?)\]/); if (!match) { return; } - const [, time, field, value] = match + const [, time, field, value] = match; this._currentFrame = { ...this._currentFrame, [field]: parseFloat(value), - time: parseInt(time), - } - + time: parseInt(time, 10), + }; + this.sendCurrentFrameThrottled(); } } diff --git a/src/serialmonitor/serialportctrl.ts b/src/serialmonitor/serialportctrl.ts index c4ea77bd..d2069785 100644 --- a/src/serialmonitor/serialportctrl.ts +++ b/src/serialmonitor/serialportctrl.ts @@ -2,7 +2,7 @@ // Licensed under the MIT license. import * as os from "os"; -import * as vscode from 'vscode'; +import * as vscode from "vscode"; import { OutputChannel, QuickPickItem, StatusBarAlignment, StatusBarItem, window } from "vscode"; import { VscodeSettings } from "../arduino/vscodeSettings"; @@ -107,8 +107,8 @@ export class SerialPortCtrl { this._currentSerialPort.on("data", (_event) => { this._outputChannel.append(_event.toString()); - - this.readLines(_event).forEach(line => this._lineEmitter.fire(line)); + + this.readLines(_event).forEach((line) => this._lineEmitter.fire(line)); }); this._currentSerialPort.on("error", (_error) => { @@ -196,7 +196,7 @@ export class SerialPortCtrl { this._ending = newEnding; } - private readLines(buf: Buffer): Array { + private readLines(buf: Buffer): string[] { this._lineBuffer = Buffer.concat([this._lineBuffer, buf]); const lastEndingIdx = this._lineBuffer.lastIndexOf("\r\n"); diff --git a/src/views/app/actions/api.ts b/src/views/app/actions/api.ts index ee538df3..5990732f 100644 --- a/src/views/app/actions/api.ts +++ b/src/views/app/actions/api.ts @@ -97,7 +97,7 @@ export function openExample(examplePath) { } export function updatePlotRefreshRate(rate) { - return postHTTP("/api/update-plot-refresh-rate", { + return postHTTP("/api/updateplotrate", { rate, }).then((response) => response.json()); } diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx index 17667b13..9af75e6e 100644 --- a/src/views/app/components/SerialPlotter.tsx +++ b/src/views/app/components/SerialPlotter.tsx @@ -1,57 +1,45 @@ +import * as Highcharts from "highcharts/highstock"; +import * as boost from "highcharts/modules/boost"; import * as React from "react"; -import { connect, ReactNode } from "react-redux"; import { - FormGroup, - FormControl, - Col, Button, + ControlLabel, + FormControl, + FormGroup, InputGroup, - ControlLabel } from "react-bootstrap"; -import * as Highcharts from "highcharts/highstock"; -import * as boost from "highcharts/modules/boost"; -import { chartConfig } from "./chartConfig"; import * as API from "../actions/api"; +import { chartConfig } from "./chartConfig"; boost(Highcharts); -interface DataFrame { +interface IDataFrame { time: number; [field: string]: number; } -interface DataAction { +interface IDataAction { action: string; } -interface ISerialPlotterProps extends React.Props {} - interface ISerialPlotterState extends React.Props { rate: string; active: boolean; } -const mapStateToProps = store => { - return {}; -}; - -const mapDispatchToProps = dispatch => { - return {}; -}; - class SerialPlotter extends React.Component< - ISerialPlotterProps, + void, ISerialPlotterState > { - private _chartRef: HTMLElement; - private _chart: Highcharts; - private _ws: WebSocket; - public state = { rate: "100", - active: false + active: false, }; + private _chartRef: HTMLElement; + private _chart: Highcharts; + private _ws: WebSocket; + constructor(props) { super(props); } @@ -64,7 +52,7 @@ class SerialPlotter extends React.Component< public render() { return (
-
(this._chartRef = el)} /> +
(this._chartRef = el)} />
@@ -89,7 +77,7 @@ class SerialPlotter extends React.Component< - + @@ -102,7 +90,7 @@ class SerialPlotter extends React.Component< this._chart = Highcharts.stockChart(this._chartRef, chartConfig); } - private addFrame(frame: DataFrame) { + private addFrame(frame: IDataFrame) { const time = frame.time; for (const field of Object.keys(frame)) { @@ -121,13 +109,13 @@ class SerialPlotter extends React.Component< name: field, data: [point], color: getRandomColor(), - type: "line" + type: "line", }); } } } - private doAction(action: DataAction) { + private doAction(action: IDataAction) { if (action.action === "RESET") { this.reset(); } @@ -135,15 +123,15 @@ class SerialPlotter extends React.Component< private play = () => { this.setState({ - active: true + active: true, }); - }; + } private pause = () => { this.setState({ - active: false + active: false, }); - }; + } private reset = () => { while (this._chart.series.length > 0) { @@ -151,14 +139,14 @@ class SerialPlotter extends React.Component< } this._chart.redraw(); - }; + } private initWebSocket() { this._ws = new WebSocket(`ws://${window.location.host}`); this._ws.onmessage = (e: MessageEvent) => { - if(!this.state.active) { - return + if (!this.state.active) { + return; } const data = JSON.parse(e.data); @@ -171,31 +159,28 @@ class SerialPlotter extends React.Component< }; this.setState({ - active: true + active: true, }); } private updatePlotRefreshRate = async () => { - const rate = parseInt(this.state.rate); + const rate = parseInt(this.state.rate, 10); if (!Number.isFinite(rate)) { return; } await API.updatePlotRefreshRate(rate); - }; + } - private onRateChange = e => { + private onRateChange = (e) => { this.setState({ - rate: e.target.value + rate: e.target.value, }); - }; + } } -export default connect( - mapStateToProps, - mapDispatchToProps -)(SerialPlotter); +export default SerialPlotter; function getRandomColor(): string { const letters = "0123456789ABCDEF"; diff --git a/src/views/app/components/chartConfig.ts b/src/views/app/components/chartConfig.ts index 93a6ef2a..49fcd208 100644 --- a/src/views/app/components/chartConfig.ts +++ b/src/views/app/components/chartConfig.ts @@ -1,9 +1,9 @@ export const chartConfig = { chart: { - zoomType: "x" + zoomType: "x", }, title: { - text: "Serial Plotter" + text: "Serial Plotter", }, boost: { enabled: true, @@ -13,60 +13,60 @@ export const chartConfig = { type: "datetime", crosshair: true, title: { - text: "Time" - } + text: "Time", + }, }, yAxis: { title: { - text: "Value" - } + text: "Value", + }, }, series: { marker: { - enabled: false - } + enabled: false, + }, }, tooltip: { animation: false, split: true, - xDateFormat: "%H:%M:%S.%L" + xDateFormat: "%H:%M:%S.%L", }, legend: { layout: "vertical", align: "right", verticalAlign: "middle", title: { - text: "Legend" - } + text: "Legend", + }, }, plotOptions: { series: { - showInNavigator: true - } + showInNavigator: true, + }, }, rangeSelector: { buttons: [ { count: 10, type: "second", - text: "10s" + text: "10s", }, { count: 30, type: "second", - text: "30s" + text: "30s", }, { count: 1, type: "minute", - text: "1m" + text: "1m", }, { type: "all", - text: "All" - } + text: "All", + }, ], inputEnabled: false, - selected: 0 - } + selected: 0, + }, }; diff --git a/src/views/app/reducers/index.ts b/src/views/app/reducers/index.ts index 2b85c861..f9af3f9a 100644 --- a/src/views/app/reducers/index.ts +++ b/src/views/app/reducers/index.ts @@ -6,14 +6,12 @@ import boardConfigReducer from "./boardConfigReducer"; import boardManagerReducer from "./boardManagerReducer"; import exampleReducer from "./exampleReducer"; import libraryManagerReducer from "./libraryManagerReducer"; -import serialPlotterReducer from "./serialPlotterReducer"; const rootReducer = combineReducers({ boardManagerStore: boardManagerReducer, boardConfigStore: boardConfigReducer, exampleStore: exampleReducer, libraryManagerStore: libraryManagerReducer, - serialPlotterStore: serialPlotterReducer, }); export default rootReducer; diff --git a/src/views/app/reducers/serialPlotterReducer.ts b/src/views/app/reducers/serialPlotterReducer.ts deleted file mode 100644 index bbad741c..00000000 --- a/src/views/app/reducers/serialPlotterReducer.ts +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -import * as actions from "../actions"; -import * as util from "../utils/util"; - -interface IState { - data: { - [field: string]: Array<[number, number]>, - }; -} - -const initalState: IState = { - data: {}, -}; - -export default function serialPlotterReducer(state = initalState, action) { - switch (action.type) { - default: - return state; - } -} From 6059f2610ff3e86d08e875aa18e24a7508e161b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Mon, 1 Oct 2018 07:24:57 +0300 Subject: [PATCH 11/35] add new command to tests --- test/extension.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/extension.test.ts b/test/extension.test.ts index 1309bbdc..11750d31 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -45,6 +45,7 @@ suite("Arduino: Extension Tests", () => { "arduino.addLibPath", "arduino.selectSerialPort", "arduino.openSerialMonitor", + "arduino.openSerialPlotter", "arduino.changeBaudRate", "arduino.changeEnding", "arduino.sendMessageToSerialPort", From 51a678b0c88042c5b93b00a8057b9887956d559c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Mon, 14 Jan 2019 18:14:32 +0300 Subject: [PATCH 12/35] replace deprecated `previewHtml` with webview api --- src/extension.ts | 10 +++++++++- src/serialmonitor/serialPlotter.ts | 3 +-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 9ccdea67..a62344cc 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -12,7 +12,7 @@ import ArduinoActivator from "./arduinoActivator"; import ArduinoContext from "./arduinoContext"; import { ARDUINO_CONFIG_FILE, ARDUINO_MANAGER_PROTOCOL, ARDUINO_MODE, BOARD_CONFIG_URI, BOARD_MANAGER_URI, EXAMPLES_URI, - LIBRARY_MANAGER_URI, + LIBRARY_MANAGER_URI, SERIAL_PLOTTER_URI } from "./common/constants"; import { validateArduinoPath } from "./common/platform"; import * as util from "./common/util"; @@ -146,6 +146,14 @@ export async function activate(context: vscode.ExtensionContext) { panel.webview.html = await arduinoManagerProvider.provideTextDocumentContent(EXAMPLES_URI); }); + registerArduinoCommand("arduino.showSerialPlotter", async () => { + const panel = vscode.window.createWebviewPanel("arduinoSerialPlotter", "Arduino Serial Plottter", vscode.ViewColumn.Two, { + enableScripts: true, + retainContextWhenHidden: true, + }); + panel.webview.html = await arduinoManagerProvider.provideTextDocumentContent(SERIAL_PLOTTER_URI); + }); + // change board type registerArduinoCommand("arduino.changeBoardType", async () => { try { diff --git a/src/serialmonitor/serialPlotter.ts b/src/serialmonitor/serialPlotter.ts index 4397800b..3307bc38 100644 --- a/src/serialmonitor/serialPlotter.ts +++ b/src/serialmonitor/serialPlotter.ts @@ -2,7 +2,6 @@ import * as throttle from "lodash.throttle"; import * as vscode from "vscode"; import * as WebSocket from "ws"; -import { SERIAL_PLOTTER_URI } from "../common/constants"; import { SerialPortCtrl } from "./serialportctrl"; interface IDataFrame { @@ -24,7 +23,7 @@ export class SerialPlotter implements vscode.Disposable { } public open() { - vscode.commands.executeCommand("vscode.previewHtml", SERIAL_PLOTTER_URI, vscode.ViewColumn.Two, "Serial Plotter"); + vscode.commands.executeCommand("arduino.showSerialPlotter"); } public reset() { From 0c1ae8af4830aad2cc6f5d3670d3e06623c22ec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Mon, 14 Jan 2019 18:53:36 +0300 Subject: [PATCH 13/35] add `plotRegex` setting to specify custom regex to parse serial output --- README.md | 3 ++- package.json | 4 ++++ src/arduino/vscodeSettings.ts | 6 ++++++ src/serialmonitor/serialPlotter.ts | 3 ++- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 910cba07..55df6d6d 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,8 @@ 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 + "arduino.defaultBaudRate": 115200, + "arduino.plotRegex": "/^PLOT\\[(\\d+)\\]\\[(.+?)=(.+?)\\]/", } ``` *Note:* You only need to set `arduino.path` in Visual Studio Code settings, other options are not required. diff --git a/package.json b/package.json index 46a38a8c..40177024 100644 --- a/package.json +++ b/package.json @@ -484,6 +484,10 @@ "arduino.defaultBaudRate": { "type": "number", "default": 115200 + }, + "arduino.plotRegex": { + "type": "string", + "default": "^PLOT\\[(\\d+)\\]\\[(.+?)=(.+?)\\]" } } }, diff --git a/src/arduino/vscodeSettings.ts b/src/arduino/vscodeSettings.ts index a2fce5ab..12c1c10c 100644 --- a/src/arduino/vscodeSettings.ts +++ b/src/arduino/vscodeSettings.ts @@ -14,6 +14,7 @@ const configKeys = { IGNORE_BOARDS: "arduino.ignoreBoards", SKIP_HEADER_PROVIDER: "arduino.skipHeaderProvider", DEFAULT_BAUD_RATE: "arduino.defaultBaudRate", + PLOT_REGEX: "arduino.plotRegex", }; export interface IVscodeSettings { @@ -26,6 +27,7 @@ export interface IVscodeSettings { ignoreBoards: string[]; skipHeaderProvider: boolean; defaultBaudRate: number; + plotRegex: string; updateAdditionalUrls(urls: string | string[]): void; } @@ -81,6 +83,10 @@ export class VscodeSettings implements IVscodeSettings { return this.getConfigValue(configKeys.SKIP_HEADER_PROVIDER); } + public get plotRegex(): string { + return this.getConfigValue(configKeys.PLOT_REGEX); + } + public async updateAdditionalUrls(value) { await this.setConfigValue(configKeys.ADDITIONAL_URLS, value, true); } diff --git a/src/serialmonitor/serialPlotter.ts b/src/serialmonitor/serialPlotter.ts index 3307bc38..4f876d70 100644 --- a/src/serialmonitor/serialPlotter.ts +++ b/src/serialmonitor/serialPlotter.ts @@ -3,6 +3,7 @@ import * as vscode from "vscode"; import * as WebSocket from "ws"; import { SerialPortCtrl } from "./serialportctrl"; +import { VscodeSettings } from "../arduino/vscodeSettings"; interface IDataFrame { time?: number; @@ -68,7 +69,7 @@ export class SerialPlotter implements vscode.Disposable { } private handleSerialLine(line: string): void { - const match = line.match(/^PLOT\[(\d+)\]\[(.+?)=(.+?)\]/); + const match = line.match(new RegExp(VscodeSettings.getInstance().plotRegex)); if (!match) { return; From 9965bc309e3cf5591b2ca2f52675ef35e57e6c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Mon, 14 Jan 2019 18:56:59 +0300 Subject: [PATCH 14/35] add command to open serial plotter --- package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/package.json b/package.json index 40177024..008c7730 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "onCommand:arduino.showLibraryManager", "onCommand:arduino.showExamples", "onCommand:arduino.initialize", + "onCommand:arduino.openSerialPlotter", "onDebug" ], "main": "./out/src/extension", @@ -132,6 +133,10 @@ { "command": "arduino.showExamples", "title": "Arduino: Examples" + }, + { + "command": "arduino.openSerialPlotter", + "title": "Arduino: Open Serial Plotter" } ], "menus": { From 35c939c7dd67a4bab308e6ecc20c6c6344568e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Mon, 14 Jan 2019 19:33:15 +0300 Subject: [PATCH 15/35] add $ to the end of plot regex in the package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 008c7730..ac5df44d 100644 --- a/package.json +++ b/package.json @@ -492,7 +492,7 @@ }, "arduino.plotRegex": { "type": "string", - "default": "^PLOT\\[(\\d+)\\]\\[(.+?)=(.+?)\\]" + "default": "^PLOT\\[(\\d+)\\]\\[(.+?)=(.+?)\\]$" } } }, From ca204e22d530076773cf5483ea203d95969645f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Mon, 14 Jan 2019 19:33:25 +0300 Subject: [PATCH 16/35] update readme --- README.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 55df6d6d..0b642ca7 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ This extension provides several commands in the Command Palette (F1 o - **Arduino: Initialize**: Scaffold a VS Code project with an Arduino sketch. - **Arduino: Library Manager**: Explore and manage libraries. - **Arduino: Open Serial Monitor**: Open the serial monitor in the integrated output window. +- **Arduino: Open Serial Plotter**: Open the serial plotter. - **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. @@ -78,7 +79,7 @@ The following Visual Studio Code settings are available for the Arduino extensio "http://arduino.esp8266.com/stable/package_esp8266com_index.json" ], "arduino.defaultBaudRate": 115200, - "arduino.plotRegex": "/^PLOT\\[(\\d+)\\]\\[(.+?)=(.+?)\\]/", + "arduino.plotRegex": "^PLOT\\[(\\d+)\\]\\[(.+?)=(.+?)\\]$", } ``` *Note:* You only need to set `arduino.path` in Visual Studio Code settings, other options are not required. @@ -121,6 +122,36 @@ Steps to start debugging: > To learn more about how to debug Arduino code, visit our [team blog](https://blogs.msdn.microsoft.com/iotdev/2017/05/27/debug-your-arduino-code-with-visual-studio-code/). +## Using Serial Plotter + +You can start Serial Plotter by calling `Arduino: Open Serial Plotter` from Command Pallete. + +By default, it looks for lines in the following format in the serial input: `PLOT[time][variable=value]` + +For example, `PLOT[1234][cos=0.5]` means that we have variable named `cos` with it's value `0.5` in the time `1234`. + +You can use snippet below to print variables in such format. + +```c +void plot(String name, float value) +{ + String time = String(millis()); + Serial.println("PLOT[" + time + "][" + name + "=" + value + "]"); +} +``` + +Or you can override default regex to specify your own format, but the order will be remain the same: time, variable name, variable value. + +```json +{ + "arduino.plotRegex": "^(\\d+):(.+?)=(.+?)$" +} +``` + +``` + 1234:cos=0.5 +``` + ## Change Log See the [Change log](https://github.com/Microsoft/vscode-arduino/blob/master/CHANGELOG.md) for details about the changes in each version. From e35f71b6abc66b2d12163c2a1bf83932646b633f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Mon, 14 Jan 2019 23:09:03 +0300 Subject: [PATCH 17/35] use vscode `postMessage` instead of wss server --- src/arduino/arduinoContentProvider.ts | 14 ++++--- src/arduino/localWebServer.ts | 10 ----- src/extension.ts | 14 +++---- src/serialmonitor/serialMonitor.ts | 2 + src/serialmonitor/serialPlotter.ts | 22 +++++------ src/serialmonitor/serialPlotterPanel.ts | 46 ++++++++++++++++++++++ src/views/app/components/SerialPlotter.tsx | 28 +++++++------ 7 files changed, 88 insertions(+), 48 deletions(-) create mode 100644 src/serialmonitor/serialPlotterPanel.ts diff --git a/src/arduino/arduinoContentProvider.ts b/src/arduino/arduinoContentProvider.ts index 0fb5eb98..8de75a80 100644 --- a/src/arduino/arduinoContentProvider.ts +++ b/src/arduino/arduinoContentProvider.ts @@ -4,7 +4,6 @@ import * as path from "path"; import * as Uuid from "uuid/v4"; import * as vscode from "vscode"; -import * as WebSocket from "ws"; import ArduinoActivator from "../arduinoActivator"; import ArduinoContext from "../arduinoContext"; import * as Constants from "../common/constants"; @@ -60,10 +59,6 @@ export class ArduinoContentProvider implements vscode.TextDocumentContentProvide this._webserver.start(); } - public getWebSocketServer(): WebSocket.Server { - return this._webserver.getWebSocketServer(); - } - public async provideTextDocumentContent(uri: vscode.Uri): Promise { if (!ArduinoContext.initialized) { await ArduinoActivator.activate(); @@ -97,7 +92,14 @@ export class ArduinoContentProvider implements vscode.TextDocumentContentProvide "theme=" + encodeURIComponent(theme.trim()) + "&backgroundcolor=" + encodeURIComponent(backgroundcolor.trim()) + "&color=" + encodeURIComponent(color.trim()); - document.getElementById('frame').src = url; + + var iframe = document.getElementById('frame') + iframe.src = url; + + window.addEventListener('message', msg => { + var data = msg.data; + iframe.contentWindow.postMessage(data, url); + }) }; diff --git a/src/arduino/localWebServer.ts b/src/arduino/localWebServer.ts index 12bd6436..3d1f316c 100644 --- a/src/arduino/localWebServer.ts +++ b/src/arduino/localWebServer.ts @@ -5,19 +5,16 @@ import * as bodyParser from "body-parser"; import * as express from "express"; import * as http from "http"; import * as path from "path"; -import * as WebSocket from "ws"; export default class LocalWebServer { private app = express(); private server; - private wss; private _serverPort: string; constructor(private _extensionPath: string) { this.app.use("/", express.static(path.join(this._extensionPath, "./out/views"))); this.app.use(bodyParser.json()); this.server = http.createServer(this.app); - this.wss = new WebSocket.Server({ server: this.server }); } public getServerUrl(): string { @@ -26,9 +23,6 @@ export default class LocalWebServer { public getEndpointUri(type: string): string { return `http://localhost:${this._serverPort}/${type}`; } - public getWebSocketUri(): string { - return `ws://localhost:${this._serverPort}`; - } public addHandler(url: string, handler: (req, res) => void): void { this.app.get(url, handler); @@ -38,10 +32,6 @@ export default class LocalWebServer { this.app.post(url, handler); } - public getWebSocketServer(): WebSocket.Server { - return this.wss; - } - public start(): void { const port = this.server.listen(0).address().port; // tslint:disable-next-line diff --git a/src/extension.ts b/src/extension.ts index a62344cc..0c4b64aa 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -12,7 +12,7 @@ import ArduinoActivator from "./arduinoActivator"; import ArduinoContext from "./arduinoContext"; import { ARDUINO_CONFIG_FILE, ARDUINO_MANAGER_PROTOCOL, ARDUINO_MODE, BOARD_CONFIG_URI, BOARD_MANAGER_URI, EXAMPLES_URI, - LIBRARY_MANAGER_URI, SERIAL_PLOTTER_URI + LIBRARY_MANAGER_URI, SERIAL_PLOTTER_URI, } from "./common/constants"; import { validateArduinoPath } from "./common/platform"; import * as util from "./common/util"; @@ -23,6 +23,7 @@ import { CompletionProvider } from "./langService/completionProvider"; import * as Logger from "./logger/logger"; import { NSAT } from "./nsat"; import { SerialMonitor } from "./serialmonitor/serialMonitor"; +import { SerialPlotterPanel } from "./serialmonitor/serialPlotterPanel"; import { UsbDetector } from "./serialmonitor/usbDetector"; const status: any = {}; @@ -147,11 +148,11 @@ export async function activate(context: vscode.ExtensionContext) { }); registerArduinoCommand("arduino.showSerialPlotter", async () => { - const panel = vscode.window.createWebviewPanel("arduinoSerialPlotter", "Arduino Serial Plottter", vscode.ViewColumn.Two, { - enableScripts: true, - retainContextWhenHidden: true, - }); - panel.webview.html = await arduinoManagerProvider.provideTextDocumentContent(SERIAL_PLOTTER_URI); + const panelHtml = await arduinoManagerProvider.provideTextDocumentContent(SERIAL_PLOTTER_URI); + const panel = await SerialPlotterPanel.createOrShow(panelHtml); + const serialMonitor = SerialMonitor.getInstance(); + + serialMonitor.serialPlotter.setSendMessageFn(panel.postMessage.bind(panel)); }); // change board type @@ -289,7 +290,6 @@ export async function activate(context: vscode.ExtensionContext) { // serial monitor commands const serialMonitor = SerialMonitor.getInstance(); context.subscriptions.push(serialMonitor); - serialMonitor.serialPlotter.setWebSocketServer(arduinoManagerProvider.getWebSocketServer()); registerNonArduinoCommand("arduino.selectSerialPort", () => serialMonitor.selectSerialPort(null, null)); registerNonArduinoCommand("arduino.openSerialMonitor", () => serialMonitor.openSerialMonitor()); diff --git a/src/serialmonitor/serialMonitor.ts b/src/serialmonitor/serialMonitor.ts index 2195b914..cd2399b2 100644 --- a/src/serialmonitor/serialMonitor.ts +++ b/src/serialmonitor/serialMonitor.ts @@ -118,6 +118,8 @@ export class SerialMonitor implements vscode.Disposable { if (this._serialPortCtrl && this._serialPortCtrl.isActive) { return this._serialPortCtrl.stop(); } + + this._serialPlotter.dispose(); } public async selectSerialPort(vid: string, pid: string) { diff --git a/src/serialmonitor/serialPlotter.ts b/src/serialmonitor/serialPlotter.ts index 4f876d70..b073bfff 100644 --- a/src/serialmonitor/serialPlotter.ts +++ b/src/serialmonitor/serialPlotter.ts @@ -1,17 +1,18 @@ import * as throttle from "lodash.throttle"; import * as vscode from "vscode"; -import * as WebSocket from "ws"; -import { SerialPortCtrl } from "./serialportctrl"; import { VscodeSettings } from "../arduino/vscodeSettings"; +import { SerialPortCtrl } from "./serialportctrl"; interface IDataFrame { time?: number; [field: string]: number; } +type ISendMessage = (message: {}) => void; + export class SerialPlotter implements vscode.Disposable { - private _wss: WebSocket.Server; + private _sendMessage: ISendMessage; private _throttling: number = 100; private sendCurrentFrameThrottled; @@ -31,10 +32,11 @@ export class SerialPlotter implements vscode.Disposable { this.sendMessage({action: "RESET"}); } - public dispose() {} + public dispose() { + } - public setWebSocketServer(wss: WebSocket.Server) { - this._wss = wss; + public setSendMessageFn(sendMessage: ISendMessage) { + this._sendMessage = sendMessage; } public setSerialPortCtrl(serialPortCtrl: SerialPortCtrl) { @@ -57,15 +59,11 @@ export class SerialPlotter implements vscode.Disposable { } private sendMessage(msg: {}) { - if (!this._wss) { + if (!this._sendMessage) { return; } - this._wss.clients.forEach((client) => { - if (client.readyState === WebSocket.OPEN) { - client.send(JSON.stringify(msg)); - } - }); + this._sendMessage(msg); } private handleSerialLine(line: string): void { diff --git a/src/serialmonitor/serialPlotterPanel.ts b/src/serialmonitor/serialPlotterPanel.ts new file mode 100644 index 00000000..585b0459 --- /dev/null +++ b/src/serialmonitor/serialPlotterPanel.ts @@ -0,0 +1,46 @@ +import * as vscode from "vscode"; + +export class SerialPlotterPanel { + /** + * Track the currently panel. Only allow a single panel to exist at a time. + */ + public static currentPanel: SerialPlotterPanel | undefined; + + public static createOrShow(html: string): SerialPlotterPanel { + // If we already have a panel, show it. + if (SerialPlotterPanel.currentPanel) { + SerialPlotterPanel.currentPanel._panel.reveal(); + return SerialPlotterPanel.currentPanel; + } + + // Otherwise, create a new panel. + const panel = vscode.window.createWebviewPanel("arduinoSerialPlotter", "Arduino Serial Plottter", vscode.ViewColumn.Two, { + enableScripts: true, + retainContextWhenHidden: true, + }); + + panel.webview.html = html; + + SerialPlotterPanel.currentPanel = new SerialPlotterPanel(panel); + + return SerialPlotterPanel.currentPanel; + } + + private readonly _panel: vscode.WebviewPanel; + + private constructor(panel: vscode.WebviewPanel) { + this._panel = panel; + + this._panel.onDidDispose(() => this.dispose()); + } + + public postMessage(msg: {}): void { + this._panel.webview.postMessage(msg); + } + + public dispose(): void { + SerialPlotterPanel.currentPanel = undefined; + + this._panel.dispose(); + } +} diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx index 9af75e6e..05935cd8 100644 --- a/src/views/app/components/SerialPlotter.tsx +++ b/src/views/app/components/SerialPlotter.tsx @@ -27,10 +27,7 @@ interface ISerialPlotterState extends React.Props { active: boolean; } -class SerialPlotter extends React.Component< - void, - ISerialPlotterState -> { +class SerialPlotter extends React.Component { public state = { rate: "100", active: false, @@ -38,14 +35,13 @@ class SerialPlotter extends React.Component< private _chartRef: HTMLElement; private _chart: Highcharts; - private _ws: WebSocket; constructor(props) { super(props); } public componentDidMount() { - this.initWebSocket(); + this.initMessageHandler(); this.initChart(); } @@ -77,7 +73,15 @@ class SerialPlotter extends React.Component< - + @@ -141,22 +145,20 @@ class SerialPlotter extends React.Component< this._chart.redraw(); } - private initWebSocket() { - this._ws = new WebSocket(`ws://${window.location.host}`); + private initMessageHandler() { + window.addEventListener("message", (event) => { + const data = event.data; - this._ws.onmessage = (e: MessageEvent) => { if (!this.state.active) { return; } - const data = JSON.parse(e.data); - if (data.time) { this.addFrame(data); } else if (data.action) { this.doAction(data); } - }; + }); this.setState({ active: true, From d56fa34196f3202678c84ecf03a8de29c2494cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 17 Jan 2019 00:03:56 +0300 Subject: [PATCH 18/35] refactor code --- src/extension.ts | 7 +- src/serialmonitor/serialMonitor.ts | 6 +- src/serialmonitor/serialPlotter.ts | 85 ++++++++++++++++------ src/serialmonitor/serialPlotterPanel.ts | 26 +++---- src/views/app/components/SerialPlotter.tsx | 72 ++++++++++-------- 5 files changed, 123 insertions(+), 73 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 0c4b64aa..e545e168 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -148,11 +148,10 @@ export async function activate(context: vscode.ExtensionContext) { }); registerArduinoCommand("arduino.showSerialPlotter", async () => { - const panelHtml = await arduinoManagerProvider.provideTextDocumentContent(SERIAL_PLOTTER_URI); - const panel = await SerialPlotterPanel.createOrShow(panelHtml); - const serialMonitor = SerialMonitor.getInstance(); + const html = await arduinoManagerProvider.provideTextDocumentContent(SERIAL_PLOTTER_URI); + const serialPlotter = SerialMonitor.getInstance().serialPlotter; - serialMonitor.serialPlotter.setSendMessageFn(panel.postMessage.bind(panel)); + SerialPlotterPanel.createOrShow({serialPlotter, html}); }); // change board type diff --git a/src/serialmonitor/serialMonitor.ts b/src/serialmonitor/serialMonitor.ts index cd2399b2..5ab3dab6 100644 --- a/src/serialmonitor/serialMonitor.ts +++ b/src/serialmonitor/serialMonitor.ts @@ -115,11 +115,11 @@ export class SerialMonitor implements vscode.Disposable { } public dispose() { + this._serialPlotter.dispose(); + if (this._serialPortCtrl && this._serialPortCtrl.isActive) { return this._serialPortCtrl.stop(); } - - this._serialPlotter.dispose(); } public async selectSerialPort(vid: string, pid: string) { @@ -186,9 +186,9 @@ export class SerialMonitor implements vscode.Disposable { } try { + this._serialPlotter.reset(); await this._serialPortCtrl.open(); this.updatePortStatus(true); - this._serialPlotter.reset(); } catch (error) { Logger.notifyUserWarning("openSerialMonitorError", error, `Failed to open serial port ${this._currentPort} due to error: + ${error.toString()}`); diff --git a/src/serialmonitor/serialPlotter.ts b/src/serialmonitor/serialPlotter.ts index b073bfff..b4ea5924 100644 --- a/src/serialmonitor/serialPlotter.ts +++ b/src/serialmonitor/serialPlotter.ts @@ -4,24 +4,45 @@ import * as vscode from "vscode"; import { VscodeSettings } from "../arduino/vscodeSettings"; import { SerialPortCtrl } from "./serialportctrl"; -interface IDataFrame { +enum MessageType { + Frame = "Frame", + Action = "Action", +} + +enum Action { + Reset = "Reset", +} + +interface IMessage { + type: MessageType; +} + +interface IMessageFrame extends IMessage { + type: typeof MessageType.Frame; time?: number; - [field: string]: number; + [field: string]: string | number; +} + +interface IMessageAction extends IMessage { + type: typeof MessageType.Action; + action: Action; } -type ISendMessage = (message: {}) => void; +type ISendMessage = (message: IMessage) => void; export class SerialPlotter implements vscode.Disposable { - private _sendMessage: ISendMessage; - private _throttling: number = 100; - private sendCurrentFrameThrottled; + public static DEFAULT_THROTTLING: number = 100; + + private _throttling: number = SerialPlotter.DEFAULT_THROTTLING; + private _frame: IMessageFrame = null; + private _sendMessage: ISendMessage = null; - private _currentFrame: IDataFrame; - private _lastSentTime: number; + private disposableOnLineHandler: vscode.Disposable = null; + private sendFrame: () => void = null; constructor() { - this.setThrottling(this._throttling); - this._currentFrame = {}; + this.setThrottling(SerialPlotter.DEFAULT_THROTTLING); + this.emptyFrame(); } public open() { @@ -29,10 +50,20 @@ export class SerialPlotter implements vscode.Disposable { } public reset() { - this.sendMessage({action: "RESET"}); + this.setThrottling(SerialPlotter.DEFAULT_THROTTLING); + this.sendMessage({type: MessageType.Action, action: Action.Reset} as IMessageAction); + + this.emptyFrame(); } public dispose() { + this._sendMessage = undefined; + this._frame = undefined; + + if (this.disposableOnLineHandler) { + this.disposableOnLineHandler.dispose(); + this.disposableOnLineHandler = undefined; + } } public setSendMessageFn(sendMessage: ISendMessage) { @@ -40,25 +71,28 @@ export class SerialPlotter implements vscode.Disposable { } public setSerialPortCtrl(serialPortCtrl: SerialPortCtrl) { - serialPortCtrl.onLine(this.handleSerialLine.bind(this)); + if (this.disposableOnLineHandler) { + this.disposableOnLineHandler.dispose(); + } + + this.disposableOnLineHandler = serialPortCtrl.onLine(this.handleSerialLine.bind(this)); } public setThrottling(throttling: number): void { this._throttling = throttling; - this.sendCurrentFrameThrottled = throttle(this.sendCurrentFrame, this._throttling, { leading: false }); + this.sendFrame = throttle(this._sendFrame, this._throttling, { leading: false }); } - private sendCurrentFrame() { - if (this._lastSentTime >= this._currentFrame.time) { + private _sendFrame() { + if (!this._frame) { return; } - this.sendMessage(this._currentFrame); - this._lastSentTime = this._currentFrame.time; - this._currentFrame = {}; + this.sendMessage(this._frame); + this.emptyFrame(); } - private sendMessage(msg: {}) { + private sendMessage(msg: IMessage) { if (!this._sendMessage) { return; } @@ -75,12 +109,17 @@ export class SerialPlotter implements vscode.Disposable { const [, time, field, value] = match; - this._currentFrame = { - ...this._currentFrame, - [field]: parseFloat(value), + this._frame = { + ...this._frame, + type: MessageType.Frame, time: parseInt(time, 10), + [field]: parseFloat(value), }; - this.sendCurrentFrameThrottled(); + this.sendFrame(); + } + + private emptyFrame() { + this._frame = {type: MessageType.Frame}; } } diff --git a/src/serialmonitor/serialPlotterPanel.ts b/src/serialmonitor/serialPlotterPanel.ts index 585b0459..2a10d236 100644 --- a/src/serialmonitor/serialPlotterPanel.ts +++ b/src/serialmonitor/serialPlotterPanel.ts @@ -1,19 +1,16 @@ import * as vscode from "vscode"; +import {SerialPlotter} from "./serialPlotter"; export class SerialPlotterPanel { - /** - * Track the currently panel. Only allow a single panel to exist at a time. - */ - public static currentPanel: SerialPlotterPanel | undefined; + public static currentPanel: SerialPlotterPanel | void = null; + public static serialPlotter: SerialPlotter | void = null; - public static createOrShow(html: string): SerialPlotterPanel { - // If we already have a panel, show it. + public static createOrShow({html, serialPlotter}: {html: string, serialPlotter: SerialPlotter}): void { if (SerialPlotterPanel.currentPanel) { SerialPlotterPanel.currentPanel._panel.reveal(); - return SerialPlotterPanel.currentPanel; + return; } - // Otherwise, create a new panel. const panel = vscode.window.createWebviewPanel("arduinoSerialPlotter", "Arduino Serial Plottter", vscode.ViewColumn.Two, { enableScripts: true, retainContextWhenHidden: true, @@ -21,25 +18,26 @@ export class SerialPlotterPanel { panel.webview.html = html; + SerialPlotterPanel.serialPlotter = serialPlotter; SerialPlotterPanel.currentPanel = new SerialPlotterPanel(panel); - - return SerialPlotterPanel.currentPanel; } - private readonly _panel: vscode.WebviewPanel; + private readonly _panel: vscode.WebviewPanel = null; private constructor(panel: vscode.WebviewPanel) { this._panel = panel; this._panel.onDidDispose(() => this.dispose()); - } - public postMessage(msg: {}): void { - this._panel.webview.postMessage(msg); + if (SerialPlotterPanel.serialPlotter) { + SerialPlotterPanel.serialPlotter.setSendMessageFn((msg) => panel.webview.postMessage(msg)); + SerialPlotterPanel.serialPlotter.reset(); + } } public dispose(): void { SerialPlotterPanel.currentPanel = undefined; + SerialPlotterPanel.serialPlotter = undefined; this._panel.dispose(); } diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx index 05935cd8..7df83f2e 100644 --- a/src/views/app/components/SerialPlotter.tsx +++ b/src/views/app/components/SerialPlotter.tsx @@ -13,13 +13,28 @@ import { chartConfig } from "./chartConfig"; boost(Highcharts); -interface IDataFrame { - time: number; - [field: string]: number; +enum MessageType { + Frame = "Frame", + Action = "Action", } -interface IDataAction { - action: string; +enum Action { + Reset = "Reset", +} + +interface IMessage { + type: MessageType; +} + +interface IMessageFrame extends IMessage { + type: typeof MessageType.Frame; + time?: number; + [field: string]: string | number; +} + +interface IMessageAction extends IMessage { + type: typeof MessageType.Action; + action: Action; } interface ISerialPlotterState extends React.Props { @@ -28,17 +43,15 @@ interface ISerialPlotterState extends React.Props { } class SerialPlotter extends React.Component { + public static DEFAULT_THROTTLING = 100; + public state = { - rate: "100", + rate: SerialPlotter.DEFAULT_THROTTLING.toString(), active: false, }; - private _chartRef: HTMLElement; - private _chart: Highcharts; - - constructor(props) { - super(props); - } + private _chartRef: HTMLElement = null; + private _chart: Highcharts = null; public componentDidMount() { this.initMessageHandler(); @@ -94,11 +107,11 @@ class SerialPlotter extends React.Component { this._chart = Highcharts.stockChart(this._chartRef, chartConfig); } - private addFrame(frame: IDataFrame) { + private addFrame(frame: IMessageFrame) { const time = frame.time; for (const field of Object.keys(frame)) { - if (field === "time") { + if (field === "time" || field === "type") { continue; } @@ -119,8 +132,8 @@ class SerialPlotter extends React.Component { } } - private doAction(action: IDataAction) { - if (action.action === "RESET") { + private doAction(msg: IMessageAction) { + if (msg.action === Action.Reset) { this.reset(); } } @@ -138,25 +151,26 @@ class SerialPlotter extends React.Component { } private reset = () => { - while (this._chart.series.length > 0) { - this._chart.series[0].remove(false); - } - - this._chart.redraw(); + this.initChart(); } private initMessageHandler() { window.addEventListener("message", (event) => { - const data = event.data; - if (!this.state.active) { return; } - if (data.time) { - this.addFrame(data); - } else if (data.action) { - this.doAction(data); + const data: IMessage = event.data; + + switch (data.type) { + case MessageType.Frame: + this.addFrame(data as IMessageFrame); + break; + case MessageType.Action: + this.doAction(data as IMessageAction); + break; + default: + console.warn("Unknown message type", data); } }); @@ -165,14 +179,14 @@ class SerialPlotter extends React.Component { }); } - private updatePlotRefreshRate = async () => { + private updatePlotRefreshRate = () => { const rate = parseInt(this.state.rate, 10); if (!Number.isFinite(rate)) { return; } - await API.updatePlotRefreshRate(rate); + API.updatePlotRefreshRate(rate); } private onRateChange = (e) => { From a1805428a6433661e71b183f530496e13f5753a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 17 Jan 2019 00:22:39 +0300 Subject: [PATCH 19/35] fix message proxy --- src/arduino/arduinoContentProvider.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/arduino/arduinoContentProvider.ts b/src/arduino/arduinoContentProvider.ts index 8de75a80..1ec2cd14 100644 --- a/src/arduino/arduinoContentProvider.ts +++ b/src/arduino/arduinoContentProvider.ts @@ -93,13 +93,16 @@ export class ArduinoContentProvider implements vscode.TextDocumentContentProvide "&backgroundcolor=" + encodeURIComponent(backgroundcolor.trim()) + "&color=" + encodeURIComponent(color.trim()); - var iframe = document.getElementById('frame') - iframe.src = url; + var iframe = document.getElementById('frame'); + + iframe.onload = function() { + window.addEventListener('message', msg => { + var data = msg.data; + iframe.contentWindow.postMessage(data, url); + }) + } - window.addEventListener('message', msg => { - var data = msg.data; - iframe.contentWindow.postMessage(data, url); - }) + iframe.src = url; }; From d4fad269472617ecbc69ec878ab6cdc746c6ff01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 17 Jan 2019 00:55:00 +0300 Subject: [PATCH 20/35] styling --- src/views/app/components/SerialPlotter.tsx | 77 +++++++++------------- src/views/app/styles/board.scss | 29 +++++++- 2 files changed, 59 insertions(+), 47 deletions(-) diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx index 7df83f2e..e86c9e78 100644 --- a/src/views/app/components/SerialPlotter.tsx +++ b/src/views/app/components/SerialPlotter.tsx @@ -38,7 +38,7 @@ interface IMessageAction extends IMessage { } interface ISerialPlotterState extends React.Props { - rate: string; + rate: number; active: boolean; } @@ -46,7 +46,7 @@ class SerialPlotter extends React.Component { public static DEFAULT_THROTTLING = 100; public state = { - rate: SerialPlotter.DEFAULT_THROTTLING.toString(), + rate: SerialPlotter.DEFAULT_THROTTLING, active: false, }; @@ -60,44 +60,35 @@ class SerialPlotter extends React.Component { public render() { return ( -
+
(this._chartRef = el)} /> -
- - - Refresh rate - - - - - - - - - - - - - - - - - - +
+
+ Refresh rate + + +
+ +
+ + +
); @@ -180,13 +171,7 @@ class SerialPlotter extends React.Component { } private updatePlotRefreshRate = () => { - const rate = parseInt(this.state.rate, 10); - - if (!Number.isFinite(rate)) { - return; - } - - API.updatePlotRefreshRate(rate); + API.updatePlotRefreshRate(this.state.rate); } private onRateChange = (e) => { diff --git a/src/views/app/styles/board.scss b/src/views/app/styles/board.scss index eb42759d..30fdc7e8 100644 --- a/src/views/app/styles/board.scss +++ b/src/views/app/styles/board.scss @@ -215,4 +215,31 @@ a { .react-selector { width: 70%; } -} \ No newline at end of file +} + +.serialplotter { + .settings { + padding: 12px; + display: flex; + justify-content: space-between; + } + + .section { + display: grid; + grid-auto-columns: auto; + grid-auto-flow: column; + grid-gap: 6px; + align-items: baseline; + border: 1px solid white; + padding: 6px; + } + + .refresh-rate { + input { + width: 80px; + } + } + + .actions { + } +} From 2fa59089e728ed26578f4e6d26c17bd7d3a384c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 17 Jan 2019 01:11:21 +0300 Subject: [PATCH 21/35] fix typo --- src/serialmonitor/serialPlotterPanel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serialmonitor/serialPlotterPanel.ts b/src/serialmonitor/serialPlotterPanel.ts index 2a10d236..b562d819 100644 --- a/src/serialmonitor/serialPlotterPanel.ts +++ b/src/serialmonitor/serialPlotterPanel.ts @@ -11,7 +11,7 @@ export class SerialPlotterPanel { return; } - const panel = vscode.window.createWebviewPanel("arduinoSerialPlotter", "Arduino Serial Plottter", vscode.ViewColumn.Two, { + const panel = vscode.window.createWebviewPanel("arduinoSerialPlotter", "Arduino Serial Plotter", vscode.ViewColumn.Two, { enableScripts: true, retainContextWhenHidden: true, }); From 4916f26f82d910a84ca21e812991972434d15efc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 17 Jan 2019 01:11:28 +0300 Subject: [PATCH 22/35] update readme --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0b642ca7..2bd22a14 100644 --- a/README.md +++ b/README.md @@ -126,9 +126,9 @@ Steps to start debugging: You can start Serial Plotter by calling `Arduino: Open Serial Plotter` from Command Pallete. -By default, it looks for lines in the following format in the serial input: `PLOT[time][variable=value]` +By default, it looks for lines of the following format in the serial input: `PLOT[time][variable=value]` -For example, `PLOT[1234][cos=0.5]` means that we have variable named `cos` with it's value `0.5` in the time `1234`. +For example, `PLOT[1234][cos=0.5]` means that we have variable named `cos` with it's value `0.5` at the time `1234`. You can use snippet below to print variables in such format. @@ -140,7 +140,15 @@ void plot(String name, float value) } ``` -Or you can override default regex to specify your own format, but the order will be remain the same: time, variable name, variable value. +### Throttling (refresh rate) + +This Plotter is not working in real time. It's built using library [https://www.highcharts.com/](https://www.highcharts.com/) for creating interactive charts that's not superfast. + +Plotter accumulates data and flushes it to the chart with some periodicity that we will call `throttling` or `refresh rate`. By default it's 100ms, but you can change it as you want. This value was chosen empirically, lower values ​​can lead to noticable lags. + +### Override log format + +You can override default regex to specify your own format, but the order will be remain the same: time, variable name, variable value. ```json { @@ -148,9 +156,7 @@ Or you can override default regex to specify your own format, but the order will } ``` -``` - 1234:cos=0.5 -``` + ## Change Log See the [Change log](https://github.com/Microsoft/vscode-arduino/blob/master/CHANGELOG.md) for details about the changes in each version. From 611f41af309cabd1237fda4614d4ebcc9d17146f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 17 Jan 2019 01:14:53 +0300 Subject: [PATCH 23/35] remove extra new lines at readme --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 2bd22a14..9af9886e 100644 --- a/README.md +++ b/README.md @@ -156,8 +156,6 @@ You can override default regex to specify your own format, but the order will be } ``` - - ## Change Log See the [Change log](https://github.com/Microsoft/vscode-arduino/blob/master/CHANGELOG.md) for details about the changes in each version. From 10ccbfcdf0c4ada0858fcdbd1c5141faa19cf31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 17 Jan 2019 01:15:47 +0300 Subject: [PATCH 24/35] rename `plotRegex` to `plotterRegex` --- README.md | 4 ++-- package.json | 2 +- src/arduino/vscodeSettings.ts | 8 ++++---- src/serialmonitor/serialPlotter.ts | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9af9886e..16329e3f 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ The following Visual Studio Code settings are available for the Arduino extensio "http://arduino.esp8266.com/stable/package_esp8266com_index.json" ], "arduino.defaultBaudRate": 115200, - "arduino.plotRegex": "^PLOT\\[(\\d+)\\]\\[(.+?)=(.+?)\\]$", + "arduino.plotterRegex": "^PLOT\\[(\\d+)\\]\\[(.+?)=(.+?)\\]$", } ``` *Note:* You only need to set `arduino.path` in Visual Studio Code settings, other options are not required. @@ -152,7 +152,7 @@ You can override default regex to specify your own format, but the order will be ```json { - "arduino.plotRegex": "^(\\d+):(.+?)=(.+?)$" + "arduino.plotterRegex": "^(\\d+):(.+?)=(.+?)$" } ``` diff --git a/package.json b/package.json index ac5df44d..a4b6fe2c 100644 --- a/package.json +++ b/package.json @@ -490,7 +490,7 @@ "type": "number", "default": 115200 }, - "arduino.plotRegex": { + "arduino.plotterRegex": { "type": "string", "default": "^PLOT\\[(\\d+)\\]\\[(.+?)=(.+?)\\]$" } diff --git a/src/arduino/vscodeSettings.ts b/src/arduino/vscodeSettings.ts index 12c1c10c..f2a65384 100644 --- a/src/arduino/vscodeSettings.ts +++ b/src/arduino/vscodeSettings.ts @@ -14,7 +14,7 @@ const configKeys = { IGNORE_BOARDS: "arduino.ignoreBoards", SKIP_HEADER_PROVIDER: "arduino.skipHeaderProvider", DEFAULT_BAUD_RATE: "arduino.defaultBaudRate", - PLOT_REGEX: "arduino.plotRegex", + PLOTTER_REGEX: "arduino.plotterRegex", }; export interface IVscodeSettings { @@ -27,7 +27,7 @@ export interface IVscodeSettings { ignoreBoards: string[]; skipHeaderProvider: boolean; defaultBaudRate: number; - plotRegex: string; + plotterRegex: string; updateAdditionalUrls(urls: string | string[]): void; } @@ -83,8 +83,8 @@ export class VscodeSettings implements IVscodeSettings { return this.getConfigValue(configKeys.SKIP_HEADER_PROVIDER); } - public get plotRegex(): string { - return this.getConfigValue(configKeys.PLOT_REGEX); + public get plotterRegex(): string { + return this.getConfigValue(configKeys.PLOTTER_REGEX); } public async updateAdditionalUrls(value) { diff --git a/src/serialmonitor/serialPlotter.ts b/src/serialmonitor/serialPlotter.ts index b4ea5924..2af8674c 100644 --- a/src/serialmonitor/serialPlotter.ts +++ b/src/serialmonitor/serialPlotter.ts @@ -101,7 +101,7 @@ export class SerialPlotter implements vscode.Disposable { } private handleSerialLine(line: string): void { - const match = line.match(new RegExp(VscodeSettings.getInstance().plotRegex)); + const match = line.match(new RegExp(VscodeSettings.getInstance().plotterRegex)); if (!match) { return; From f74ec47323cb9d013b9c5e8a944ff6236ceb1c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 17 Jan 2019 01:16:52 +0300 Subject: [PATCH 25/35] remove unneeded `ws` package --- package-lock.json | 39 ++------------------------------------- package.json | 4 +--- 2 files changed, 3 insertions(+), 40 deletions(-) diff --git a/package-lock.json b/package-lock.json index 96de13c9..e9176c0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,12 +33,6 @@ "integrity": "sha512-HNXtUQQuW3ThO9DVfTNbdvClVr+8AZlNNa2pxk5qtEvObnT27qh0DdQXTN4h5PuTTGinxwXkRKXsllJxuAzGPw==", "dev": true }, - "@types/events": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-1.1.0.tgz", - "integrity": "sha512-y3bR98mzYOo0pAZuiLari+cQyiKk3UXRuT45h1RjhfeCzqkjaVsfZJNaxdgtk7/3tzOm1ozLTqEqMP3VbI48jw==", - "dev": true - }, "@types/mocha": { "version": "2.2.41", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.41.tgz", @@ -57,16 +51,6 @@ "integrity": "sha1-kdZxDlNtNFucmwF8V0z2qNpkxRg=", "dev": true }, - "@types/ws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-4.0.1.tgz", - "integrity": "sha512-J56Wn8j7ovzmlrkUSPXnVRH+YXUCGoVokiB49QIjz+yq0234guOrBvF/HHrqrJjnY4p5oq+q6xAxT/7An6SeWQ==", - "dev": true, - "requires": { - "@types/events": "*", - "@types/node": "*" - } - }, "accepts": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", @@ -394,11 +378,6 @@ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", "dev": true }, - "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -6685,7 +6664,8 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -7435,11 +7415,6 @@ "dev": true, "optional": true }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" - }, "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", @@ -8231,16 +8206,6 @@ "slide": "^1.1.5" } }, - "ws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-4.0.0.tgz", - "integrity": "sha512-QYslsH44bH8O7/W2815u5DpnCpXWpEK44FmaHffNwgJI4JMaSZONgPBTOfrxJ29mXKbXak+LsJ2uAkDTYq2ptQ==", - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - }, "xdg-basedir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", diff --git a/package.json b/package.json index a4b6fe2c..91a60825 100644 --- a/package.json +++ b/package.json @@ -550,7 +550,6 @@ "@types/mocha": "^2.2.32", "@types/node": "^6.0.40", "@types/winreg": "^1.2.30", - "@types/ws": "^4.0.1", "del": "^2.2.2", "eslint": "^3.19.0", "eslint-config-standard": "^10.2.1", @@ -585,7 +584,6 @@ "uuid": "^3.0.1", "vscode-extension-telemetry": "0.0.18", "winreg": "^1.2.3", - "winston": "^2.3.1", - "ws": "^4.0.0" + "winston": "^2.3.1" } } From 8314902fc0ed2f98db4f9b2c56f80aa3764a8058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 17 Jan 2019 01:24:07 +0300 Subject: [PATCH 26/35] refactor --- src/serialmonitor/serialMonitor.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/serialmonitor/serialMonitor.ts b/src/serialmonitor/serialMonitor.ts index 5ab3dab6..84ef51ae 100644 --- a/src/serialmonitor/serialMonitor.ts +++ b/src/serialmonitor/serialMonitor.ts @@ -51,7 +51,7 @@ export class SerialMonitor implements vscode.Disposable { private _endingStatusBar: vscode.StatusBarItem; - private _openPlotStatusBar: vscode.StatusBarItem; + private _plotterStatusBar: vscode.StatusBarItem; private _serialPortCtrl: SerialPortCtrl = null; @@ -100,11 +100,11 @@ export class SerialMonitor implements vscode.Disposable { this._endingStatusBar.tooltip = "Serial Port Line Ending"; this._endingStatusBar.text = `No line ending`; - this._openPlotStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.OPEN_SERIAL_PLOTTER); - this._openPlotStatusBar.command = "arduino.openSerialPlotter"; - this._openPlotStatusBar.tooltip = "Open Serial Plotter"; - this._openPlotStatusBar.text = "Plotter"; - this._openPlotStatusBar.show(); + this._plotterStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.OPEN_SERIAL_PLOTTER); + this._plotterStatusBar.command = "arduino.openSerialPlotter"; + this._plotterStatusBar.tooltip = "Open Serial Plotter"; + this._plotterStatusBar.text = "Plotter"; + this._plotterStatusBar.show(); } public get initialized(): boolean { return !!this._outputChannel; From 8e4d1ca33c4311505c0c1eacc4c1ec83cd8f9f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 17 Jan 2019 01:24:24 +0300 Subject: [PATCH 27/35] remove unneeded `prop-types` package --- src/views/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/views/package.json b/src/views/package.json index 6ceca880..32ef8b63 100644 --- a/src/views/package.json +++ b/src/views/package.json @@ -35,7 +35,6 @@ "svg-url-loader": "^2.0.2", "ts-loader": "^2.0.0", "webpack": "^2.2.1", - "highcharts": "^6.1.4", - "prop-types": "^15.6.0" + "highcharts": "^6.1.4" } } From 036be64769323c14f1bff2b28170da13ab88c5f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 17 Jan 2019 01:25:14 +0300 Subject: [PATCH 28/35] revert back empty dependencies at package.json --- src/views/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/views/package.json b/src/views/package.json index 32ef8b63..369d29f3 100644 --- a/src/views/package.json +++ b/src/views/package.json @@ -36,5 +36,6 @@ "ts-loader": "^2.0.0", "webpack": "^2.2.1", "highcharts": "^6.1.4" - } + }, + "dependencies": {} } From 11218af09d92dde49a4a90010694761242366fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 17 Jan 2019 10:53:32 +0300 Subject: [PATCH 29/35] update readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 16329e3f..4a7a831b 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,8 @@ void plot(String name, float value) ### Throttling (refresh rate) -This Plotter is not working in real time. It's built using library [https://www.highcharts.com/](https://www.highcharts.com/) for creating interactive charts that's not superfast. +This Plotter is not working in real time. It's built on top of web technologies +with [highcharts](https://www.highcharts.com/) library to create interactive chart, so it's pretty fast but not instant. Plotter accumulates data and flushes it to the chart with some periodicity that we will call `throttling` or `refresh rate`. By default it's 100ms, but you can change it as you want. This value was chosen empirically, lower values ​​can lead to noticable lags. From 2f319e12075d800ad08f88fb36f7d650765793a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Tue, 22 Jan 2019 18:26:36 +0300 Subject: [PATCH 30/35] use dygraphs instead of highcharts --- README.md | 6 +- package-lock.json | 13 ++ package.json | 1 + src/views/app/components/SerialPlotter.tsx | 222 ++++++++++++++------- src/views/app/styles/board.scss | 13 +- src/views/package-lock.json | 5 + src/views/package.json | 4 +- src/views/tsconfig.json | 8 +- 8 files changed, 200 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 4a7a831b..93d9b927 100644 --- a/README.md +++ b/README.md @@ -143,10 +143,14 @@ void plot(String name, float value) ### Throttling (refresh rate) This Plotter is not working in real time. It's built on top of web technologies -with [highcharts](https://www.highcharts.com/) library to create interactive chart, so it's pretty fast but not instant. +with [dygraphs](http://dygraphs.com/) library to create interactive chart, so it's pretty fast but not instant. Plotter accumulates data and flushes it to the chart with some periodicity that we will call `throttling` or `refresh rate`. By default it's 100ms, but you can change it as you want. This value was chosen empirically, lower values ​​can lead to noticable lags. +### Time window + +Data is recorded for a specified period of time called `Time window`. By default it's 20 seconds and you can also change it in the way you need. The greater the value, the more resources are required to render chart, and the more lags we have. + ### Override log format You can override default regex to specify your own format, but the order will be remain the same: time, variable name, variable value. diff --git a/package-lock.json b/package-lock.json index e9176c0c..00161258 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,19 @@ "integrity": "sha512-HNXtUQQuW3ThO9DVfTNbdvClVr+8AZlNNa2pxk5qtEvObnT27qh0DdQXTN4h5PuTTGinxwXkRKXsllJxuAzGPw==", "dev": true }, + "@types/dygraphs": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@types/dygraphs/-/dygraphs-1.1.8.tgz", + "integrity": "sha512-qoSvrmDb83ll0hM3ANs6x5Xa163osIKrstX6Vgg1l9A8HPz72IHEOY+4EPb6jW+B25i6NCR+Dv7O9D0p2m4b6A==", + "requires": { + "@types/google.visualization": "*" + } + }, + "@types/google.visualization": { + "version": "0.0.46", + "resolved": "https://registry.npmjs.org/@types/google.visualization/-/google.visualization-0.0.46.tgz", + "integrity": "sha512-zYOvek3Qxj64YDcft+cNIz9Vm4fp8vMt6p/uDPL+bhh7BgvU7CyEk33H4i2mFwW/o3WY+mLGuE4sXjghrPXJEg==" + }, "@types/mocha": { "version": "2.2.41", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.41.tgz", diff --git a/package.json b/package.json index 91a60825..b6bd9564 100644 --- a/package.json +++ b/package.json @@ -573,6 +573,7 @@ "webpack": "^2.2.1" }, "dependencies": { + "@types/dygraphs": "^1.1.8", "body-parser": "^1.16.1", "compare-versions": "^3.4.0", "eventemitter2": "^4.1.0", diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx index e86c9e78..df907dff 100644 --- a/src/views/app/components/SerialPlotter.tsx +++ b/src/views/app/components/SerialPlotter.tsx @@ -1,17 +1,9 @@ -import * as Highcharts from "highcharts/highstock"; -import * as boost from "highcharts/modules/boost"; import * as React from "react"; -import { - Button, - ControlLabel, - FormControl, - FormGroup, - InputGroup, -} from "react-bootstrap"; +import { Button, ControlLabel, FormControl, FormGroup } from "react-bootstrap"; import * as API from "../actions/api"; import { chartConfig } from "./chartConfig"; -boost(Highcharts); +import Dygraph from "dygraphs"; enum MessageType { Frame = "Frame", @@ -40,54 +32,99 @@ interface IMessageAction extends IMessage { interface ISerialPlotterState extends React.Props { rate: number; active: boolean; + timeWindow: number; } +const formatTime = (time: number) => { + const date = new Date(time); + + const hh = date.getUTCHours().toString().padStart(2, "0"); + const mm = date.getUTCMinutes().toString().padStart(2, "0"); + const ss = date.getUTCSeconds().toString().padStart(2, "0"); + const mss = date.getUTCMilliseconds().toString().padStart(3, "0"); + + return `${hh}:${mm}:${ss}.${mss}`; +}; + +const getFrameLabels = (msg: IMessageFrame) => + Object.keys(msg).filter((label) => !["time", "type"].includes(label)); + class SerialPlotter extends React.Component { - public static DEFAULT_THROTTLING = 100; + public static INITIAL_THROTTLING = 100; + public static INITIAL_TIME_WINDOW = 1000 * 20; public state = { - rate: SerialPlotter.DEFAULT_THROTTLING, + rate: SerialPlotter.INITIAL_THROTTLING, + timeWindow: SerialPlotter.INITIAL_TIME_WINDOW, active: false, }; - private _chartRef: HTMLElement = null; - private _chart: Highcharts = null; + private _graph: Dygraph = null; + private _data: number[][] = null; + private _lastValues: { [field: string]: number } = null; + private _labels: string[] = null; + private _timeWindow: number = SerialPlotter.INITIAL_TIME_WINDOW; + + private _ref: HTMLElement = null; public componentDidMount() { this.initMessageHandler(); this.initChart(); + + window.addEventListener("resize", this.handleResize, true); } public render() { return (
-
(this._chartRef = el)} /> +
+
(this._ref = el)} /> +
-
- Refresh rate - - +
+
+
+ + Refresh rate + + + + + Time window + + +
+ +
-
- - +
+
+ + +
@@ -95,32 +132,73 @@ class SerialPlotter extends React.Component { } private initChart() { - this._chart = Highcharts.stockChart(this._chartRef, chartConfig); + if (this._graph) { + this._graph.destroy(); + } + + this._labels = []; + this._graph = new Dygraph(this._ref, [[0, 0]], { + labels: this._labels, + legend: "always", + showRangeSelector: true, + connectSeparatedPoints: true, + drawGapEdgePoints: true, + axes: { + x: { + valueFormatter: formatTime, + axisLabelFormatter: formatTime, + }, + }, + }); + + this._data = []; + this._lastValues = {}; } - private addFrame(frame: IMessageFrame) { - const time = frame.time; + private getFrameValues(msg: IMessageFrame, labels: string[]) { + return labels.map((label) => { + const value = msg[label] as number; - for (const field of Object.keys(frame)) { - if (field === "time" || field === "type") { - continue; - } + if (typeof value !== "undefined") { + this._lastValues[label] = value; - const point = [time, frame[field]]; - const series = this._chart.get(field); - - if (series) { - series.addPoint(point, true, false, false); - } else { - this._chart.addSeries({ - id: field, - name: field, - data: [point], - color: getRandomColor(), - type: "line", - }); + return value; } + + return this._lastValues[label] || null; + }); + } + + private getDataTimeWindow(time: number) { + const start = Math.max(0, time - this._timeWindow); + const startIdx = this._data.findIndex((data) => data[0] > start); + const timeWindowData = this._data.slice(startIdx); + + return timeWindowData; + } + + private updateChart() { + this._graph.updateOptions({ + file: this._data, + labels: ["time", ...this._labels], + }); + } + + private addFrame(msg: IMessageFrame) { + if (!this._graph) { + return; } + + const labels = [...new Set([...this._labels, ...getFrameLabels(msg)])]; + const values = this.getFrameValues(msg, labels); + + const time = msg.time; + const frameData = [time, ...values]; + + this._data = [...this.getDataTimeWindow(time), frameData]; + this._labels = labels; + + this.updateChart(); } private doAction(msg: IMessageAction) { @@ -170,8 +248,17 @@ class SerialPlotter extends React.Component { }); } - private updatePlotRefreshRate = () => { + private applyPlotSettings = () => { API.updatePlotRefreshRate(this.state.rate); + + this._timeWindow = this.state.timeWindow; + + const lastData = this._data[this._data.length - 1]; + const lastTime = lastData[0]; + + this._data = this.getDataTimeWindow(lastTime); + + this.updateChart(); } private onRateChange = (e) => { @@ -179,15 +266,16 @@ class SerialPlotter extends React.Component { rate: e.target.value, }); } -} -export default SerialPlotter; + private onTimeWindowChange = (e) => { + this.setState({ + timeWindow: e.target.value, + }); + } -function getRandomColor(): string { - const letters = "0123456789ABCDEF"; - let color = "#"; - for (let i = 0; i < 6; i++) { - color += letters[Math.floor(Math.random() * 16)]; + private handleResize() { + (this._graph as any).resize(); } - return color; } + +export default SerialPlotter; diff --git a/src/views/app/styles/board.scss b/src/views/app/styles/board.scss index 30fdc7e8..85e59a9c 100644 --- a/src/views/app/styles/board.scss +++ b/src/views/app/styles/board.scss @@ -218,6 +218,12 @@ a { } .serialplotter { + padding: 12px; + + .graph { + width: 100% !important; + } + .settings { padding: 12px; display: flex; @@ -234,7 +240,12 @@ a { padding: 6px; } - .refresh-rate { + .parameters { + display: grid; + grid-auto-columns: auto; + grid-auto-flow: row; + grid-gap: 6px; + input { width: 80px; } diff --git a/src/views/package-lock.json b/src/views/package-lock.json index e5f2349a..edb45554 100644 --- a/src/views/package-lock.json +++ b/src/views/package-lock.json @@ -1221,6 +1221,11 @@ "domelementtype": "1" } }, + "dygraphs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/dygraphs/-/dygraphs-2.1.0.tgz", + "integrity": "sha1-L7/SyAPq0CMH3z+vjU3T71XLIHU=" + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", diff --git a/src/views/package.json b/src/views/package.json index 369d29f3..a455d411 100644 --- a/src/views/package.json +++ b/src/views/package.json @@ -37,5 +37,7 @@ "webpack": "^2.2.1", "highcharts": "^6.1.4" }, - "dependencies": {} + "dependencies": { + "dygraphs": "^2.1.0" + } } diff --git a/src/views/tsconfig.json b/src/views/tsconfig.json index 9def2d1d..cb71ceaa 100644 --- a/src/views/tsconfig.json +++ b/src/views/tsconfig.json @@ -7,9 +7,13 @@ "outDir": "out", "alwaysStrict": true, "sourceMap": true, - "rootDir": "." + "rootDir": ".", + "lib": [ + "dom", + "es2017" + ] }, "exclude": [ "node_modules" ] -} \ No newline at end of file +} From 6c318d4a2eb4f93d10b9e1d9eb9e8af3daff2e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Thu, 30 May 2019 11:58:42 +0300 Subject: [PATCH 31/35] fix arduino commands test --- test/extension.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/extension.test.ts b/test/extension.test.ts index 11750d31..185f6253 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -40,6 +40,7 @@ suite("Arduino: Extension Tests", () => { "arduino.showLibraryManager", "arduino.showBoardConfig", "arduino.showExamples", + "arduino.showSerialPlotter", "arduino.changeBoardType", "arduino.initialize", "arduino.addLibPath", From b987abbc63d2f237b801b45b0529852dc0b2b848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D1=80=D0=B5=D0=BD=D0=B8=D1=88=D0=B8=D0=BD?= Date: Fri, 31 May 2019 02:33:33 +0300 Subject: [PATCH 32/35] fix react component props type --- src/views/app/components/SerialPlotter.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx index df907dff..27082fcd 100644 --- a/src/views/app/components/SerialPlotter.tsx +++ b/src/views/app/components/SerialPlotter.tsx @@ -49,7 +49,7 @@ const formatTime = (time: number) => { const getFrameLabels = (msg: IMessageFrame) => Object.keys(msg).filter((label) => !["time", "type"].includes(label)); -class SerialPlotter extends React.Component { +class SerialPlotter extends React.Component, ISerialPlotterState> { public static INITIAL_THROTTLING = 100; public static INITIAL_TIME_WINDOW = 1000 * 20; From 86a9e48c1c586dad5d8c64d80d6453c1c570d0d6 Mon Sep 17 00:00:00 2001 From: nd0ut Date: Sun, 21 Jul 2019 18:03:35 +0300 Subject: [PATCH 33/35] remove highcharts from deps --- src/views/package-lock.json | 9 ++------- src/views/package.json | 3 --- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/views/package-lock.json b/src/views/package-lock.json index bd898790..f43878d0 100644 --- a/src/views/package-lock.json +++ b/src/views/package-lock.json @@ -1470,7 +1470,8 @@ "dygraphs": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/dygraphs/-/dygraphs-2.1.0.tgz", - "integrity": "sha1-L7/SyAPq0CMH3z+vjU3T71XLIHU=" + "integrity": "sha1-L7/SyAPq0CMH3z+vjU3T71XLIHU=", + "dev": true }, "ecc-jsbn": { "version": "0.1.2", @@ -2675,12 +2676,6 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, - "highcharts": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/highcharts/-/highcharts-6.2.0.tgz", - "integrity": "sha512-A4E89MA+kto8giic7zyLU6ZxfXnVeCUlKOyzFsah3+n4BROx4bgonl92KIBtwLud/mIWir8ahqhuhe2by9LakQ==", - "dev": true - }, "history": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/history/-/history-3.3.0.tgz", diff --git a/src/views/package.json b/src/views/package.json index a455d411..11e9ab76 100644 --- a/src/views/package.json +++ b/src/views/package.json @@ -35,9 +35,6 @@ "svg-url-loader": "^2.0.2", "ts-loader": "^2.0.0", "webpack": "^2.2.1", - "highcharts": "^6.1.4" - }, - "dependencies": { "dygraphs": "^2.1.0" } } From c60ad7336daa5affd0bdca12d081761e1ac1a49a Mon Sep 17 00:00:00 2001 From: Adi Azulay Date: Tue, 31 Aug 2021 13:55:38 -0700 Subject: [PATCH 34/35] fix merge conflict issues --- package-lock.json | 580 +--------------------------- package.json | 3 +- src/extension.ts | 13 +- src/serialmonitor/serialMonitor.ts | 22 +- src/serialmonitor/serialportctrl.ts | 15 +- src/views/package-lock.json | 21 +- src/views/package.json | 2 +- 7 files changed, 52 insertions(+), 604 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1e996870..045dadfb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -236,24 +236,24 @@ "compare-versions": "*" } }, + "@types/dygraphs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/dygraphs/-/dygraphs-2.1.0.tgz", + "integrity": "sha512-v61ndhl/F215QQVBJka4W2hpCAsmRY/TRMOeIq8fMBlGmnbvO7GNxD6DxC+vNS1lLaaZEqUsQbHkZsqg5cPh5w==", + "requires": { + "@types/google.visualization": "*" + } + }, "@types/fancy-log": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@types/fancy-log/-/fancy-log-1.3.0.tgz", "integrity": "sha512-mQjDxyOM1Cpocd+vm1kZBP7smwKZ4TNokFeds9LV7OZibmPJFEzY3+xZMrKfUdNT71lv8GoCPD6upKwHxubClw==", "dev": true }, - "@types/dygraphs": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@types/dygraphs/-/dygraphs-1.1.8.tgz", - "integrity": "sha512-qoSvrmDb83ll0hM3ANs6x5Xa163osIKrstX6Vgg1l9A8HPz72IHEOY+4EPb6jW+B25i6NCR+Dv7O9D0p2m4b6A==", - "requires": { - "@types/google.visualization": "*" - } - }, "@types/google.visualization": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@types/google.visualization/-/google.visualization-0.0.48.tgz", - "integrity": "sha512-dK6g23tPWwlWr4W50bk1cv0qhOes/GfPAqadnWdtA96GMqjXeDtb+sTIM3pCd0LxFuXtm4hTgGUOl9xuOoCDnA==" + "version": "0.0.68", + "resolved": "https://registry.npmjs.org/@types/google.visualization/-/google.visualization-0.0.68.tgz", + "integrity": "sha512-LkLniL1TYykhz+ZdRof3Bi8cp1OhqoK11Tj1RM2bPtGVBNexQ0eRnOrOWcWTdi80Sz9DzJ4JIG2rTlSJBVV58w==" }, "@types/mocha": { "version": "5.2.7", @@ -3751,548 +3751,14 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz", - "integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, "optional": true, "requires": { "bindings": "^1.5.0", - "nan": "^2.12.1", - "node-pre-gyp": "*" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "3.2.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.6.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.9.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.9.0" - } - }, - "mkdirp": { - "version": "0.5.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.14.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4.4.2" - } - }, - "nopt": { - "version": "4.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "readable-stream": { - "version": "2.3.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.7.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.1", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.13", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "optional": true - } + "nan": "^2.12.1" } }, "function-bind": { @@ -6208,6 +5674,11 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -6217,17 +5688,6 @@ "chalk": "^2.0.1" } }, - "lodash.throttle": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" - }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true - }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", diff --git a/package.json b/package.json index 0f725525..19a8ec91 100644 --- a/package.json +++ b/package.json @@ -527,7 +527,6 @@ "type": "number", "default": 115200 }, - "arduino.plotterRegex": { "type": "string", "default": "^PLOT\\[(\\d+)\\]\\[(.+?)=(.+?)\\]$" @@ -622,7 +621,7 @@ "webpack": "^4.44.1" }, "dependencies": { - "@types/dygraphs": "^1.1.8", + "@types/dygraphs": "2.1.0", "body-parser": "^1.16.1", "cocopa": "0.0.13", "compare-versions": "^3.4.0", diff --git a/src/extension.ts b/src/extension.ts index 18e751a1..58793649 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -117,13 +117,6 @@ export async function activate(context: vscode.ExtensionContext) { registerArduinoCommand("arduino.initialize", async () => await deviceContext.initialize()); - registerArduinoCommand("arduino.showSerialPlotter", async () => { - const html = await arduinoManagerProvider.provideTextDocumentContent(SERIAL_PLOTTER_URI); - const serialPlotter = SerialMonitor.getInstance().serialPlotter; - - SerialPlotterPanel.createOrShow({serialPlotter, html}); - }); - registerArduinoCommand("arduino.verify", async () => { if (!arduinoContextModule.default.arduinoApp.building) { await vscode.window.withProgress({ @@ -417,6 +410,12 @@ export async function activate(context: vscode.ExtensionContext) { arduinoContextModule.default.boardManager.currentBoard.name, }; }); + registerArduinoCommand("arduino.showSerialPlotter", async () => { + const html = await arduinoManagerProvider.provideTextDocumentContent(SERIAL_PLOTTER_URI); + const serialPlotter = SerialMonitor.getInstance().serialPlotter; + + SerialPlotterPanel.createOrShow({serialPlotter, html}); + }); }, 100); setTimeout(() => { diff --git a/src/serialmonitor/serialMonitor.ts b/src/serialmonitor/serialMonitor.ts index 7e78022f..2534bc35 100644 --- a/src/serialmonitor/serialMonitor.ts +++ b/src/serialmonitor/serialMonitor.ts @@ -48,6 +48,7 @@ export class SerialMonitor implements vscode.Disposable { private _baudRateStatusBar: vscode.StatusBarItem; + // TODO: Remove? private _endingStatusBar: vscode.StatusBarItem; private _plotterStatusBar: vscode.StatusBarItem; @@ -56,20 +57,8 @@ export class SerialMonitor implements vscode.Disposable { private _outputChannel: vscode.OutputChannel; - private _ending: SerialPortEnding; - private constructor() { this._serialPlotter = new SerialPlotter(); - - const dc = DeviceContext.getInstance(); - dc.onDidChange(() => { - if (dc.port) { - if (!this.initialized) { - this.initialize(); - } - this.updatePortListStatus(null); - } - }); } public initialize() { @@ -98,11 +87,10 @@ export class SerialMonitor implements vscode.Disposable { this._baudRateStatusBar.text = defaultBaudRate.toString(); this.updatePortListStatus(); - this._endingStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.ENDING); - this._ending = SerialMonitor.DEFAULT_ENDING; - this._endingStatusBar.command = "arduino.changeEnding"; - this._endingStatusBar.tooltip = "Serial Port Line Ending"; - this._endingStatusBar.text = `No line ending`; + // this._endingStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.ENDING); + // this._endingStatusBar.command = "arduino.changeEnding"; + // this._endingStatusBar.tooltip = "Serial Port Line Ending"; + // this._endingStatusBar.text = `No line ending`; this._plotterStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, constants.statusBarPriority.OPEN_SERIAL_PLOTTER); this._plotterStatusBar.command = "arduino.openSerialPlotter"; diff --git a/src/serialmonitor/serialportctrl.ts b/src/serialmonitor/serialportctrl.ts index 561c98b3..65c5f8af 100644 --- a/src/serialmonitor/serialportctrl.ts +++ b/src/serialmonitor/serialportctrl.ts @@ -3,11 +3,10 @@ import { ChildProcess, execFileSync, spawn } from "child_process"; import * as os from "os"; -import * as vscode from "vscode"; -import { OutputChannel, QuickPickItem, StatusBarAlignment, StatusBarItem, window } from "vscode"; -import { VscodeSettings } from "../arduino/vscodeSettings"; import * as path from "path"; +import * as vscode from "vscode"; import { OutputChannel } from "vscode"; +import { VscodeSettings } from "../arduino/vscodeSettings"; import { DeviceContext } from "../deviceContext"; interface ISerialPortDetail { @@ -65,14 +64,12 @@ export class SerialPortCtrl { private _currentPort: string; private _currentBaudRate: number; private _currentSerialPort = null; - private _ending: SerialPortEnding; private _lineEmitter: vscode.EventEmitter; private _lineBuffer: Buffer; public constructor(port: string, baudRate: number, private _outputChannel: OutputChannel) { this._currentBaudRate = baudRate; this._currentPort = port; - this._ending = ending; this._lineEmitter = new vscode.EventEmitter(); this._lineBuffer = Buffer.alloc(0); } @@ -111,8 +108,8 @@ export class SerialPortCtrl { this._child.stdout.on("data", (data) => { const jsonObj = JSON.parse(data.toString()) this._outputChannel.append(jsonObj["payload"] + "\n"); - - this.readLines(_event).forEach((line) => this._lineEmitter.fire(line)); + + this.readLines(jsonObj["payload"]).forEach((line) => this._lineEmitter.fire(line)); }); // TODO: add message check to ensure _child spawned without errors resolve(); @@ -200,10 +197,6 @@ export class SerialPortCtrl { }); } - public changeEnding(newEnding: SerialPortEnding) { - this._ending = newEnding; - } - private readLines(buf: Buffer): string[] { this._lineBuffer = Buffer.concat([this._lineBuffer, buf]); diff --git a/src/views/package-lock.json b/src/views/package-lock.json index b942f56f..76ef1209 100644 --- a/src/views/package-lock.json +++ b/src/views/package-lock.json @@ -21,6 +21,21 @@ } } }, + "@types/dygraphs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@types/dygraphs/-/dygraphs-2.1.3.tgz", + "integrity": "sha512-EYPByx1ziEgeoQJLWf/bmMNtjOQFw41Y5QMBWaYxb46eKhW1uP9ulDIZI1jY576e7Up+ECzp0uvpYpWKhoOBFA==", + "dev": true, + "requires": { + "@types/google.visualization": "*" + } + }, + "@types/google.visualization": { + "version": "0.0.68", + "resolved": "https://registry.npmjs.org/@types/google.visualization/-/google.visualization-0.0.68.tgz", + "integrity": "sha512-LkLniL1TYykhz+ZdRof3Bi8cp1OhqoK11Tj1RM2bPtGVBNexQ0eRnOrOWcWTdi80Sz9DzJ4JIG2rTlSJBVV58w==", + "dev": true + }, "@types/history": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@types/history/-/history-3.2.4.tgz", @@ -1622,12 +1637,6 @@ "domelementtype": "1" } }, - "dygraphs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/dygraphs/-/dygraphs-2.1.0.tgz", - "integrity": "sha1-L7/SyAPq0CMH3z+vjU3T71XLIHU=", - "dev": true - }, "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", diff --git a/src/views/package.json b/src/views/package.json index f66d0071..b8fd24ad 100644 --- a/src/views/package.json +++ b/src/views/package.json @@ -34,7 +34,7 @@ "style-loader": "^0.13.1", "svg-url-loader": "^2.0.2", "ts-loader": "^4.5.0", - "webpack": "^4.44.1" + "webpack": "^4.44.1", "dygraphs": "^2.1.0" }, "dependencies": {} From e492275af80a4004e4601de87c130aa43d73cc44 Mon Sep 17 00:00:00 2001 From: Adi Azulay Date: Tue, 31 Aug 2021 14:07:24 -0700 Subject: [PATCH 35/35] fix linting errors --- src/arduino/arduinoContentProvider.ts | 2 +- src/arduino/vscodeSettings.ts | 2 +- src/serialmonitor/serialPlotterPanel.ts | 2 +- src/views/app/components/SerialPlotter.tsx | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/arduino/arduinoContentProvider.ts b/src/arduino/arduinoContentProvider.ts index 6d5a67f5..8f93d544 100644 --- a/src/arduino/arduinoContentProvider.ts +++ b/src/arduino/arduinoContentProvider.ts @@ -97,7 +97,7 @@ export class ArduinoContentProvider implements vscode.TextDocumentContentProvide window.addEventListener('message', msg => { var data = msg.data; iframe.contentWindow.postMessage(data, url); - }) + }) } iframe.src = url; diff --git a/src/arduino/vscodeSettings.ts b/src/arduino/vscodeSettings.ts index d324e506..b7d00c17 100644 --- a/src/arduino/vscodeSettings.ts +++ b/src/arduino/vscodeSettings.ts @@ -97,7 +97,7 @@ export class VscodeSettings implements IVscodeSettings { public get skipHeaderProvider(): boolean { return this.getConfigValue(configKeys.SKIP_HEADER_PROVIDER); } - + public get plotterRegex(): string { return this.getConfigValue(configKeys.PLOTTER_REGEX); } diff --git a/src/serialmonitor/serialPlotterPanel.ts b/src/serialmonitor/serialPlotterPanel.ts index b562d819..759aab0e 100644 --- a/src/serialmonitor/serialPlotterPanel.ts +++ b/src/serialmonitor/serialPlotterPanel.ts @@ -1,5 +1,5 @@ import * as vscode from "vscode"; -import {SerialPlotter} from "./serialPlotter"; +import { SerialPlotter } from "./serialPlotter"; export class SerialPlotterPanel { public static currentPanel: SerialPlotterPanel | void = null; diff --git a/src/views/app/components/SerialPlotter.tsx b/src/views/app/components/SerialPlotter.tsx index 27082fcd..7924bc44 100644 --- a/src/views/app/components/SerialPlotter.tsx +++ b/src/views/app/components/SerialPlotter.tsx @@ -239,7 +239,8 @@ class SerialPlotter extends React.Component, ISerialPlotterSta this.doAction(data as IMessageAction); break; default: - console.warn("Unknown message type", data); + // TODO: Add warning back in not in console + // console.warn("Unknown message type", data); } });