diff --git a/README.md b/README.md index dcd8041..c7798c7 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ Demo of a P300-controlled turret. ## Setting Up 1. Clone this repo locally. -2. run "npm start" and wait. +2. Run neurostack client locally on port :8002 +3. run "npm run robotserver" +4. in a new terminal, run "npm start" and wait. ## Developer Notes diff --git a/package-lock.json b/package-lock.json index f62754c..4879484 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1016,6 +1016,137 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" }, + "@serialport/binding-abstract": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@serialport/binding-abstract/-/binding-abstract-8.0.6.tgz", + "integrity": "sha512-1swwUVoRyQ9ubxrkJ8JPppykohUpTAP4jkGr36e9NjbVocSPfqeX6tFZFwl/IdUlwJwxGdbKDqq7FvXniCQUMw==", + "requires": { + "debug": "^4.1.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "@serialport/binding-mock": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-8.0.6.tgz", + "integrity": "sha512-BIbY5/PsDDo0QWDNCCxDgpowAdks+aZR8BOsEtK2GoASTTcJCy1fBwPIfH870o7rnbH901wY3C+yuTfdOvSO9A==", + "requires": { + "@serialport/binding-abstract": "^8.0.6", + "debug": "^4.1.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "@serialport/bindings": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@serialport/bindings/-/bindings-8.0.6.tgz", + "integrity": "sha512-4raWw8U2Qz9vhcPZP7DZamRZW+KEIFjf4FpoJTV85lW+Bzjd52wWmVuUBJNo54m4R8g0f6yXLP+/7/FsKM3opA==", + "requires": { + "@serialport/binding-abstract": "^8.0.6", + "@serialport/parser-readline": "^8.0.6", + "bindings": "^1.5.0", + "debug": "^4.1.1", + "nan": "^2.14.0", + "prebuild-install": "^5.3.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "@serialport/parser-byte-length": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@serialport/parser-byte-length/-/parser-byte-length-8.0.6.tgz", + "integrity": "sha512-92mrFxFEvq3gRvSM7ANK/jfbmHslz91a5oYJy/nbSn4H/MCRXjxR2YOkQgVXuN+zLt+iyDoW3pcOP4Sc1nWdqQ==" + }, + "@serialport/parser-cctalk": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@serialport/parser-cctalk/-/parser-cctalk-8.0.6.tgz", + "integrity": "sha512-pqtCYQPgxnxHygiXUPCfgX7sEx+fdR/ObjpscidynEULUq2fFrC5kBkrxRbTfHRtTaU2ii9DyjFq0JVRCbhI0Q==" + }, + "@serialport/parser-delimiter": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@serialport/parser-delimiter/-/parser-delimiter-8.0.6.tgz", + "integrity": "sha512-ogKOcPisPMlVtirkuDu3SFTF0+xT0ijxoH7XjpZiYL41EVi367MwuCnEmXG+dEKKnF0j9EPqOyD2LGSJxaFmhQ==" + }, + "@serialport/parser-readline": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@serialport/parser-readline/-/parser-readline-8.0.6.tgz", + "integrity": "sha512-OYBT2mpczh9QUI3MTw8j0A0tIlPVjpVipvuVnjRkYwxrxPeq04RaLFhaDpuRzua5rTKMt89c1y3btYeoDXMjAA==", + "requires": { + "@serialport/parser-delimiter": "^8.0.6" + } + }, + "@serialport/parser-ready": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@serialport/parser-ready/-/parser-ready-8.0.6.tgz", + "integrity": "sha512-xcEqv4rc119WR5JzAuu8UeJOlAwET2PTdNb6aIrrLlmTxhvuBbuRFcsnF3BpH9jUL30Kh7a6QiNXIwVG+WR/1Q==" + }, + "@serialport/parser-regex": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@serialport/parser-regex/-/parser-regex-8.0.6.tgz", + "integrity": "sha512-J8KY75Azz5ZyExmyM5YfUxbXOWBkZCytKgCCmZ966ttwZS0bUZOuoCaZj2Zp4VILJAiLuxHoqc0foi67Fri5+g==" + }, + "@serialport/stream": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@serialport/stream/-/stream-8.0.6.tgz", + "integrity": "sha512-ym1PwM0rwLrj90vRBB66I1hwMXbuMw9wGTxqns75U3N/tuNFOH85mxXaYVF2TpI66aM849NoI1jMm50fl9equg==", + "requires": { + "debug": "^4.1.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "@svgr/babel-plugin-add-jsx-attribute": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz", @@ -1731,6 +1862,49 @@ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -2641,11 +2815,38 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "optional": true, "requires": { "file-uri-to-path": "1.0.0" } }, + "bl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz", + "integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==", + "requires": { + "readable-stream": "^3.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, "blob": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", @@ -3982,6 +4183,11 @@ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", @@ -4604,6 +4810,14 @@ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, + "decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "requires": { + "mimic-response": "^2.0.0" + } + }, "deep-equal": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", @@ -4773,6 +4987,11 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -4800,6 +5019,11 @@ "repeating": "^2.0.0" } }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, "detect-newline": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", @@ -5851,6 +6075,11 @@ "fill-range": "^2.1.0" } }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, "expect": { "version": "23.6.0", "resolved": "https://registry.npmjs.org/expect/-/expect-23.6.0.tgz", @@ -6344,8 +6573,7 @@ "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "optional": true + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" }, "filename-regex": { "version": "2.0.1", @@ -6866,6 +7094,11 @@ } } }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "fs-extra": { "version": "0.30.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", @@ -7385,6 +7618,36 @@ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "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" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -7421,6 +7684,11 @@ "assert-plus": "^1.0.0" } }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -7633,6 +7901,11 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -10380,6 +10653,11 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" }, + "mimic-response": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.0.0.tgz", + "integrity": "sha512-8ilDoEapqA4uQ3TwS0jakGONKXVJqpy+RpM+3b7pLdOjghCrEiGp9SRkFbUHAmZW9vdnrENWHjaweIoTIJExSQ==" + }, "mini-css-extract-plugin": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz", @@ -10568,8 +10846,7 @@ "nan": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "optional": true + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" }, "nanomatch": { "version": "1.2.13", @@ -10606,6 +10883,11 @@ } } }, + "napi-build-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz", + "integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -10634,6 +10916,14 @@ "lower-case": "^1.1.1" } }, + "node-abi": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.13.0.tgz", + "integrity": "sha512-9HrZGFVTR5SOu3PZAnAY2hLO36aW1wmA+FDsVkr85BTST32TLCA1H/AEcatVRAsWLyXS3bqUDYCAjq5/QGuSTA==", + "requires": { + "semver": "^5.4.1" + } + }, "node-forge": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", @@ -10757,6 +11047,11 @@ } } }, + "noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -10794,6 +11089,17 @@ "path-key": "^2.0.0" } }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, "nth-check": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", @@ -13220,6 +13526,28 @@ "uniq": "^1.0.1" } }, + "prebuild-install": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.3.tgz", + "integrity": "sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==", + "requires": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + } + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -14923,6 +15251,38 @@ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==" }, + "serialport": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/serialport/-/serialport-8.0.6.tgz", + "integrity": "sha512-TDdP374kZ4+iYKqZbx47eSnJEMoQQfZwztAikWFjZORU1HokOSc3KVuyACy1yX2cVK6u+3C7PmBK3N31CLxMWg==", + "requires": { + "@serialport/binding-mock": "^8.0.6", + "@serialport/bindings": "^8.0.6", + "@serialport/parser-byte-length": "^8.0.6", + "@serialport/parser-cctalk": "^8.0.6", + "@serialport/parser-delimiter": "^8.0.6", + "@serialport/parser-readline": "^8.0.6", + "@serialport/parser-ready": "^8.0.6", + "@serialport/parser-regex": "^8.0.6", + "@serialport/stream": "^8.0.6", + "debug": "^4.1.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", @@ -15076,6 +15436,21 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, + "simple-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", + "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" + }, + "simple-get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", + "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "requires": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -15953,6 +16328,49 @@ "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" }, + "tar-fs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz", + "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==", + "requires": { + "chownr": "^1.1.1", + "mkdirp": "^0.5.1", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, + "tar-stream": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz", + "integrity": "sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==", + "requires": { + "bl": "^3.0.0", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, "terser": { "version": "3.17.0", "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", @@ -17248,6 +17666,19 @@ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, + "which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/package.json b/package.json index 952c11c..8146624 100644 --- a/package.json +++ b/package.json @@ -9,17 +9,18 @@ "react": "^16.5.2", "react-dom": "^16.5.2", "react-scripts": "^2.1.8", + "serialport": "^8.0.6", "socket.io": "2.1.1", "uuid": "^3.3.2", "wait-on": "^3.3.0" }, "scripts": { - "prestart": "npm install", "start": "concurrently \"react-scripts start\" \"wait-on http://localhost:3000 && electron . \"", "build": "react-scripts build", "pretest": "npm install && eslint . --fix", "test": "react-scripts test --env=jsdom", - "eject": "react-scripts eject" + "eject": "react-scripts eject", + "robotserver": "node robotServer.js COM6" }, "browserslist": [ ">0.2%", diff --git a/robotServer.js b/robotServer.js new file mode 100644 index 0000000..b0b3b89 --- /dev/null +++ b/robotServer.js @@ -0,0 +1,27 @@ +const SerialPort = require("serialport"); +const Readline = require('@serialport/parser-readline'); +const io = require('socket.io')(8003) // FileServer will be run on http://localhost:8003 + +let portName = process.argv[2]; + +let myPort; + +try{ + myPort = new SerialPort(portName, { + baudRate:9600 + }); + + myPort.on('open', ()=>{console.log('Robot port open')}); +} catch(err) { + console.log("Turret port unable to open: ", portName); +} + +io.on('connection', (socket) => { + socket.on('data', data => { + console.log("Received: ", data); + if(myPort){ + myPort.write(data); + myPort.write('d'); + } + }); +}); diff --git a/src/components/App/App.js b/src/components/App/App.js index 1a1fb32..3c56201 100644 --- a/src/components/App/App.js +++ b/src/components/App/App.js @@ -19,8 +19,6 @@ export default class App extends React.Component { btnStates: Array(Arrows.BTN_VALS.length).fill("notSelected") }; this.update = this.update.bind(this); - this.handleKeyChosen = this.handleKeyChosen.bind(this); - this.handleKeyNotChosen = this.handleKeyNotChosen.bind(this); } componentDidMount() { @@ -42,8 +40,9 @@ export default class App extends React.Component { this.setBtnState(curBtnIndex, "selected"); const curKey = Arrows.BTN_VALS[curBtnIndex]; this.props.updateCallback(curKey, (args) => { + this.props.handleData(args); if(this.props.isChosen(curKey, args)){ - this.setBtnState(curBtnIndex, "chosen"); + this.setBtnState(Arrows.BTN_VALS().findIndex(curKey), "chosen"); this.props.handleSelection(curKey, args); this.shuffleOrder(); } else { @@ -64,23 +63,6 @@ export default class App extends React.Component { // HELPERS // - // Set the current key as highlighted and return it's index - selectCurrentKey(){ - const curBtnIndex = this.getCurBtnIndex(); - this.setBtnState(curBtnIndex, "selected"); - return curBtnIndex; - } - - handleKeyChosen(){ - let curBtnIndex = this.selectCurrentKey(); - this.setBtnState(curBtnIndex, "chosen"); - this.shuffleOrder(); - } - - handleKeyNotChosen(){ - this.updateCurIndices(); - } - resetKeys() { const btnStates = Array(Arrows.BTN_VALS.length).fill("notSelected"); this.setState({btnStates}) @@ -142,6 +124,7 @@ App.propTypes = { updateCallback: PropTypes.func.isRequired, isChosen: PropTypes.func.isRequired, handleSelection: PropTypes.func.isRequired, + handleData: PropTypes.func.isRequired, goBack: PropTypes.func.isRequired, children: PropTypes.node }; \ No newline at end of file diff --git a/src/components/KeyComponent/ArrowComponent.js b/src/components/KeyComponent/ArrowComponent.js index 0b0d712..5d84783 100644 --- a/src/components/KeyComponent/ArrowComponent.js +++ b/src/components/KeyComponent/ArrowComponent.js @@ -3,17 +3,11 @@ import Key from './KeyComponent'; import PropTypes from 'prop-types'; class Arrows extends Component { - static get BTN_VALS() { return ["↖", "↑", "↗", "←", "o", "→"] } - static get BTN_ANGLES() { - return [45, 90, 135, - 180, 90, 0] - } - static get ROWS() { return [[0,1,2], [3,4,5]] } @@ -22,6 +16,18 @@ class Arrows extends Component { return [[0,3], [1,4], [2,5]] } + static ANGLE(arrow) { + let arrowAngles = { + "↖" : 135, + "↑" : 90, + "↗" : 45, + "←" : 180, + "o" : -1, + "→" : 0 + }; + return arrowAngles[arrow]; + } + render() { return (
diff --git a/src/containers/Training/Training.js b/src/containers/Training/Training.js index 28c3de4..73bcc16 100644 --- a/src/containers/Training/Training.js +++ b/src/containers/Training/Training.js @@ -1,12 +1,9 @@ import React from 'react'; import { getNextInstrPause } from '../../helpers/intervals'; -import { sendTrainingFlashEvent, masterUUID } from '../../helpers/P300Communication'; -import Sockets from "../../helpers/getSockets"; +import { sendTrainingFlashEvent, masterUUID } from '../../helpers/SocketCommunication'; import App from '../../components/App/App'; import './Training.css'; import PropTypes from 'prop-types'; - -const client_socket = (new Sockets()).client_socket; export default class Training extends React.Component { constructor(props) { super(props); @@ -17,37 +14,19 @@ export default class Training extends React.Component { accuracy: undefined }; this.statement = '↖↑↖↑→'; - this.trainingCompleted = this.trainingCompleted.bind(this); - this.updateAccuracy = this.updateAccuracy.bind(this); - this.onUpdate = this.onUpdate.bind(this); - } - - onUpdate(selectedKey, handleChosen, handleNotChosen){ - const curGoal = this.statement[this.state.lettersFound]; - let P300 = selectedKey === curGoal; - sendTrainingFlashEvent(client_socket, masterUUID(), P300 ? 1 : 0, this.updateAccuracy); - if(P300){ - handleChosen(); - const newDisplay = this.state.displayText + selectedKey; - this.setState({ - displayText : newDisplay, - lettersFound : this.state.lettersFound + 1, - }); - if (this.state.lettersFound === this.statement.length) { - this.trainingCompleted(); - } - } else { - handleNotChosen(); - } + this.handleData = this.handleData.bind(this); + this.handleSelection = this.handleSelection.bind(this); + this.isP300 = this.isP300.bind(this); } render() { return ( - sendTrainingFlashEvent(client_socket, masterUUID(), this.isP300(selection), handleResponse)} + sendTrainingFlashEvent(masterUUID(), this.isP300(selection), handleResponse)} isChosen={(selection) => this.isP300(selection)} handleSelection={(selection) => {this.handleSelection(selection)}} + handleData={this.handleData} goBack={this.props.goBack} >
@@ -60,20 +39,14 @@ export default class Training extends React.Component { ) } - // HELPERS // - - // data is return value from Neurostack Client train event - updateAccuracy(data){ - console.log("here", data) + // Neurostack client callback + handleData(data) { if (data.acc) { this.setState({accuracy: data.acc}); } } - - trainingCompleted(){ - setTimeout(this.props.goBack, getNextInstrPause()); - } + // Key is selected handleSelection(selection){ const newDisplay = this.state.displayText + selection; this.setState({ @@ -84,6 +57,7 @@ export default class Training extends React.Component { setTimeout(this.props.goBack, getNextInstrPause()); } } + isP300(curKey) { const curGoal = this.statement[this.state.lettersFound]; return curKey === curGoal; diff --git a/src/containers/Turret/Turret.js b/src/containers/Turret/Turret.js index 4c676d0..6896f21 100644 --- a/src/containers/Turret/Turret.js +++ b/src/containers/Turret/Turret.js @@ -1,29 +1,28 @@ import React from 'react'; -import App from "../../components/App/App" -import Sockets from "../../helpers/getSockets"; -import { sendPredictionEvent, masterUUID } from '../../helpers/P300Communication'; +import App from "../../components/App/App"; +import Arrows from "../../components/KeyComponent/ArrowComponent"; +import { sendPredictionEvent, masterUUID, moveTurret } from '../../helpers/SocketCommunication'; import './Turret.css'; import PropTypes from 'prop-types'; -const client_socket = (new Sockets()).client_socket; - export default class Turret extends React.Component { constructor(props) { super(props); this.state = { displayText: "" }; - this.handlePrediction = this.handlePrediction.bind(this); + this.handleData = this.handleData.bind(this); + this.handleSelection = this.handleSelection.bind(this); } render() { return ( - sendPredictionEvent(client_socket, masterUUID(), handleResponse)} + sendPredictionEvent(selection, masterUUID(), handleResponse)} isChosen={(selection, args) => args['p300']} - handleSelection={(selection, args) => { - console.log("P300 for key: " + selection + " with score: " + args['score'])}} + handleSelection={this.handleSelection} + handleData={this.handleData} goBack={this.props.goBack} >

Try to select a direction using your brain!

@@ -34,19 +33,26 @@ export default class Turret extends React.Component { // HELPERS // - // data is return value from Neurostack Client predict event - handlePrediction(data, selectedKey, handleChosen, handleNotChosen){ - if(data.p300){ - console.log(selectedKey, " chosen. confidence: ", data.score*100, "%"); - const newDisplay = this.state.displayText + selectedKey; - this.setState({ - displayText : newDisplay - }); - handleChosen(); + // Neurostack client callback + handleData(){ + } + + // key is selected + handleSelection(selection, args){ + console.log("P300 for key: " + selection + " with score: " + args['score']); + const newDisplay = this.state.displayText + selection; + this.setState({ + displayText : newDisplay + }); + let angle = Arrows.ANGLE(selection); + if (angle === -1){ + angle = 's'; + } else if (angle === 180) { + angle = angle.toString(); } else { - console.log(selectedKey, " NOT chosen. confidence: ", data.score*100, "%"); - handleNotChosen(); + angle = (angle + 15).toString(); } + moveTurret(angle); } } diff --git a/src/helpers/P300Communication.js b/src/helpers/SocketCommunication.js similarity index 60% rename from src/helpers/P300Communication.js rename to src/helpers/SocketCommunication.js index b5dd641..30eeda6 100644 --- a/src/helpers/P300Communication.js +++ b/src/helpers/SocketCommunication.js @@ -1,9 +1,13 @@ +import Sockets from "./getSockets"; +const client_socket = (new Sockets()).client_socket; +const robot_socket = (new Sockets()).robot_socket; + function randomP300() { // 10% chance of P300 return Math.floor(Math.random() * 10) === 0; } -export function sendTrainingFlashEvent(client_socket, userId, p300, callback) { +export function sendTrainingFlashEvent(userId, p300, callback) { let timestamp = Date.now() / 1000.0; let json = { 'uuid': userId, @@ -20,11 +24,13 @@ export function sendTrainingFlashEvent(client_socket, userId, p300, callback) { // Upon server respose, callback will execute console.log("sent"); client_socket.once("train", callback); - client_socket.emit("train", JSON.stringify(json)); + client_socket.emit("train", JSON.stringify(json)); + client_socket.once("generate_uuid", (data)=>{console.log(data)}); + client_socket.emit("generate_uuid", " lashf"); } } -export function sendPredictionEvent(client_socket, userId, callback) { +export function sendPredictionEvent(selection, userId, callback) { let timestamp = Date.now() / 1000.0; let json = { 'uuid': userId, @@ -37,13 +43,17 @@ export function sendPredictionEvent(client_socket, userId, callback) { p300: randomP300(), score: "0.4" }); - }else{ + } else{ // Upon server respose, callback will execute - client_socket.once("predict", callback); + client_socket.once("predict", () => callback(selection)); client_socket.emit("predict", JSON.stringify(json)); } } export function masterUUID() { - return "masterUUID"; + return "masterUUID2"; } + +export function moveTurret(angle){ + robot_socket.emit("data", angle); +} \ No newline at end of file diff --git a/src/helpers/getSockets.js b/src/helpers/getSockets.js index 3e45ae7..8ab2f6b 100644 --- a/src/helpers/getSockets.js +++ b/src/helpers/getSockets.js @@ -11,9 +11,10 @@ export default class Sockets { "timeout" : 10000, "transports" : ["websocket"] }; - - this.client_socket = io('http://localhost:8002', connectionOptions); // Socket to connect to P300Client. - // this.robot_socket = io('http://localhost:8003'); // Socket to control Turret + // Socket to connect to P300Client. + this.client_socket = io('http://localhost:8002', connectionOptions); + // Socket to connect to Robot / Turret Server + this.robot_socket = io('http://localhost:8003', connectionOptions); Sockets.instance = this; } diff --git a/src/helpers/robotServer.js b/src/helpers/robotServer.js deleted file mode 100644 index 87c978a..0000000 --- a/src/helpers/robotServer.js +++ /dev/null @@ -1,11 +0,0 @@ -const io = require('socket.io'); -const server = io.listen(8003); - -var robot = require('robotjs'); - -server.on('connection', function (socket) { - socket.on('typing', function (data) { - //robot js - robot.typeString(data); - }); -}); \ No newline at end of file