diff --git a/images/hardware/Lline.png b/images/hardware/Lline.png index de238a4402..2496a41f84 100644 Binary files a/images/hardware/Lline.png and b/images/hardware/Lline.png differ diff --git a/images/hardware/avatarbot.png b/images/hardware/avatarbot.png index 1f886c8a28..c807126996 100644 Binary files a/images/hardware/avatarbot.png and b/images/hardware/avatarbot.png differ diff --git a/images/hardware/disasterAlert.png b/images/hardware/disasterAlert.png index 82ae56706c..fe66a0e9b7 100644 Binary files a/images/hardware/disasterAlert.png and b/images/hardware/disasterAlert.png differ diff --git a/images/hardware/guideline.png b/images/hardware/guideline.png index 51ed876d51..c5315e7e10 100644 Binary files a/images/hardware/guideline.png and b/images/hardware/guideline.png differ diff --git a/images/hardware/robico.png b/images/hardware/robico.png index b0071800e9..575150eb77 100644 Binary files a/images/hardware/robico.png and b/images/hardware/robico.png differ diff --git a/images/hw/robico.png b/images/hw/robico.png index b0071800e9..575150eb77 100644 Binary files a/images/hw/robico.png and b/images/hw/robico.png differ diff --git a/images/hw_lite/alux_proboconnect_lite.png b/images/hw_lite/alux_proboconnect_lite.png index d40b0e3447..cd2c54ddbb 100644 Binary files a/images/hw_lite/alux_proboconnect_lite.png and b/images/hw_lite/alux_proboconnect_lite.png differ diff --git a/images/hw_lite/cocodroncontrollerLite.png b/images/hw_lite/cocodroncontrollerLite.png index e5ceab2538..11fda2dbd9 100644 Binary files a/images/hw_lite/cocodroncontrollerLite.png and b/images/hw_lite/cocodroncontrollerLite.png differ diff --git a/images/hw_lite/robotis_koalabot_lite.png b/images/hw_lite/robotis_koalabot_lite.png index 78c9a6fae5..7bd8dfcfbb 100644 Binary files a/images/hw_lite/robotis_koalabot_lite.png and b/images/hw_lite/robotis_koalabot_lite.png differ diff --git a/images/hw_lite/robotis_rgee_lite.png b/images/hw_lite/robotis_rgee_lite.png index bb1d99f3e1..6106ae2865 100644 Binary files a/images/hw_lite/robotis_rgee_lite.png and b/images/hw_lite/robotis_rgee_lite.png differ diff --git a/images/hw_lite/robotis_robotai_lite.png b/images/hw_lite/robotis_robotai_lite.png index ad983b52d7..ef49273aff 100644 Binary files a/images/hw_lite/robotis_robotai_lite.png and b/images/hw_lite/robotis_robotai_lite.png differ diff --git a/package.json b/package.json index a9d37beead..720f557dad 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "postcss-flexbugs-fixes": "^4.1.0", "simplebar": "^5.3.0", "skmeans": "^0.11.3", - "socket.io-client": "^2.3.0", + "socket.io-client": "^4.8.1", "ua-parser-js": "^1.0.38", "uid": "^0.0.2", "webpack": "^5.85.0", @@ -88,7 +88,6 @@ "@types/lodash": "^4.14.155", "@types/node": "^14.0.11", "@types/pixi.js": "5.0.0", - "@types/socket.io-client": "^1.4.33", "@types/w3c-web-usb": "^1.0.8", "@types/web-bluetooth": "^0.0.18", "@types/webpack-env": "^1.15.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f6af65f23e..dad454c1a5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,7 +37,7 @@ importers: version: 6.0.3 copy-webpack-plugin: specifier: ^12.0.2 - version: 12.0.2(webpack@5.85.0(webpack-cli@5.1.1)) + version: 12.0.2(webpack@5.85.0) core-js: specifier: ^3.6.4 version: 3.6.4 @@ -61,10 +61,10 @@ importers: version: 2.0.8 html-webpack-plugin: specifier: ^5.5.3 - version: 5.5.3(webpack@5.85.0(webpack-cli@5.1.1)) + version: 5.5.3(webpack@5.85.0) html-webpack-template: specifier: ^6.2.0 - version: 6.2.0(html-webpack-plugin@5.5.3(webpack@5.85.0(webpack-cli@5.1.1))) + version: 6.2.0(html-webpack-plugin@5.5.3(webpack@5.85.0)) isomorphic-fetch: specifier: ^2.2.1 version: 2.2.1 @@ -99,8 +99,8 @@ importers: specifier: ^0.11.3 version: 0.11.3 socket.io-client: - specifier: ^2.3.0 - version: 2.3.0 + specifier: ^4.8.1 + version: 4.8.1 ua-parser-js: specifier: ^1.0.38 version: 1.0.38 @@ -112,7 +112,7 @@ importers: version: 5.85.0(webpack-cli@5.1.1) worker-loader: specifier: ^3.0.8 - version: 3.0.8(webpack@5.85.0(webpack-cli@5.1.1)) + version: 3.0.8(webpack@5.85.0) xss-filters: specifier: ^1.2.7 version: 1.2.7 @@ -171,9 +171,6 @@ importers: '@types/pixi.js': specifier: 5.0.0 version: 5.0.0 - '@types/socket.io-client': - specifier: ^1.4.33 - version: 1.4.33 '@types/w3c-web-usb': specifier: ^1.0.8 version: 1.0.10 @@ -191,7 +188,7 @@ importers: version: 1.0.0 babel-loader: specifier: ^8.0.6 - version: 8.0.6(@babel/core@7.22.1)(webpack@5.85.0(webpack-cli@5.1.1)) + version: 8.0.6(@babel/core@7.22.1)(webpack@5.85.0) babel-plugin-dynamic-import-node: specifier: ^2.3.0 version: 2.3.0 @@ -206,7 +203,7 @@ importers: version: 5.1.4 css-loader: specifier: ^3.2.0 - version: 3.2.0(webpack@5.85.0(webpack-cli@5.1.1)) + version: 3.2.0(webpack@5.85.0) cssnano: specifier: ^4.1.10 version: 4.1.10 @@ -218,16 +215,16 @@ importers: version: 9.1.0(eslint@7.32.0) eslint-loader: specifier: ^4.0.2 - version: 4.0.2(eslint@7.32.0)(webpack@5.85.0(webpack-cli@5.1.1)) + version: 4.0.2(eslint@7.32.0)(webpack@5.85.0) eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(@types/eslint@8.40.0)(eslint-config-prettier@9.1.0(eslint@7.32.0))(eslint@7.32.0)(prettier@3.2.5) extract-text-webpack-plugin: specifier: ^4.0.0-beta.0 - version: 4.0.0-beta.0(webpack@5.85.0(webpack-cli@5.1.1)) + version: 4.0.0-beta.0(webpack@5.85.0) file-loader: specifier: ^4.2.0 - version: 4.2.0(webpack@5.85.0(webpack-cli@5.1.1)) + version: 4.2.0(webpack@5.85.0) karma: specifier: ^4.2.0 version: 4.2.0 @@ -245,10 +242,10 @@ importers: version: 3.10.1 less-loader: specifier: ^5.0.0 - version: 5.0.0(less@3.10.1)(webpack@5.85.0(webpack-cli@5.1.1)) + version: 5.0.0(less@3.10.1)(webpack@5.85.0) mini-css-extract-plugin: specifier: ^2.7.6 - version: 2.7.6(webpack@5.85.0(webpack-cli@5.1.1)) + version: 2.7.6(webpack@5.85.0) mocha: specifier: ^6.2.0 version: 6.2.0 @@ -266,16 +263,16 @@ importers: version: 0.20.2 terser-webpack-plugin: specifier: ^5.3.9 - version: 5.3.9(webpack@5.85.0(webpack-cli@5.1.1)) + version: 5.3.9(webpack@5.85.0) ts-loader: specifier: ^9.4.3 - version: 9.4.3(typescript@4.7.4)(webpack@5.85.0(webpack-cli@5.1.1)) + version: 9.4.3(typescript@4.7.4)(webpack@5.85.0) typescript: specifier: ^4.7.4 version: 4.7.4 url-loader: specifier: ^1.0.1 - version: 1.0.1(webpack@5.85.0(webpack-cli@5.1.1)) + version: 1.0.1(webpack@5.85.0) webpack-cli: specifier: ^5.1.1 version: 5.1.1(webpack-dev-server@4.15.0)(webpack@5.85.0) @@ -284,13 +281,13 @@ importers: version: 4.15.0(webpack-cli@5.1.1)(webpack@5.85.0) webpack-manifest-plugin: specifier: ^5.0.0 - version: 5.0.0(webpack@5.85.0(webpack-cli@5.1.1)) + version: 5.0.0(webpack@5.85.0) webpack-merge: specifier: ^5.9.0 version: 5.9.0 webpack-strip-block: specifier: ^0.3.0 - version: 0.3.0(webpack@5.85.0(webpack-cli@5.1.1)) + version: 0.3.0(webpack@5.85.0) packages: @@ -1067,6 +1064,9 @@ packages: resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} engines: {node: '>=18'} + '@socket.io/component-emitter@3.1.2': + resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + '@tensorflow/tfjs-backend-cpu@4.17.0': resolution: {integrity: sha512-2VSCHnX9qhYTjw9HiVwTBSnRVlntKXeBlK7aSVsmZfHGwWE2faErTtO7bWmqNqw0U7gyznJbVAjlow/p+0RNGw==} engines: {yarn: '>= 1.3.2'} @@ -1242,9 +1242,6 @@ packages: '@types/sizzle@2.3.3': resolution: {integrity: sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==} - '@types/socket.io-client@1.4.33': - resolution: {integrity: sha512-m4LnxkljsI9fMsjwpW5QhRpMixo2BeeLpFmg0AE+sS4H1pzAd/cs/ftTiL60FLZgfFa8PFRPx5KsHu8O0bADKQ==} - '@types/sockjs@0.3.33': resolution: {integrity: sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==} @@ -1691,10 +1688,6 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - base64-arraybuffer@0.1.4: - resolution: {integrity: sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==} - engines: {node: '>= 0.6.0'} - base64-arraybuffer@0.1.5: resolution: {integrity: sha512-437oANT9tP582zZMwSvZGy2nmSeAb8DW2me3y+Uv1Wp2Rulr8Mqlyrv3E7MLxmsiaPSMMDmiDVzgE+e8zlMx9g==} engines: {node: '>= 0.6.0'} @@ -2201,15 +2194,6 @@ packages: supports-color: optional: true - debug@4.1.1: - resolution: {integrity: sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==} - deprecated: Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797) - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -2385,14 +2369,15 @@ packages: engine.io-client@3.2.1: resolution: {integrity: sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==} - engine.io-client@3.4.4: - resolution: {integrity: sha512-iU4CRr38Fecj8HoZEnFtm2EiKGbYZcPn3cHxqNGl/tmdWRf60KhK+9vE0JeSjgnlS/0oynEfLgKbT9ALpim0sQ==} + engine.io-client@6.6.3: + resolution: {integrity: sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==} engine.io-parser@2.1.3: resolution: {integrity: sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==} - engine.io-parser@2.2.1: - resolution: {integrity: sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==} + engine.io-parser@5.2.3: + resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} + engines: {node: '>=10.0.0'} engine.io@3.2.1: resolution: {integrity: sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==} @@ -2804,7 +2789,7 @@ packages: resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} engines: {node: '>= 4.0'} os: [darwin] - deprecated: The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2 + deprecated: Upgrade to fsevents v2 to mitigate potential security issues fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} @@ -4221,15 +4206,9 @@ packages: parseqs@0.0.5: resolution: {integrity: sha512-B3Nrjw2aL7aI4TDujOzfA4NsEc4u1lVcIRE0xesutH8kjeWF70uk+W5cBlIQx04zUH9NTBvuN36Y9xLRPK6Jjw==} - parseqs@0.0.6: - resolution: {integrity: sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==} - parseuri@0.0.5: resolution: {integrity: sha512-ijhdxJu6l5Ru12jF0JvzXVPvsC+VibqeaExlNoMhWN6VQ79PGjkmc7oA4W1lp00sFkNyj0fx6ivPLdV51/UMog==} - parseuri@0.0.6: - resolution: {integrity: sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==} - parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -4973,14 +4952,16 @@ packages: socket.io-client@2.1.1: resolution: {integrity: sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==} - socket.io-client@2.3.0: - resolution: {integrity: sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==} + socket.io-client@4.8.1: + resolution: {integrity: sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==} + engines: {node: '>=10.0.0'} socket.io-parser@3.2.0: resolution: {integrity: sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==} - socket.io-parser@3.3.3: - resolution: {integrity: sha512-qOg87q1PMWWTeO01768Yh9ogn7chB9zkKtQnya41Y355S0UmpXgpcrFwAgjYJxu9BdKug5r5e9YtVSeWhKBUZg==} + socket.io-parser@4.2.4: + resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + engines: {node: '>=10.0.0'} socket.io@2.1.1: resolution: {integrity: sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==} @@ -5693,19 +5674,20 @@ packages: utf-8-validate: optional: true - ws@6.1.4: - resolution: {integrity: sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==} + ws@8.13.0: + resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} + engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 + utf-8-validate: '>=5.0.2' peerDependenciesMeta: bufferutil: optional: true utf-8-validate: optional: true - ws@8.13.0: - resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -5723,6 +5705,10 @@ packages: resolution: {integrity: sha512-/bFPLUgJrfGUL10AIv4Y7/CUt6so9CLtB/oFxQSHseSDNNCdC6vwwKEqwLN6wNPBg9YWXAiMu8jkf6RPRS/75Q==} engines: {node: '>=0.4.0'} + xmlhttprequest-ssl@2.1.2: + resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} + engines: {node: '>=0.4.0'} + xss-filters@1.2.7: resolution: {integrity: sha512-KzcmYT/f+YzcYrYRqw6mXxd25BEZCxBQnf+uXTopQDIhrmiaLwO+f+yLsIvvNlPhYvgff8g3igqrBxYh9k8NbQ==} @@ -6625,7 +6611,9 @@ snapshots: source-map: 0.6.1 string-length: 2.0.0 transitivePeerDependencies: + - bufferutil - supports-color + - utf-8-validate '@jest/schemas@29.6.3': dependencies: @@ -6939,6 +6927,8 @@ snapshots: '@sindresorhus/merge-streams@2.3.0': {} + '@socket.io/component-emitter@3.1.2': {} + '@tensorflow/tfjs-backend-cpu@4.17.0(@tensorflow/tfjs-core@4.17.0(encoding@0.1.13))': dependencies: '@tensorflow/tfjs-core': 4.17.0(encoding@0.1.13) @@ -7164,8 +7154,6 @@ snapshots: '@types/sizzle@2.3.3': {} - '@types/socket.io-client@1.4.33': {} - '@types/sockjs@0.3.33': dependencies: '@types/node': 14.0.11 @@ -7354,17 +7342,17 @@ snapshots: '@webgpu/types@0.1.38': {} - '@webpack-cli/configtest@2.1.0(webpack-cli@5.1.1(webpack-dev-server@4.15.0)(webpack@5.85.0))(webpack@5.85.0(webpack-cli@5.1.1))': + '@webpack-cli/configtest@2.1.0(webpack-cli@5.1.1)(webpack@5.85.0)': dependencies: webpack: 5.85.0(webpack-cli@5.1.1) webpack-cli: 5.1.1(webpack-dev-server@4.15.0)(webpack@5.85.0) - '@webpack-cli/info@2.0.1(webpack-cli@5.1.1(webpack-dev-server@4.15.0)(webpack@5.85.0))(webpack@5.85.0(webpack-cli@5.1.1))': + '@webpack-cli/info@2.0.1(webpack-cli@5.1.1)(webpack@5.85.0)': dependencies: webpack: 5.85.0(webpack-cli@5.1.1) webpack-cli: 5.1.1(webpack-dev-server@4.15.0)(webpack@5.85.0) - '@webpack-cli/serve@2.0.4(webpack-cli@5.1.1(webpack-dev-server@4.15.0)(webpack@5.85.0))(webpack-dev-server@4.15.0(webpack-cli@5.1.1)(webpack@5.85.0))(webpack@5.85.0(webpack-cli@5.1.1))': + '@webpack-cli/serve@2.0.4(webpack-cli@5.1.1)(webpack-dev-server@4.15.0)(webpack@5.85.0)': dependencies: webpack: 5.85.0(webpack-cli@5.1.1) webpack-cli: 5.1.1(webpack-dev-server@4.15.0)(webpack@5.85.0) @@ -7580,7 +7568,7 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@8.0.6(@babel/core@7.22.1)(webpack@5.85.0(webpack-cli@5.1.1)): + babel-loader@8.0.6(@babel/core@7.22.1)(webpack@5.85.0): dependencies: '@babel/core': 7.22.1 find-cache-dir: 2.1.0 @@ -7616,8 +7604,6 @@ snapshots: balanced-match@1.0.2: {} - base64-arraybuffer@0.1.4: {} - base64-arraybuffer@0.1.5: {} base64-js@1.5.1: {} @@ -7997,7 +7983,7 @@ snapshots: copy-descriptor@0.1.1: {} - copy-webpack-plugin@12.0.2(webpack@5.85.0(webpack-cli@5.1.1)): + copy-webpack-plugin@12.0.2(webpack@5.85.0): dependencies: fast-glob: 3.3.2 glob-parent: 6.0.2 @@ -8060,7 +8046,7 @@ snapshots: postcss: 7.0.39 timsort: 0.3.0 - css-loader@3.2.0(webpack@5.85.0(webpack-cli@5.1.1)): + css-loader@3.2.0(webpack@5.85.0): dependencies: camelcase: 5.3.1 cssesc: 3.0.0 @@ -8203,10 +8189,6 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.1.1: - dependencies: - ms: 2.1.3 - debug@4.3.4: dependencies: ms: 2.1.2 @@ -8380,19 +8362,13 @@ snapshots: - supports-color - utf-8-validate - engine.io-client@3.4.4: + engine.io-client@6.6.3: dependencies: - component-emitter: 1.3.0 - component-inherit: 0.0.3 - debug: 3.1.0 - engine.io-parser: 2.2.1 - has-cors: 1.1.0 - indexof: 0.0.1 - parseqs: 0.0.6 - parseuri: 0.0.6 - ws: 6.1.4 - xmlhttprequest-ssl: 1.5.5 - yeast: 0.1.2 + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.4 + engine.io-parser: 5.2.3 + ws: 8.17.1 + xmlhttprequest-ssl: 2.1.2 transitivePeerDependencies: - bufferutil - supports-color @@ -8406,13 +8382,7 @@ snapshots: blob: 0.0.5 has-binary2: 1.0.3 - engine.io-parser@2.2.1: - dependencies: - after: 0.8.2 - arraybuffer.slice: 0.0.7 - base64-arraybuffer: 0.1.4 - blob: 0.0.5 - has-binary2: 1.0.3 + engine.io-parser@5.2.3: {} engine.io@3.2.1: dependencies: @@ -8531,7 +8501,7 @@ snapshots: dependencies: eslint: 7.32.0 - eslint-loader@4.0.2(eslint@7.32.0)(webpack@5.85.0(webpack-cli@5.1.1)): + eslint-loader@4.0.2(eslint@7.32.0)(webpack@5.85.0): dependencies: eslint: 7.32.0 find-cache-dir: 3.3.2 @@ -8813,7 +8783,7 @@ snapshots: transitivePeerDependencies: - supports-color - extract-text-webpack-plugin@4.0.0-beta.0(webpack@5.85.0(webpack-cli@5.1.1)): + extract-text-webpack-plugin@4.0.0-beta.0(webpack@5.85.0): dependencies: async: 2.6.4 loader-utils: 1.4.2 @@ -8857,7 +8827,7 @@ snapshots: dependencies: flat-cache: 3.0.4 - file-loader@4.2.0(webpack@5.85.0(webpack-cli@5.1.1)): + file-loader@4.2.0(webpack@5.85.0): dependencies: loader-utils: 1.4.2 schema-utils: 2.7.1 @@ -9209,7 +9179,7 @@ snapshots: relateurl: 0.2.7 terser: 5.17.6 - html-webpack-plugin@5.5.3(webpack@5.85.0(webpack-cli@5.1.1)): + html-webpack-plugin@5.5.3(webpack@5.85.0): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -9218,9 +9188,9 @@ snapshots: tapable: 2.2.1 webpack: 5.85.0(webpack-cli@5.1.1) - html-webpack-template@6.2.0(html-webpack-plugin@5.5.3(webpack@5.85.0(webpack-cli@5.1.1))): + html-webpack-template@6.2.0(html-webpack-plugin@5.5.3(webpack@5.85.0)): dependencies: - html-webpack-plugin: 5.5.3(webpack@5.85.0(webpack-cli@5.1.1)) + html-webpack-plugin: 5.5.3(webpack@5.85.0) htmlparser2@6.1.0: dependencies: @@ -9731,7 +9701,9 @@ snapshots: pretty-format: 24.9.0 throat: 4.1.0 transitivePeerDependencies: + - bufferutil - supports-color + - utf-8-validate jest-leak-detector@24.9.0: dependencies: @@ -10078,7 +10050,7 @@ snapshots: left-pad@1.3.0: {} - less-loader@5.0.0(less@3.10.1)(webpack@5.85.0(webpack-cli@5.1.1)): + less-loader@5.0.0(less@3.10.1)(webpack@5.85.0): dependencies: clone: 2.1.2 less: 3.10.1 @@ -10306,7 +10278,7 @@ snapshots: mimic-fn@2.1.0: {} - mini-css-extract-plugin@2.7.6(webpack@5.85.0(webpack-cli@5.1.1)): + mini-css-extract-plugin@2.7.6(webpack@5.85.0): dependencies: schema-utils: 4.0.1 webpack: 5.85.0(webpack-cli@5.1.1) @@ -10701,14 +10673,10 @@ snapshots: dependencies: better-assert: 1.0.2 - parseqs@0.0.6: {} - parseuri@0.0.5: dependencies: better-assert: 1.0.2 - parseuri@0.0.6: {} - parseurl@1.3.3: {} pascal-case@3.1.2: @@ -11592,22 +11560,12 @@ snapshots: - supports-color - utf-8-validate - socket.io-client@2.3.0: + socket.io-client@4.8.1: dependencies: - backo2: 1.0.2 - base64-arraybuffer: 0.1.5 - component-bind: 1.0.0 - component-emitter: 1.2.1 - debug: 4.1.1 - engine.io-client: 3.4.4 - has-binary2: 1.0.3 - has-cors: 1.1.0 - indexof: 0.0.1 - object-component: 0.0.3 - parseqs: 0.0.5 - parseuri: 0.0.5 - socket.io-parser: 3.3.3 - to-array: 0.1.4 + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.4 + engine.io-client: 6.6.3 + socket.io-parser: 4.2.4 transitivePeerDependencies: - bufferutil - supports-color @@ -11621,11 +11579,10 @@ snapshots: transitivePeerDependencies: - supports-color - socket.io-parser@3.3.3: + socket.io-parser@4.2.4: dependencies: - component-emitter: 1.3.0 - debug: 3.1.0 - isarray: 2.0.1 + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.4 transitivePeerDependencies: - supports-color @@ -11897,7 +11854,7 @@ snapshots: tapable@2.2.1: {} - terser-webpack-plugin@5.3.9(webpack@5.85.0(webpack-cli@5.1.1)): + terser-webpack-plugin@5.3.9(webpack@5.85.0): dependencies: '@jridgewell/trace-mapping': 0.3.18 jest-worker: 27.5.1 @@ -11977,7 +11934,7 @@ snapshots: dependencies: typescript: 5.4.5 - ts-loader@9.4.3(typescript@4.7.4)(webpack@5.85.0(webpack-cli@5.1.1)): + ts-loader@9.4.3(typescript@4.7.4)(webpack@5.85.0): dependencies: chalk: 4.1.2 enhanced-resolve: 5.14.1 @@ -12092,7 +12049,7 @@ snapshots: urix@0.1.0: {} - url-loader@1.0.1(webpack@5.85.0(webpack-cli@5.1.1)): + url-loader@1.0.1(webpack@5.85.0): dependencies: loader-utils: 1.4.2 mime: 2.6.0 @@ -12197,9 +12154,9 @@ snapshots: webpack-cli@5.1.1(webpack-dev-server@4.15.0)(webpack@5.85.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.0(webpack-cli@5.1.1(webpack-dev-server@4.15.0)(webpack@5.85.0))(webpack@5.85.0(webpack-cli@5.1.1)) - '@webpack-cli/info': 2.0.1(webpack-cli@5.1.1(webpack-dev-server@4.15.0)(webpack@5.85.0))(webpack@5.85.0(webpack-cli@5.1.1)) - '@webpack-cli/serve': 2.0.4(webpack-cli@5.1.1(webpack-dev-server@4.15.0)(webpack@5.85.0))(webpack-dev-server@4.15.0(webpack-cli@5.1.1)(webpack@5.85.0))(webpack@5.85.0(webpack-cli@5.1.1)) + '@webpack-cli/configtest': 2.1.0(webpack-cli@5.1.1)(webpack@5.85.0) + '@webpack-cli/info': 2.0.1(webpack-cli@5.1.1)(webpack@5.85.0) + '@webpack-cli/serve': 2.0.4(webpack-cli@5.1.1)(webpack-dev-server@4.15.0)(webpack@5.85.0) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 @@ -12213,7 +12170,7 @@ snapshots: optionalDependencies: webpack-dev-server: 4.15.0(webpack-cli@5.1.1)(webpack@5.85.0) - webpack-dev-middleware@5.3.3(webpack@5.85.0(webpack-cli@5.1.1)): + webpack-dev-middleware@5.3.3(webpack@5.85.0): dependencies: colorette: 2.0.20 memfs: 3.5.1 @@ -12252,7 +12209,7 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 5.3.3(webpack@5.85.0(webpack-cli@5.1.1)) + webpack-dev-middleware: 5.3.3(webpack@5.85.0) ws: 8.13.0 optionalDependencies: webpack: 5.85.0(webpack-cli@5.1.1) @@ -12263,7 +12220,7 @@ snapshots: - supports-color - utf-8-validate - webpack-manifest-plugin@5.0.0(webpack@5.85.0(webpack-cli@5.1.1)): + webpack-manifest-plugin@5.0.0(webpack@5.85.0): dependencies: tapable: 2.2.1 webpack: 5.85.0(webpack-cli@5.1.1) @@ -12286,7 +12243,7 @@ snapshots: webpack-sources@3.2.3: {} - webpack-strip-block@0.3.0(webpack@5.85.0(webpack-cli@5.1.1)): + webpack-strip-block@0.3.0(webpack@5.85.0): dependencies: loader-utils: 1.4.2 webpack: 5.85.0(webpack-cli@5.1.1) @@ -12314,7 +12271,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.1.2 tapable: 2.2.1 - terser-webpack-plugin: 5.3.9(webpack@5.85.0(webpack-cli@5.1.1)) + terser-webpack-plugin: 5.3.9(webpack@5.85.0) watchpack: 2.4.0 webpack-sources: 3.2.3 optionalDependencies: @@ -12396,7 +12353,7 @@ snapshots: wordwrap@0.0.3: {} - worker-loader@3.0.8(webpack@5.85.0(webpack-cli@5.1.1)): + worker-loader@3.0.8(webpack@5.85.0): dependencies: loader-utils: 2.0.4 schema-utils: 3.1.2 @@ -12437,16 +12394,16 @@ snapshots: dependencies: async-limiter: 1.0.1 - ws@6.1.4: - dependencies: - async-limiter: 1.0.1 - ws@8.13.0: {} + ws@8.17.1: {} + xml-name-validator@3.0.0: {} xmlhttprequest-ssl@1.5.5: {} + xmlhttprequest-ssl@2.1.2: {} + xss-filters@1.2.7: {} y18n@4.0.3: {} diff --git a/src/class/engine.js b/src/class/engine.js index 6e94c4fbda..d4d6e6040b 100644 --- a/src/class/engine.js +++ b/src/class/engine.js @@ -15,6 +15,15 @@ Entry.Engine = class Engine { this.popup = null; this.isUpdating = true; this.speeds = [1, 15, 30, 45, 60]; + this.engineTimer = { + isInit: false, + isPaused: false, + start: 0, + pauseStart: 0, + pausedTime: 0, + }; + this._engineTimeouts = []; + this._engineTimeoutSeq = 0; this.attachKeyboardCapture(); @@ -558,6 +567,8 @@ Entry.Engine = class Engine { audioUtils.stopRecord(); clearInterval(this.ticker); this.ticker = null; + this._stopEngineTimer(); + this._clearEngineTimeouts(); } /** @@ -570,6 +581,7 @@ Entry.Engine = class Engine { if (Entry.hw.communicationType !== 'manual') { Entry.hw.update(); } + this._processEngineTimeouts(); } }; @@ -646,6 +658,7 @@ Entry.Engine = class Engine { container.takeSequenceSnapshot(); Entry.scene.takeStartSceneSnapshot(); this.state = EntryEngineState.run; + this._resetEngineTimer(); this.fireEvent('start'); this.achieveEnabled = !(disableAchieve === false); } @@ -788,6 +801,8 @@ Entry.Engine = class Engine { } this.state = EntryEngineState.stop; + this._stopEngineTimer(); + this._clearEngineTimeouts(); this.setEnableInputField(false); Entry.dispatchEvent('stop'); Entry.stage.hideInputField(); @@ -822,6 +837,7 @@ Entry.Engine = class Engine { delete timer.pauseStart; } this.state = EntryEngineState.run; + this._resumeEngineTimer(); Entry.Utils.recoverSoundInstances(); if (visible && this.runButton) { this.setPauseButton(this.option); @@ -849,6 +865,7 @@ Entry.Engine = class Engine { timer.pausedTime += new Date().getTime() - timer.pauseStart; timer.pauseStart = new Date().getTime(); } + this._pauseEngineTimer(); Entry.Utils.pauseSoundInstances(); if (visible && this.runButton) { this.setPauseButton(this.option); @@ -1297,4 +1314,98 @@ Entry.Engine = class Engine { this.execPromises[index + i] = execPromise; }); } + + _resetEngineTimer() { + const timer = this.engineTimer; + timer.start = new Date().getTime(); + timer.pausedTime = 0; + timer.pauseStart = 0; + timer.isPaused = false; + timer.isInit = true; + } + + _pauseEngineTimer() { + const timer = this.engineTimer; + if (!timer.isInit || timer.isPaused) { + return; + } + timer.isPaused = true; + timer.pauseStart = new Date().getTime(); + } + + _resumeEngineTimer() { + const timer = this.engineTimer; + if (!timer.isInit || !timer.isPaused) { + return; + } + if (timer.pauseStart) { + timer.pausedTime += new Date().getTime() - timer.pauseStart; + } + timer.pauseStart = 0; + timer.isPaused = false; + } + + _stopEngineTimer() { + const timer = this.engineTimer; + timer.isInit = false; + timer.isPaused = false; + timer.start = 0; + timer.pauseStart = 0; + timer.pausedTime = 0; + } + + _getEngineTimeMs() { + const timer = this.engineTimer; + if (!timer.isInit) { + return 0; + } + const now = timer.isPaused && timer.pauseStart ? timer.pauseStart : new Date().getTime(); + return Math.max(now - timer.start - timer.pausedTime, 0); + } + + _processEngineTimeouts() { + if (!this._engineTimeouts.length) { + return; + } + const nowMs = this._getEngineTimeMs(); + const timeouts = this._engineTimeouts; + let writeIndex = 0; + for (let i = 0; i < timeouts.length; i++) { + const item = timeouts[i]; + if (item.targetTimeMs <= nowMs) { + try { + item.callback(); + } catch (e) { + console.error('Engine setTimeout callback error', e); + } + } else { + timeouts[writeIndex++] = item; + } + } + if (writeIndex !== timeouts.length) { + timeouts.length = writeIndex; + } + } + + _clearEngineTimeouts() { + this._engineTimeouts = []; + } + + setTimeout(callback, delay) { + if (typeof callback !== 'function') { + return null; + } + const id = ++this._engineTimeoutSeq; + const targetTimeMs = this._getEngineTimeMs() + Math.max(Number(delay) || 0, 0); + this._engineTimeouts.push({ + id, + callback, + targetTimeMs, + }); + return id; + } + + clearTimeout(id) { + this._engineTimeouts = this._engineTimeouts.filter((item) => item.id !== id); + } }; diff --git a/src/playground/blocks/block_analysis.js b/src/playground/blocks/block_analysis.js index fafceedf9e..14f4c2aef6 100644 --- a/src/playground/blocks/block_analysis.js +++ b/src/playground/blocks/block_analysis.js @@ -856,7 +856,7 @@ module.exports = { const tableId = script.getField('MATRIX', script); const timeValue = script.getNumberValue('SECOND', script); DataTable.showTable(tableId); - setTimeout(() => { + Entry.engine.setTimeout(() => { DataTable.closeModal(); }, timeValue * 1000); return script.callReturn(); @@ -1233,10 +1233,9 @@ module.exports = { const returnCol = DataTable.getColumnIndex(script.getValue('RETURN', script)); const value = script.getValue('VALUE', script); const table = DataTable.getSource(tableId, sprite); - const { origin } = table; let foundIndex; - for (let i = 0; i < origin.length; i++) { + for (let i = 0; i < table?.table?.length || 0; i++) { if (table.getValue([i, col]) == value) { foundIndex = i; break; diff --git a/src/playground/blocks/block_expansion_behaviorconduct_disaster.js b/src/playground/blocks/block_expansion_behaviorconduct_disaster.js index 7c269403a9..f058a3e259 100644 --- a/src/playground/blocks/block_expansion_behaviorconduct_disaster.js +++ b/src/playground/blocks/block_expansion_behaviorconduct_disaster.js @@ -250,7 +250,7 @@ Entry.EXPANSION_BLOCK.behaviorConductDisaster.getBlocks = function () { isNotFor: ['behaviorConductDisaster'], func(sprite, script) { const number = script.getStringValue('NUMBER', script); - const defaultValue = Lang.Blocks.no_data; + const defaultValue = Lang.Blocks.deprecated; const params = { category: Entry.EXPANSION_BLOCK.behaviorConductDisaster.apiType, subCategory: script.getField('CATEGORY', script), diff --git a/src/playground/blocks/block_expansion_behaviorconduct_lifesafety.js b/src/playground/blocks/block_expansion_behaviorconduct_lifesafety.js index 9cfb698a38..6968cff0c2 100644 --- a/src/playground/blocks/block_expansion_behaviorconduct_lifesafety.js +++ b/src/playground/blocks/block_expansion_behaviorconduct_lifesafety.js @@ -254,7 +254,7 @@ Entry.EXPANSION_BLOCK.behaviorConductLifeSafety.getBlocks = function () { isNotFor: ['behaviorConductLifeSafety'], func(sprite, script) { const number = script.getStringValue('NUMBER', script); - const defaultValue = Lang.Blocks.no_data; + const defaultValue = Lang.Blocks.deprecated; const params = { category: Entry.EXPANSION_BLOCK.behaviorConductLifeSafety.apiType, subCategory: script.getField('CATEGORY', script), diff --git a/src/playground/blocks/block_expansion_weather.js b/src/playground/blocks/block_expansion_weather.js index 697af75ab9..4d7189048a 100644 --- a/src/playground/blocks/block_expansion_weather.js +++ b/src/playground/blocks/block_expansion_weather.js @@ -32,7 +32,12 @@ Entry.EXPANSION_BLOCK.weather = { return; } Entry.EXPANSION_BLOCK.weather.date = new Date(); - Entry.EXPANSION_BLOCK.weather.localDate = new Date().toLocaleDateString().replaceAll('.', '').replaceAll(' ', '') + const localDate = new Date(); + const localDateYear = localDate.getFullYear(); + const localDateMonth = String(localDate.getMonth() + 1).padStart(2, '0'); + const localDateDay = String(localDate.getDate()).padStart(2, '0'); + // eslint-disable-next-line max-len + Entry.EXPANSION_BLOCK.weather.localDate = `${localDateYear}${localDateMonth}${localDateDay}`; Entry.EXPANSION_BLOCK.weather.getData('week', 'Seoul', 'today'); Entry.EXPANSION_BLOCK.weather.getData('hour', 'Seoul', '00'); Entry.EXPANSION_BLOCK.weather.getData('now', 'Seoul'); @@ -90,29 +95,29 @@ Entry.EXPANSION_BLOCK.weather = { } const skyCodeMap = { - '1': 'sunny', //"맑음", - '2': 'partly_cloudy', //"구름조금", - '3': 'cloudy', //"흐림", - '4': 'rainy', //"비", - '5': 'snowy', //"눈", - '6': 'sleet', //"눈비", + 1: 'sunny', //"맑음", + 2: 'partly_cloudy', //"구름조금", + 3: 'cloudy', //"흐림", + 4: 'rainy', //"비", + 5: 'snowy', //"눈", + 6: 'sleet', //"눈비", - '7': 'rainy', //"소나기", - '8': 'snowy', //"소낙눈", - '9': 'cloudy', //"안개", - '10': 'rainy', //"뇌우", - '11': 'cloudy', //"차차 흐려짐", - '12': 'rainy', //"흐려져 뇌우", - '13': 'rainy', //"흐려져 비", - '14': 'snowy', //"흐려져 눈", - '15': 'sleet', //"흐려져 눈비", - '16': 'cloudy', //"흐린 후 갬", - '17': 'rainy', //"뇌우 후 갬", - '18': 'rainy', //"비 후 갬", - '19': 'snowy', //"눈 후 갬", - '20': 'sleet', //"눈비 후 갬", - '21': 'mostly_cloudy', //"구름많음", - '22': 'cloudy', + 7: 'rainy', //"소나기", + 8: 'snowy', //"소낙눈", + 9: 'cloudy', //"안개", + 10: 'rainy', //"뇌우", + 11: 'cloudy', //"차차 흐려짐", + 12: 'rainy', //"흐려져 뇌우", + 13: 'rainy', //"흐려져 비", + 14: 'snowy', //"흐려져 눈", + 15: 'sleet', //"흐려져 눈비", + 16: 'cloudy', //"흐린 후 갬", + 17: 'rainy', //"뇌우 후 갬", + 18: 'rainy', //"비 후 갬", + 19: 'snowy', //"눈 후 갬", + 20: 'sleet', //"눈비 후 갬", + 21: 'mostly_cloudy', //"구름많음", + 22: 'cloudy', }; if (skyCodeMap[sky_code]) { @@ -170,7 +175,10 @@ Entry.EXPANSION_BLOCK.weather = { default: break; } - return date.toLocaleDateString().replaceAll('.', '').replaceAll(' ', ''); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + return `${year}${month}${day}`; }, locationMap: { Seoul: { @@ -555,7 +563,7 @@ Entry.EXPANSION_BLOCK.weather = { }, }; -Entry.EXPANSION_BLOCK.weather.getBlocks = function() { +Entry.EXPANSION_BLOCK.weather.getBlocks = function () { const params = { getDate(isPython = false) { const param = { @@ -1892,6 +1900,7 @@ Entry.EXPANSION_BLOCK.weather.getBlocks = function() { location, script.getField('DATE', script) ); + return apiResult.sky; }, syntax: { diff --git a/src/playground/blocks/block_func.js b/src/playground/blocks/block_func.js index ab67c770e9..295ee6c968 100644 --- a/src/playground/blocks/block_func.js +++ b/src/playground/blocks/block_func.js @@ -465,6 +465,11 @@ module.exports = { this.funcExecutor.localVariables = _cloneDeep(func.localVariables); } + this.funcExecutor.result = this.funcExecutor.scope; + this.funcExecutor.scope = new Entry.Scope( + this.funcExecutor.scope.block.statements[0].getFirstBlock(), + this.funcExecutor + ); const { promises } = this.funcExecutor.execute(); if (!this.funcExecutor.isEnd()) { diff --git a/src/playground/blocks/block_looks.js b/src/playground/blocks/block_looks.js index 85bffef242..867e99ecac 100644 --- a/src/playground/blocks/block_looks.js +++ b/src/playground/blocks/block_looks.js @@ -152,7 +152,7 @@ module.exports = { } }; sprite.stopDialog = stopDialog; - timeoutId = setTimeout(stopDialog, timeValue * 1000); + timeoutId = Entry.engine.setTimeout(stopDialog, timeValue * 1000); } if (script.timeFlag == 0) { delete script.timeFlag; diff --git a/src/playground/blocks/block_sound.js b/src/playground/blocks/block_sound.js index 57fd60651b..b370535d25 100644 --- a/src/playground/blocks/block_sound.js +++ b/src/playground/blocks/block_sound.js @@ -296,7 +296,7 @@ module.exports = { const duration = Math.floor( (sound.duration * 1000) / Entry.playbackRateValue ); - setTimeout(() => { + Entry.engine.setTimeout(() => { script.playState = 0; }, duration); } @@ -384,7 +384,7 @@ module.exports = { const instance = Entry.Utils.playSound(sound.id); Entry.Utils.addSoundInstances(instance, sprite); const timeValue = script.getNumberValue('SECOND', script); - setTimeout(() => { + Entry.engine.setTimeout(() => { instance.stop(); script.playState = 0; }, timeValue * 1000); @@ -498,7 +498,7 @@ module.exports = { }); Entry.Utils.addSoundInstances(instance, sprite); - setTimeout(() => { + Entry.engine.setTimeout(() => { script.playState = 0; }, duration); } diff --git a/src/playground/blocks/hardware/block_ITPLE_board.js b/src/playground/blocks/hardware/block_ITPLE_board.js index 7c8cb6cb20..64b867395b 100644 --- a/src/playground/blocks/hardware/block_ITPLE_board.js +++ b/src/playground/blocks/hardware/block_ITPLE_board.js @@ -1,8 +1,37 @@ 'use strict'; Entry.ITPLE = { + // 이전 버튼 상태 저장 + prevButtonState: { + 'A0': 1, 'A1': 1, '7': 1, '8': 1, + }, afterReceive(pd) { - if(Entry.engine.isState('run')) { + if (!Entry.engine.isState('run')) { + return; + } + + // 버튼 상태 확인 + const portConfigs = [ + { key: 'A0', type: 'ANALOG', index: 0 }, + { key: 'A1', type: 'ANALOG', index: 1 }, + { key: '7', type: 'DIGITAL', index: 7 }, + { key: '8', type: 'DIGITAL', index: 8 }, + ]; + + let buttonPressed = false; + for (const config of portConfigs) { + const currentValue = Entry.hw.portData[config.type]?.[config.index] ?? 1; + const prevValue = Entry.ITPLE.prevButtonState[config.key]; + + // 버튼이 눌린 순간 감지 (1 → 0) + if (prevValue !== 0 && currentValue === 0) { + buttonPressed = true; + } + Entry.ITPLE.prevButtonState[config.key] = currentValue; + } + + // 버튼이 눌린 순간에만 이벤트 발생 + if (buttonPressed) { Entry.engine.fireEvent('ITPLE_press_button'); } }, @@ -20,14 +49,44 @@ Entry.ITPLE = { GET: {}, SET: {}, }; - } else { - const keySet = Object.keys(Entry.hw.sendQueue.SET); - keySet.forEach((key) => { + } + + // 기존 큐 초기화 + const keySet = Object.keys(Entry.hw.sendQueue.SET); + keySet.forEach((key) => { + const portNum = parseInt(key); + // 네오픽셀 관련 포트(100-103, 200-205)와 물리 포트 9는 별도 처리 + // 206(BLINK), 207(BLINK_STOP)은 명시적으로 삭제 + if (portNum === 206 || portNum === 207) { + delete Entry.hw.sendQueue.SET[key]; + } else if (portNum !== 9 && !(portNum >= 100 && portNum <= 103) && !(portNum >= 200 && portNum <= 205)) { Entry.hw.sendQueue.SET[key].data = 0; Entry.hw.sendQueue.SET[key].time = new Date().getTime(); - }); - } - Entry.hw.update(); + } + }); + + // 깜박이기 중지 명령 전송 (전체) - INIT보다 먼저 실행 + const stopTime = new Date().getTime(); + Entry.hw.sendQueue.SET[206] = { + type: 15, // NEOPIXEL_BLINK_STOP + data: { side: 2 }, // 전체 + time: stopTime, + }; + console.log('[ITPLE] setZero - BLINK_STOP sent at', stopTime); + Entry.hw.update(); // 즉시 전송 + + // NEOPIXEL_INIT 명령 전송 (네오픽셀 끄기) + // 깜박이기 중지 후 약간의 시간차를 두고 INIT 실행 + setTimeout(() => { + const initTime = new Date().getTime(); + Entry.hw.sendQueue.SET[200] = { + type: 9, // NEOPIXEL_INIT + data: 0, + time: initTime, + }; + console.log('[ITPLE] setZero - NEOPIXEL_INIT sent at', initTime); + Entry.hw.update(); + }, 20); }, sensorTypes: { ALIVE: 0, @@ -39,8 +98,13 @@ Entry.ITPLE = { PULSEIN: 6, ULTRASONIC: 7, TIMER: 8, - NEOPIXELINIT: 9, - NEOPIXELCOLOR: 10, + NEOPIXEL_INIT: 9, + NEOPIXEL_COLOR: 10, + NEOPIXEL_BRIGHTNESS: 11, + NEOPIXEL_SHIFT: 12, + NEOPIXEL_ROTATE: 13, + NEOPIXEL_BLINK: 14, + NEOPIXEL_BLINK_STOP: 15, }, toneTable: { 0: 0, @@ -91,6 +155,7 @@ Entry.ITPLE = { '7': false, '8': false, }, + timeSeq: 0, }; Entry.ITPLE.setLanguage = function () { @@ -108,6 +173,16 @@ Entry.ITPLE.setLanguage = function () { ITPLE_set_motor_direction: '%1 모터 %2 방향으로 정하기 %3', ITPLE_set_motor_speed: '%1 모터 %2 빠르기로 정하기 %3', ITPLE_set_servo: '서보모터를 %2 도로 정하기 %3', + ITPLE_set_neopixel_init: '네오픽셀 모두 끄기 %1', + ITPLE_set_neopixel: '%1 번째 네오픽셀 LED를 %2 색으로 켜기 %3', + ITPLE_set_neopixel_all: '네오픽셀 전체의 색상을 %1 (으)로 켜기 %2', + ITPLE_set_neopixel_range: '%1 번부터 %2 번까지 네오픽셀을 %3 색상으로 켜기 %4', + ITPLE_set_neopixel_rotate: '네오픽셀 %1 방향으로 %2 칸 이동 %3', + ITPLE_set_neopixel_brightness: '네오픽셀 최대 밝기를 %1 (으)로 정하기 %2', + ITPLE_set_neopixel_blink: '%1 네오픽셀 %2 색으로 깜박이기 (간격: %3초) %4', + ITPLE_stop_neopixel_blink: '%1 네오픽셀 깜박이기 중지 %2', + ITPLE_color_picker_value: '색상 선택 %1', + ITPLE_rgb_to_color_value: 'R: %1 G: %2 B: %3 색상값', }, }, en: { @@ -123,6 +198,16 @@ Entry.ITPLE.setLanguage = function () { ITPLE_set_motor_direction: '%1 motor %2 direction %3', ITPLE_set_motor_speed: '%1 motor %2 speed %3', ITPLE_set_servo: 'Set servo motor to %2 degree %3', + ITPLE_set_neopixel_init: 'Turn off all NeoPixels %1', + ITPLE_set_neopixel: 'Set NeoPixel %1 to %2 color %3', + ITPLE_set_neopixel_all: 'Set all NeoPixels to %1 color %2', + ITPLE_set_neopixel_range: 'Fill NeoPixels from %1 to %2 with %3 color %4', + ITPLE_set_neopixel_rotate: 'Shift NeoPixels %1 by %2 steps %3', + ITPLE_set_neopixel_brightness: 'Set NeoPixel max brightness to %1 %2', + ITPLE_set_neopixel_blink: 'Blink %1 NeoPixels %2 color (interval: %3s) %4', + ITPLE_stop_neopixel_blink: 'Stop %1 NeoPixel blinking %2', + ITPLE_color_picker_value: 'Pick color %1', + ITPLE_rgb_to_color_value: 'Color from R:%1 G:%2 B:%3', }, }, }; @@ -133,6 +218,8 @@ Entry.ITPLE.blockMenuBlocks = [ 'ITPLE_get_button_value', 'ITPLE_get_sensor_value', 'ITPLE_get_ultrasonic_value', + 'ITPLE_color_picker_value', + 'ITPLE_rgb_to_color_value', 'ITPLE_is_key_pressed', 'ITPLE_value_sensor', 'ITPLE_turn_led', @@ -140,6 +227,14 @@ Entry.ITPLE.blockMenuBlocks = [ 'ITPLE_set_motor_direction', 'ITPLE_set_motor_speed', 'ITPLE_set_servo', + 'ITPLE_set_neopixel_init', + 'ITPLE_set_neopixel', + 'ITPLE_set_neopixel_all', + 'ITPLE_set_neopixel_range', + 'ITPLE_set_neopixel_rotate', + 'ITPLE_set_neopixel_brightness', + 'ITPLE_set_neopixel_blink', + 'ITPLE_stop_neopixel_blink', ]; //region ITPLE 보드 @@ -188,19 +283,18 @@ Entry.ITPLE.getBlocks = function () { '8': { type: 'DIGITAL', index: 8 }, }; - const portKey = script.getValue('PORT', script); + const portKey = script.getField('PORT', script); const config = portConfigMap[portKey]; - const value = Entry.hw.portData[config.type]?.[config.index] ?? 0; - - const hasBeenPressedBefore = Entry.ITPLE.EdgeFlag[portKey]; + if (!config) { + return this.die(); + } + + const value = Entry.hw.portData[config.type]?.[config.index] ?? 1; + + // 버튼이 눌렸을 때 (value === 0) 실행 if (value === 0) { - if (!hasBeenPressedBefore) { - Entry.ITPLE.EdgeFlag[portKey] = true; - return script.callReturn(); - } - } else { - Entry.ITPLE.EdgeFlag[portKey] = false; + return script.callReturn(); } return this.die(); @@ -274,87 +368,85 @@ Entry.ITPLE.getBlocks = function () { } }, ITPLE_get_sensor_value: { - color: EntryStatic.colorSet.block["default"].HARDWARE, - outerLine: EntryStatic.colorSet.block.darken.HARDWARE, - fontColor: '#fff', - skeleton: 'basic_string_field', - statements: [], - params: [{ - type: 'Dropdown', - options: [['조도', 'A2'], ['소리', 'A3'], ['왼쪽 라인', 'A6'], ['오른쪽 라인', 'A7']], - value: 'A2', - fontSize: 11, - bgColor: EntryStatic.colorSet.block.darken.HARDWARE, - arrowColor: EntryStatic.colorSet.arrow["default"].HARDWARE - }], - events: {}, - def: { - params: [null], - type: 'ITPLE_get_sensor_value' - }, - paramsKeyMap: { - PORT: 0 - }, - "class": 'ITPLEGet', - isNotFor: ['ITPLE'], - func: function func(sprite, script) { - const portConfigMap = { - 'A2': { type: 'ANALOG', index: 2 }, - 'A3': { type: 'ANALOG', index: 3 }, - 'A6': { type: 'ANALOG', index: 6 }, - 'A7': { type: 'ANALOG', index: 7 }, - }; - const portKey = script.getValue('PORT', script); - const config = portConfigMap[portKey]; - if (!config) return 0; - return Entry.hw.portData[config.type]?.[config.index] ?? 0; - }, - syntax: { - js: [], - py: [{ - syntax: 'Arduino.analogRead(%1)', - blockType: 'param', - textParams: [{ type: 'Block', accept: 'string' }] - }] - } + color: EntryStatic.colorSet.block["default"].HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [{ + type: 'Dropdown', + options: [['조도', 'A2'], ['소리', 'A3'], ['왼쪽 라인', 'A6'], ['오른쪽 라인', 'A7']], + value: 'A2', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow["default"].HARDWARE + }], + events: {}, + def: { + params: [null], + type: 'ITPLE_get_sensor_value' + }, + paramsKeyMap: { + PORT: 0 + }, + "class": 'ITPLEGet', + isNotFor: ['ITPLE'], + func: function func(sprite, script) { + const portConfigMap = { + 'A2': { type: 'ANALOG', index: 2 }, + 'A3': { type: 'ANALOG', index: 3 }, + 'A6': { type: 'ANALOG', index: 6 }, + 'A7': { type: 'ANALOG', index: 7 }, + }; + const portKey = script.getValue('PORT', script); + const config = portConfigMap[portKey]; + if (!config) return 0; + return Entry.hw.portData[config.type]?.[config.index] ?? 0; + }, + syntax: { + js: [], + py: [{ + syntax: 'Arduino.analogRead(%1)', + blockType: 'param', + textParams: [{ type: 'Block', accept: 'string' }] + }] + } }, ITPLE_is_key_pressed: { - color: EntryStatic.colorSet.block.default.HARDWARE, - outerLine: EntryStatic.colorSet.block.darken.HARDWARE, - fontColor: '#fff', - skeleton: 'basic_boolean_field', - params: [ - { - type: 'Dropdown', - options: [ - ['위쪽', 'A0'], - ['아래쪽', 'A1'], - ['왼쪽', '7'], - ['오른쪽', '8'], - ], - value: 'A0', - fontSize: 11, - bgColor: EntryStatic.colorSet.block.darken.HARDWARE, - arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, - }, - ], - events: {}, - def: { - params: [null], - type: 'ITPLE_is_key_pressed', - }, - paramsKeyMap: { - KEY: 0, - }, - "class": 'ITPLEGet', - isNotFor: ['ITPLE'], - func(sprite, script) { - // 각 키에 대한 하드웨어 포트 정보를 객체로 관리하여 확장성을 높입니다. - const keyToPortMap = { - 'A0': { type: 'ANALOG', index: 0 }, - 'A1': { type: 'ANALOG', index: 1 }, - '7': { type: 'DIGITAL', index: 7 }, - '8': { type: 'DIGITAL', index: 8 }, + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + params: [{ + type: 'Dropdown', + options: [ + ['위쪽', 'A0'], + ['아래쪽', 'A1'], + ['왼쪽', '7'], + ['오른쪽', '8'], + ], + value: 'A0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + },], + events: {}, + def: { + params: [null], + type: 'ITPLE_is_key_pressed', + }, + paramsKeyMap: { + KEY: 0, + }, + "class": 'ITPLEGet', + isNotFor: ['ITPLE'], + func(sprite, script) { + // 각 키에 대한 하드웨어 포트 정보를 객체로 관리하여 확장성을 높입니다. + const keyToPortMap = { + 'A0': { type: 'ANALOG', index: 0 }, + 'A1': { type: 'ANALOG', index: 1 }, + '7': { type: 'DIGITAL', index: 7 }, + '8': { type: 'DIGITAL', index: 8 }, }; const selectedKey = script.getField('KEY'); @@ -470,68 +562,139 @@ Entry.ITPLE.getBlocks = function () { }, }, ITPLE_get_ultrasonic_value: { - color: EntryStatic.colorSet.block["default"].HARDWARE, - outerLine: EntryStatic.colorSet.block.darken.HARDWARE, - fontColor: '#fff', - skeleton: 'basic_string_field', - statements: [], - params: [{ - type: 'Block', - accept: 'string', - defaultType: 'number' - }, { - type: 'Block', - accept: 'string', - defaultType: 'number' - }], - events: {}, - def: { + color: EntryStatic.colorSet.block["default"].HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], params: [{ - type: 'arduino_get_port_number', - params: ['13'] - }, { - type: 'arduino_get_port_number', - params: ['12'] - }], - type: 'ITPLE_get_ultrasonic_value' - }, - paramsKeyMap: { - PORT1: 0, - PORT2: 1 - }, - "class": 'ITPLEGet', - isNotFor: ['ITPLE'], - func: function func(sprite, script) { - var port1 = script.getNumberValue('PORT1', script); - var port2 = script.getNumberValue('PORT2', script); - if (!Entry.hw.sendQueue.SET) { - Entry.hw.sendQueue.SET = {}; - } - delete Entry.hw.sendQueue.SET[port1]; - delete Entry.hw.sendQueue.SET[port2]; - if (!Entry.hw.sendQueue.GET) { - Entry.hw.sendQueue.GET = {}; - } - Entry.hw.sendQueue.GET[Entry.ITPLE.sensorTypes.ULTRASONIC] = { - port: [port1, port2], - time: new Date().getTime() - }; - return Entry.hw.portData.ULTRASONIC || 0; - }, - syntax: { - js: [], - py: [{ - syntax: 'Arduino.ultrasonicRead(%1, %2)', - blockType: 'param', - textParams: [{ type: 'Block', - accept: 'string' - }, { + accept: 'string', + defaultType: 'number' + }, { type: 'Block', - accept: 'string' - }] + accept: 'string', + defaultType: 'number' }], - } + events: {}, + def: { + params: [{ + type: 'arduino_get_port_number', + params: ['13'] + }, { + type: 'arduino_get_port_number', + params: ['12'] + }], + type: 'ITPLE_get_ultrasonic_value' + }, + paramsKeyMap: { + PORT1: 0, + PORT2: 1 + }, + "class": 'ITPLEGet', + isNotFor: ['ITPLE'], + func: function func(sprite, script) { + var port1 = script.getNumberValue('PORT1', script); + var port2 = script.getNumberValue('PORT2', script); + if (!Entry.hw.sendQueue.SET) { + Entry.hw.sendQueue.SET = {}; + } + delete Entry.hw.sendQueue.SET[port1]; + delete Entry.hw.sendQueue.SET[port2]; + if (!Entry.hw.sendQueue.GET) { + Entry.hw.sendQueue.GET = {}; + } + Entry.hw.sendQueue.GET[Entry.ITPLE.sensorTypes.ULTRASONIC] = { + port: [port1, port2], + time: new Date().getTime() + }; + return Entry.hw.portData.ULTRASONIC || 0; + }, + syntax: { + js: [], + py: [{ + syntax: 'Arduino.ultrasonicRead(%1, %2)', + blockType: 'param', + textParams: [{ + type: 'Block', + accept: 'string' + }, { + type: 'Block', + accept: 'string' + }] + }], + } + }, + ITPLE_color_picker_value: { + color: EntryStatic.colorSet.block["default"].HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { type: 'Color' }, + ], + events: {}, + def: { + params: [null], + type: 'ITPLE_color_picker_value', + }, + paramsKeyMap: { + COLOR: 0, + }, + class: 'ITPLE_neopixel', + isNotFor: ['ITPLE'], + func(sprite, script) { + // Color 파라미터는 이미 hex 문자열을 반환 + return script.getStringValue('COLOR', script); + }, + syntax: { + js: [], + py: [] + }, + }, + ITPLE_rgb_to_color_value: { + color: EntryStatic.colorSet.block["default"].HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { type: 'Block', accept: 'string', defaultType: 'number' }, + { type: 'Block', accept: 'string', defaultType: 'number' }, + { type: 'Block', accept: 'string', defaultType: 'number' }, + ], + events: {}, + def: { + params: [ + { type: 'number', params: ['255'] }, + { type: 'number', params: ['0'] }, + { type: 'number', params: ['0'] }, + ], + type: 'ITPLE_rgb_to_color_value', + }, + paramsKeyMap: { + RED: 0, + GREEN: 1, + BLUE: 2, + }, + class: 'ITPLE_neopixel', + isNotFor: ['ITPLE'], + func(sprite, script) { + let r = script.getNumberValue('RED', script); + let g = script.getNumberValue('GREEN', script); + let b = script.getNumberValue('BLUE', script); + // clamp + r = Math.min(255, Math.max(0, Math.floor(r))); + g = Math.min(255, Math.max(0, Math.floor(g))); + b = Math.min(255, Math.max(0, Math.floor(b))); + const toHex = (v) => v.toString(16).padStart(2, '0').toUpperCase(); + return `#${toHex(r)}${toHex(g)}${toHex(b)}`; + }, + syntax: { + js: [], + py: [] + }, }, ITPLE_turn_led: { // 저학년 학생을 위한, 핀 번호 없는 LED 켜기 블록 color: EntryStatic.colorSet.block.default.HARDWARE, @@ -1208,21 +1371,746 @@ Entry.ITPLE.getBlocks = function () { }, syntax: { js: [], - py: [ - { - syntax: 'Arduino.servomotorWrite(%1, %2)', - textParams: [ - { - type: 'Block', - accept: 'string', - }, - { - type: 'Block', - accept: 'string', - }, - ], - }, - ], + py: [{ + syntax: 'Arduino.servomotorWrite(%1, %2)', + textParams: [{ + type: 'Block', + accept: 'string', + },{ + type: 'Block', + accept: 'string', + },], + },], + }, + }, + ITPLE_set_neopixel_init: { + color: EntryStatic.colorSet.block["default"].HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [{ + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12 + }], + events: {}, + def: { + params: [null], + type: 'ITPLE_set_neopixel_init' + }, + "class": 'ITPLE_neopixel', + isNotFor: ['ITPLE'], + func(sprite, script) { + const sq = Entry.hw.sendQueue; + const port = 200; + + if (!script.isStart) { + if (!sq.SET) { + sq.SET = {}; + } + + // 시퀀스 번호로 고유한 시간 보장 + Entry.ITPLE.timeSeq++; + const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; + + sq.SET[port] = { + type: Entry.ITPLE.sensorTypes.NEOPIXEL_INIT, + data: uniqueTime % 10000, + time: uniqueTime, + }; + + script.isStart = true; + script.timeFlag = Date.now(); + return script; + } + + // 10ms 대기 + if (Date.now() - script.timeFlag < 2) { + return script; + } + + delete script.isStart; + delete script.timeFlag; + return script.callReturn(); + }, + syntax: { + js: [], + py: [{ + syntax: 'Arduino.neopixelInit(9, 4)' + }] + } + }, + ITPLE_set_neopixel: { + color: EntryStatic.colorSet.block["default"].HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [{ + type: 'Dropdown', + options: [['1', '0'], ['2', '1'], ['3', '2'], ['4', '3']], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow["default"].HARDWARE + }, { + type: 'Block', + accept: 'string', + defaultType: 'text' + }, { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12 + }], + events: {}, + def: { + params: [null, { + type: 'ITPLE_color_picker_value', params: ['#FF0000'] + }, null], + type: 'ITPLE_set_neopixel' + }, + paramsKeyMap: { + NUM: 0, + COLOR: 1, + }, + "class": 'ITPLE_neopixel', + isNotFor: ['ITPLE'], + func(sprite, script) { + const sq = Entry.hw.sendQueue; + const num = script.getNumberValue('NUM', script); + const port = 100 + num; + const color = script.getStringValue('COLOR', script); + + const rgb = Entry.hex2rgb(color); + let r = rgb.r || 0; + let g = rgb.g || 0; + let b = rgb.b || 0; + + r = Math.min(255, Math.max(0, r)); + g = Math.min(255, Math.max(0, g)); + b = Math.min(255, Math.max(0, b)); + + if (!script.isStart) { + if (!sq.SET) { + sq.SET = {}; + } + + // 시퀀스 번호로 고유한 시간 보장 + Entry.ITPLE.timeSeq++; + const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; + + sq.SET[port] = { + type: Entry.ITPLE.sensorTypes.NEOPIXEL_COLOR, + data: { num, r, g, b }, + time: uniqueTime, + }; + + script.isStart = true; + script.timeFlag = Date.now(); + return script; + } + + // 10ms 대기 + if (Date.now() - script.timeFlag < 2) { + return script; + } + + delete script.isStart; + delete script.timeFlag; + return script.callReturn(); + }, + syntax: { + js: [], + py: [{ + syntax: 'Arduino.neopixelColor(9, %1, %2)', + textParams: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + ], + }] + } + }, + ITPLE_set_neopixel_all: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { type: 'Block', accept: 'string', defaultType: 'text' }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { type: 'ITPLE_color_picker_value', params: ['#00FF00'] }, + null, + ], + type: 'ITPLE_set_neopixel_all', + }, + paramsKeyMap: { + COLOR: 0, + }, + class: 'ITPLE_neopixel', + isNotFor: ['ITPLE'], + func(sprite, script) { + const sq = Entry.hw.sendQueue; + const port = 202; // 전체 설정용 가상 포트 + const color = script.getStringValue('COLOR', script); + + const rgb = Entry.hex2rgb(color); + let r = rgb.r || 0; + let g = rgb.g || 0; + let b = rgb.b || 0; + + r = Math.min(255, Math.max(0, r)); + g = Math.min(255, Math.max(0, g)); + b = Math.min(255, Math.max(0, b)); + + if (!script.isStart) { + if (!sq.SET) { + sq.SET = {}; + } + + // 시퀀스 번호로 고유한 시간 보장 + Entry.ITPLE.timeSeq++; + const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; + + sq.SET[port] = { + type: Entry.ITPLE.sensorTypes.NEOPIXEL_COLOR, + data: { num: 255, r, g, b }, // num: 255는 전체를 의미 + time: uniqueTime, + }; + + script.isStart = true; + script.timeFlag = Date.now(); + return script; + } + + // 10ms 대기 + if (Date.now() - script.timeFlag < 2) { + return script; + } + + delete script.isStart; + delete script.timeFlag; + return script.callReturn(); + }, + syntax: { + js: [], + py: [ + { + syntax: 'Arduino.neopixelColorAll(9, %1)', + textParams: [ + { + type: 'Block', + accept: 'string', + }, + ], + }, + ] + }, + }, + ITPLE_set_neopixel_range: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['1', '0'], + ['2', '1'], + ['3', '2'], + ['4', '3'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['1', '0'], + ['2', '1'], + ['3', '2'], + ['4', '3'], + ], + value: '3', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { type: 'Block', accept: 'string', defaultType: 'text' }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { type: 'ITPLE_color_picker_value', params: ['#0000FF'] }, + null, + ], + type: 'ITPLE_set_neopixel_range', + }, + paramsKeyMap: { + START: 0, + END: 1, + COLOR: 2, + }, + class: 'ITPLE_neopixel', + isNotFor: ['ITPLE'], + func(sprite, script) { + const sq = Entry.hw.sendQueue; + const port = 203; // 범위 설정용 가상 포트 + let start = script.getNumberValue('START', script); + let end = script.getNumberValue('END', script); + const color = script.getStringValue('COLOR', script); + + const rgb = Entry.hex2rgb(color); + let r = rgb.r || 0; + let g = rgb.g || 0; + let b = rgb.b || 0; + + // 범위 자동 조절 (0~3) + start = Math.min(3, Math.max(0, start)); + end = Math.min(3, Math.max(0, end)); + + // start > end인 경우 swap + if (start > end) { + const temp = start; + start = end; + end = temp; + } + + // RGB 값 조절 + r = Math.min(255, Math.max(0, r)); + g = Math.min(255, Math.max(0, g)); + b = Math.min(255, Math.max(0, b)); + + if (!script.isStart) { + if (!sq.SET) { + sq.SET = {}; + } + + // 시퀀스 번호로 고유한 시간 보장 + Entry.ITPLE.timeSeq++; + const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; + + sq.SET[port] = { + type: Entry.ITPLE.sensorTypes.NEOPIXEL_COLOR, + data: { num: 254, start, end, r, g, b }, // num: 254는 범위를 의미 + time: uniqueTime, + }; + + script.isStart = true; + script.timeFlag = Date.now(); + return script; + } + + // 10ms 대기 + if (Date.now() - script.timeFlag < 2) { + return script; + } + + delete script.isStart; + delete script.timeFlag; + return script.callReturn(); + }, + syntax: { + js: [], + py: [ + { + syntax: 'Arduino.neopixelColorRange(9, %1, %2, %3)', + textParams: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + ], + }, + ] + }, + }, + ITPLE_set_neopixel_rotate: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['왼쪽', '-1'], + ['오른쪽', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'number', + params: ['1'], + }, + null, + ], + type: 'ITPLE_set_neopixel_rotate', + }, + paramsKeyMap: { + DIRECTION: 0, + STEPS: 1, + }, + class: 'ITPLE_neopixel', + isNotFor: ['ITPLE'], + func(sprite, script) { + const sq = Entry.hw.sendQueue; + const port = 205; // 회전용 가상 포트 + let direction = script.getNumberValue('DIRECTION', script); + let steps = script.getNumberValue('STEPS', script); + + // steps 범위 조절 (0~4) + steps = Math.min(4, Math.max(0, Math.floor(steps))); + + if (!script.isStart) { + if (!sq.SET) { + sq.SET = {}; + } + + // 시퀀스 번호로 고유한 시간 보장 + Entry.ITPLE.timeSeq++; + const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; + + sq.SET[port] = { + type: Entry.ITPLE.sensorTypes.NEOPIXEL_ROTATE, + data: { direction, steps }, + time: uniqueTime, + }; + + script.isStart = true; + script.timeFlag = Date.now(); + return script; + } + + // 10ms 대기 + if (Date.now() - script.timeFlag < 10) { + return script; + } + + delete script.isStart; + delete script.timeFlag; + return script.callReturn(); + }, + syntax: { + js: [], + py: [ + { + syntax: 'Arduino.neopixelRotate(9, %1, %2)', + textParams: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + ], + }, + ] + }, + }, + ITPLE_set_neopixel_brightness: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'number', + params: ['255'], + }, + null, + ], + type: 'ITPLE_set_neopixel_brightness', + }, + paramsKeyMap: { + BRIGHTNESS: 0, + }, + class: 'ITPLE_neopixel', + isNotFor: ['ITPLE'], + func(sprite, script) { + const sq = Entry.hw.sendQueue; + const port = 201; + let brightness = script.getNumberValue('BRIGHTNESS', script); + + brightness = Math.min(255, Math.max(0, brightness)); + + if (!script.isStart) { + if (!sq.SET) { + sq.SET = {}; + } + + // 시퀀스 번호로 고유한 시간 보장 + Entry.ITPLE.timeSeq++; + const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; + + sq.SET[port] = { + type: Entry.ITPLE.sensorTypes.NEOPIXEL_BRIGHTNESS, + data: brightness, + time: uniqueTime, + }; + + script.isStart = true; + script.timeFlag = Date.now(); + return script; + } + + // 10ms 대기 + if (Date.now() - script.timeFlag < 2) { + return script; + } + + delete script.isStart; + delete script.timeFlag; + return script.callReturn(); + }, + syntax: { + js: [], + py: [ + { + syntax: 'Arduino.neopixelBrightness(9, %1)', + textParams: [ + { + type: 'Block', + accept: 'string', + }, + ], + }, + ] + }, + }, + ITPLE_set_neopixel_blink: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['왼쪽', '0'], + ['오른쪽', '1'], + ['전체', '2'], + ], + value: '2', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { type: 'Block', accept: 'string', defaultType: 'text' }, + { type: 'Block', accept: 'string', defaultType: 'number' }, + { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12 }, + ], + events: {}, + def: { + params: [ + null, + { type: 'ITPLE_color_picker_value', params: ['#FFFFFF'] }, + { type: 'number', params: ['0.5'] }, + null, + ], + type: 'ITPLE_set_neopixel_blink', + }, + paramsKeyMap: { + SIDE: 0, + COLOR: 1, + INTERVAL: 2, + }, + class: 'ITPLE_neopixel', + isNotFor: ['ITPLE'], + func(sprite, script) { + const sq = Entry.hw.sendQueue; + const port = 206; // BLINK 가상 포트 + + const side = script.getNumberValue('SIDE', script); // 2: 전체, 0: 왼쪽, 1: 오른쪽 + const count = 0; // 무한 깜박임 + const color = script.getStringValue('COLOR', script); + let intervalSec = script.getNumberValue('INTERVAL', script); + + const rgb = Entry.hex2rgb(color); + let r = rgb.r || 0; + let g = rgb.g || 0; + let b = rgb.b || 0; + + r = Math.min(255, Math.max(0, r)); + g = Math.min(255, Math.max(0, g)); + b = Math.min(255, Math.max(0, b)); + const interval = Math.max(0.1, intervalSec) * 1000; // ms + + if (!script.isStart) { + if (!sq.SET) { + sq.SET = {}; + } + + // 시퀀스 번호로 고유한 시간 보장 (다른 네오픽셀 동작과 통일) + Entry.ITPLE.timeSeq++; + const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; + + sq.SET[port] = { + type: Entry.ITPLE.sensorTypes.NEOPIXEL_BLINK, + data: { side, count, r, g, b, interval }, + time: uniqueTime, + }; + + script.isStart = true; + script.timeFlag = Date.now(); + return script; + } + + if (Date.now() - script.timeFlag < 2) { + return script; + } + + delete script.isStart; + delete script.timeFlag; + return script.callReturn(); + }, + syntax: { + js: [], + py: [ + { + syntax: 'Arduino.neopixelBlink(%1, %2, %3)', + textParams: [ + { type: 'Block', accept: 'string' }, + { type: 'Block', accept: 'string' }, + { type: 'Block', accept: 'string' }, + ], + }, + ] + }, + }, + ITPLE_stop_neopixel_blink: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['왼쪽', '0'], + ['오른쪽', '1'], + ['전체', '2'], + ], + value: '2', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12 }, + ], + events: {}, + def: { + params: [null, null], + type: 'ITPLE_stop_neopixel_blink', + }, + paramsKeyMap: { + SIDE: 0, + }, + class: 'ITPLE_neopixel', + isNotFor: ['ITPLE'], + func(sprite, script) { + const sq = Entry.hw.sendQueue; + const port = 206; // BLINK/STOP 통합 가상 포트 + + if (!script.isStart) { + if (!sq.SET) { + sq.SET = {}; + } + + const side = script.getNumberValue('SIDE', script); + + // 시퀀스 번호로 고유한 시간 보장 + Entry.ITPLE.timeSeq++; + const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; + + sq.SET[port] = { + type: Entry.ITPLE.sensorTypes.NEOPIXEL_BLINK_STOP, + data: { side }, + time: uniqueTime, + }; + + script.isStart = true; + script.timeFlag = Date.now(); + return script; + } + + if (Date.now() - script.timeFlag < 2) { + return script; + } + + delete script.isStart; + delete script.timeFlag; + return script.callReturn(); + }, + syntax: { + js: [], + py: [ + { syntax: 'Arduino.neopixelBlinkStop(9, %1)' }, + ] }, }, }; diff --git a/src/playground/blocks/hardware/block_altino.js b/src/playground/blocks/hardware/block_altino.js index cdfa04185b..7f9a2979b6 100644 --- a/src/playground/blocks/hardware/block_altino.js +++ b/src/playground/blocks/hardware/block_altino.js @@ -286,6 +286,12 @@ Entry.Altino.getBlocks = function() { type: 'Dropdown', options: [ [Lang.Blocks.ALTINO_CDS, 'cds'], + [Lang.Blocks.ALTINO_IR1, 'ir1'], + [Lang.Blocks.ALTINO_IR2, 'ir2'], + [Lang.Blocks.ALTINO_IR3, 'ir3'], + [Lang.Blocks.ALTINO_IR4, 'ir4'], + [Lang.Blocks.ALTINO_IR5, 'ir5'], + [Lang.Blocks.ALTINO_IR6, 'ir6'], [Lang.Blocks.ALTINO_ACCX, 'accx'], [Lang.Blocks.ALTINO_ACCY, 'accy'], [Lang.Blocks.ALTINO_ACCZ, 'accz'], @@ -295,12 +301,6 @@ Entry.Altino.getBlocks = function() { [Lang.Blocks.ALTINO_GYROX, 'gyrox'], [Lang.Blocks.ALTINO_GYROY, 'gyroy'], [Lang.Blocks.ALTINO_GYROZ, 'gyroz'], - [Lang.Blocks.ALTINO_IR1, 'ir1'], - [Lang.Blocks.ALTINO_IR2, 'ir2'], - [Lang.Blocks.ALTINO_IR3, 'ir3'], - [Lang.Blocks.ALTINO_IR4, 'ir4'], - [Lang.Blocks.ALTINO_IR5, 'ir5'], - [Lang.Blocks.ALTINO_IR6, 'ir6'], [Lang.Blocks.ALTINO_TEM, 'tem'], [Lang.Blocks.ALTINO_TOR2, 'tor2'], [Lang.Blocks.ALTINO_TOR1, 'tor1'], diff --git a/src/playground/blocks/hardware/block_altino_lite.js b/src/playground/blocks/hardware/block_altino_lite.js index f90a8ee808..bf069bd520 100644 --- a/src/playground/blocks/hardware/block_altino_lite.js +++ b/src/playground/blocks/hardware/block_altino_lite.js @@ -139,7 +139,7 @@ Entry.AltinoLite.setLanguage = function() { }, template: { altino_lite_analogValue: '알티노 라이트 %1 센서값', - altino_lite_stopAll: '정지 %1°%2', + altino_lite_stopAll: '정지 %1 %2', altino_lite_dot_display: '표시하기 %1 %2', altino_lite_dot_display_line: '표시하기 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10', altino_lite_dot_display_hex: '표시하기 %1 %2 %3 %4 %5 %6 %7 %8 %9', diff --git a/src/playground/blocks/hardware/block_altino_neo.js b/src/playground/blocks/hardware/block_altino_neo.js new file mode 100644 index 0000000000..b5c5c34117 --- /dev/null +++ b/src/playground/blocks/hardware/block_altino_neo.js @@ -0,0 +1,1497 @@ +'use strict'; + +Entry.AltinoNeo = { + PORT_MAP: { + rightWheel: 0, + leftWheel: 0, + steering: 0, + led1: 0, + led2: 0, + note: 0, + ascii: 0, + dot1: 0, + dot2: 0, + dot3: 0, + dot4: 0, + dot5: 0, + dot6: 0, + dot7: 0, + dot8: 0, + }, + setZero: function() { + var portMap = Entry.AltinoNeo.PORT_MAP; + var sq = Entry.hw.sendQueue; + for (var port in portMap) { + sq[port] = portMap[port]; + } + Entry.hw.update(); + // var Altino = Entry.Altino; + // Altino.removeAllTimeouts(); + }, + timeouts: [], + removeTimeout: function(id) { + clearTimeout(id); + var timeouts = this.timeouts; + var index = timeouts.indexOf(id); + if (index >= 0) { + timeouts.splice(index, 1); + } + }, + removeAllTimeouts: function() { + var timeouts = this.timeouts; + for (var i in timeouts) { + clearTimeout(timeouts[i]); + } + this.timeouts = []; + }, + id: '18.4', + name: 'altino_neo', + url: 'http://saeon.co.kr/', + imageName: 'altino_neo.png', + title: { + en: 'Altino Neo', + ko: '알티노 네오', + }, +}; + +Entry.AltinoNeo.blockMenuBlocks = [ + 'altino_neo_analogValue', + 'altino_neo_stopAll', + 'altino_neo_rear_wheel', + 'altino_neo_steering', + 'altino_neo_sound', + 'altino_neo_light', + 'altino_neo_dot_display', + 'altino_neo_dot_display_line', + 'altino_neo_steering_hex', + 'altino_neo_light_hex', + 'altino_neo_sound_hex', + 'altino_neo_dot_display_hex', + 'altino_neo_dot_display_matrix_on', + 'altino_neo_dot_display_matrix_off', +]; + +Entry.AltinoNeo.setLanguage = function() { + return { + ko: { + // ko.js에 작성하던 내용 + Blocks: { + altino_neo_BAT: '배터리', + altino_neo_CDS: '조도', + altino_neo_TOF1: 'TOF-1', + altino_neo_TOF2: 'TOF-2', + altino_neo_TOF3: 'TOF-3', + altino_neo_TOF4: 'TOF-4', + altino_neo_TOF5: 'TOF-5', + altino_neo_TOF6: 'TOF-6', + altino_neo_ACC_X: '가속도-X', + altino_neo_ACC_Y: '가속도-Y', + altino_neo_ACC_Z: '가속도-Z', + altino_neo_MAG_X: '지자기-X', + altino_neo_MAG_Y: '지자기-Y', + altino_neo_MAG_Z: '지자기-Z', + altino_neo_GYRO_X: '자이로-X', + altino_neo_GYRO_Y: '자이로-Y', + altino_neo_GYRO_Z: '자이로-Z', + altino_neo_AHRS_Roll: '횡전각', + altino_neo_AHRS_Pitch: '종전각', + altino_neo_AHRS_Yaw: '편향각', + altino_neo_Temp: '온도', + altino_neo_Left_Wheel_Torque: '왼쪽 뒷바퀴 전류', + altino_neo_Right_Wheel_Torque: '오른쪽 뒷바퀴 전류', + altino_neo_Led_Brake_Light: '브레이크', + altino_neo_Led_Forward_Light: '전방', + altino_neo_Led_Backward_Light: '후방', + altino_neo_Led_Turn_Left_Light: '왼쪽 방향지시', + altino_neo_Led_Turn_Right_Light: '오른쪽 방향지시', + altino_neo_Line: '번째 줄', + altino_neo_Steering_Angle_Center: '중앙', + altino_neo_Steering_Angle_Left10: '왼쪽으로-10', + altino_neo_Steering_Angle_Left15: '왼쪽으로-15', + altino_neo_Steering_Angle_Left20: '왼쪽으로-20', + altino_neo_Steering_Angle_Left5: '왼쪽으로-5', + altino_neo_Steering_Angle_Right10: '오른쪽으로-10', + altino_neo_Steering_Angle_Right15: '오른쪽으로-15', + altino_neo_Steering_Angle_Right20: '오른쪽으로-20', + altino_neo_Steering_Angle_Right5: '오른쪽으로-5', + altino_neo_Value: '출력 값', + altino_neo_a: 'A(라)', + altino_neo_a2: 'A#(라#)', + altino_neo_b: 'B(시)', + altino_neo_c: 'C(도)', + altino_neo_c2: 'C#(도#)', + altino_neo_d: 'D(레)', + altino_neo_d2: 'D#(레#)', + altino_neo_dot_display_1: '한문자', + altino_neo_dot_display_2: '출력하기', + altino_neo_e: 'E(미)', + altino_neo_f: 'F(파)', + altino_neo_f2: 'F#(파#)', + altino_neo_g: 'G(솔)', + altino_neo_g2: 'G#(솔#)', + altino_neo_sound_oct: '옥타브', + altino_neo_h: '끄기', + altino_neo_h2: '켜기', + altino_neo_leftWheel: '왼쪽', + altino_neo_melody_ms: '연주하기', + altino_neo_outputValue: '출력 값', + altino_neo_rightWheel: '오른쪽', + altino_neo_set: '로 정하기', + altino_neo_stopAll: '모두', + altino_neo_stopDrive: '주행', + altino_neo_stopSteering: '조향', + altino_neo_stopSound: '소리', + altino_neo_stopLight: '라이트', + altino_neo_stopDisplay: '표시하기', + altino_neo_dot_line_1: '1행', + altino_neo_dot_line_2: '2행', + altino_neo_dot_line_3: '3행', + altino_neo_dot_line_4: '4행', + altino_neo_dot_line_5: '5행', + altino_neo_dot_line_6: '6행', + altino_neo_dot_line_7: '7행', + altino_neo_dot_line_8: '8행', + }, + template: { + altino_neo_analogValue: '알티노 네오 %1 센서값', + altino_neo_stopAll: '정지 %1 %2', + altino_neo_dot_display: '표시하기 %1 %2', + altino_neo_dot_display_line: '표시하기 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10', + altino_neo_dot_display_hex: '표시하기 %1 %2 %3 %4 %5 %6 %7 %8 %9', + altino_neo_dot_display_matrix_on: '표시하기 켜기 X:%1 Y:%2 %3', + altino_neo_dot_display_matrix_off: '표시하기 끄기 X:%1 Y:%2 %3', + altino_neo_light: '라이트%1 %2 %3', + altino_neo_light_hex: '라이트%1 %2 %3', + altino_neo_sound_hex: '소리%1 %2', + altino_neo_rear_wheel: '뒷바퀴 구동 좌:%1 우:%2%3', + altino_neo_sound: '소리 %1 %2 %3', + altino_neo_steering_hex: '조향 %1%2', + altino_neo_steering: '조향 %1°%2', + }, + }, + en: { + // en.js에 작성하던 내용 + Blocks: { + altino_neo_BAT: 'BAT', + altino_neo_CDS: 'CDS', + altino_neo_TOF1: 'TOF-1', + altino_neo_TOF2: 'TOF-2', + altino_neo_TOF3: 'TOF-3', + altino_neo_TOF4: 'TOF-4', + altino_neo_TOF5: 'TOF-5', + altino_neo_TOF6: 'TOF-6', + altino_neo_ACC_X: 'ACC-X', + altino_neo_ACC_Y: 'ACC-Y', + altino_neo_ACC_Z: 'ACC-Z', + altino_neo_MAG_X: 'MAG-X', + altino_neo_MAG_Y: 'MAG-Y', + altino_neo_MAG_Z: 'MAG-Z', + altino_neo_GYRO_X: 'GYRO-X', + altino_neo_GYRO_Y: 'GYRO-Y', + altino_neo_GYRO_Z: 'GYRO-Z', + altino_neo_AHRS_Roll: 'ROLL', + altino_neo_AHRS_Pitch: 'PITCH', + altino_neo_AHRS_Yaw: 'YAW', + altino_neo_Temp: 'TEMP', + altino_neo_Left_Wheel_Torque: 'LEFT TORQUE', + altino_neo_Right_Wheel_Torque: 'RIGHT TORQUE', + altino_neo_Led_Brake_Light: 'Brake', + altino_neo_Led_Forward_Light: 'Forward', + altino_neo_Led_Backward_Light: 'Backward', + altino_neo_Led_Turn_Left_Light: 'Turn Left', + altino_neo_Led_Turn_Right_Light: 'Turn Right', + altino_neo_Line: 'line', + altino_neo_Steering_Angle_Center: 'Center-0', + altino_neo_Steering_Angle_Left10: 'Left-10', + altino_neo_Steering_Angle_Left15: 'Left-15', + altino_neo_Steering_Angle_Left20: 'Left-20', + altino_neo_Steering_Angle_Left5: 'Left-5', + altino_neo_Steering_Angle_Right10: 'Right-10', + altino_neo_Steering_Angle_Right15: 'Right-15', + altino_neo_Steering_Angle_Right20: 'Right-20', + altino_neo_Steering_Angle_Right5: 'Right-5', + altino_neo_Value: 'output value', + altino_neo_a: 'A(la)', + altino_neo_a2: 'A#(la#)', + altino_neo_b: 'B(si)', + altino_neo_c: 'C(do)', + altino_neo_c2: 'C#(do#)', + altino_neo_d: 'D(re)', + altino_neo_d2: 'D#(re#)', + altino_neo_dot_display_1: 'one char', + altino_neo_dot_display_2: 'display', + altino_neo_e: 'E(mi)', + altino_neo_f: 'F(fa)', + altino_neo_f2: 'F#(fa#)', + altino_neo_g: 'G(sol)', + altino_neo_g2: 'G#(sol#)', + altino_neo_sound_oct: 'Oct', + altino_neo_h: 'Off', + altino_neo_h2: 'On', + altino_neo_leftWheel: 'left', + altino_neo_melody_ms: 'play', + altino_neo_outputValue: 'output', + altino_neo_rightWheel: 'right', + altino_neo_set: ' display', + altino_neo_stopAll: 'All', + altino_neo_stopDrive: 'Drive', + altino_neo_stopSteering: 'Steering', + altino_neo_stopSound: 'Sound', + altino_neo_stopLight: 'Light', + altino_neo_stopDisplay: 'Display', + altino_neo_dot_line_1: 'Line-1', + altino_neo_dot_line_2: 'Line-2', + altino_neo_dot_line_3: 'Line-3', + altino_neo_dot_line_4: 'Line-4', + altino_neo_dot_line_5: 'Line-5', + altino_neo_dot_line_6: 'Line-6', + altino_neo_dot_line_7: 'Line-7', + altino_neo_dot_line_8: 'Line-8', + }, + template: { + altino_neo_analogValue: 'Altino neo %1 sensor value', + altino_neo_stopAll: 'Stop %1°%2', + altino_neo_dot_display: 'Display %1 %2', + altino_neo_dot_display_line: 'Display %1 %2 %3 %4 %5 %6 %7 %8 %9 %10', + altino_neo_dot_display_hex: 'Display %1 %2 %3 %4 %5 %6 %7 %8 %9', + altino_neo_dot_display_matrix_on: 'Display On X:%1 Y:%2 %3', + altino_neo_dot_display_matrix_off: 'Display Off X:%1 Y:%2 %3', + altino_neo_light: 'Light %1 %2 %3', + altino_neo_light_hex: 'Light %1 %2 %3', + altino_neo_sound_hex: 'Sound %1 %2', + altino_neo_rear_wheel: 'Go L:%1 R:%2%3', + altino_neo_sound: 'Sound %1 %2 %3', + altino_neo_steering_hex: 'Steering %1%2', + altino_neo_steering: 'Steering %1°%2', + }, + }, + }; +}; + +Entry.AltinoNeo.getBlocks = function() { + return { + //region Altino 알티노 + altino_neo_analogValue: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_CDS, 'cds'], + [Lang.Blocks.altino_neo_TOF1, 'tof1'], + [Lang.Blocks.altino_neo_TOF2, 'tof2'], + [Lang.Blocks.altino_neo_TOF3, 'tof3'], + [Lang.Blocks.altino_neo_TOF4, 'tof4'], + [Lang.Blocks.altino_neo_TOF5, 'tof5'], + [Lang.Blocks.altino_neo_TOF6, 'tof6'], + [Lang.Blocks.altino_neo_BAT, 'bat'], + [Lang.Blocks.altino_neo_ACC_X, 'accx'], + [Lang.Blocks.altino_neo_ACC_Y, 'accy'], + [Lang.Blocks.altino_neo_ACC_Z, 'accz'], + [Lang.Blocks.altino_neo_MAG_X, 'magx'], + [Lang.Blocks.altino_neo_MAG_Y, 'magy'], + [Lang.Blocks.altino_neo_MAG_Z, 'magz'], + [Lang.Blocks.altino_neo_GYRO_X, 'gyrox'], + [Lang.Blocks.altino_neo_GYRO_Y, 'gyroy'], + [Lang.Blocks.altino_neo_GYRO_Z, 'gyroz'], + [Lang.Blocks.altino_neo_AHRS_Roll, 'roll'], + [Lang.Blocks.altino_neo_AHRS_Pitch, 'pitch'], + [Lang.Blocks.altino_neo_AHRS_Yaw, 'yaw'], + [Lang.Blocks.altino_neo_Temp, 'temp'], + [Lang.Blocks.altino_neo_Left_Wheel_Torque, 'leftTorque'], + [Lang.Blocks.altino_neo_Right_Wheel_Torque, 'rightTorque'], + ], + value: 'cds', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'altino_neo_analogValue', + }, + paramsKeyMap: { + DEVICE: 0, + }, + class: 'altino_neo_sensor', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var pd = Entry.hw.portData; + var dev = script.getField('DEVICE'); + return pd[dev]; + }, + syntax: { js: [], py: ['AltinoNeo.analog_value(%1)'] }, + }, + altino_neo_stopAll: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_stopAll, 'All'], + [Lang.Blocks.altino_neo_stopDrive, 'Drive'], + [Lang.Blocks.altino_neo_stopSteering, 'Steering'], + [Lang.Blocks.altino_neo_stopSound, 'Sound'], + [Lang.Blocks.altino_neo_stopLight, 'Light'], + [Lang.Blocks.altino_neo_stopDisplay, 'Display'], + ], + value: 'All', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'altino_neo_stopAll', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'altino_neo_output', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + var direction = script.getField('DIRECTION', script); + + if (direction == 'All') { + sq.steering = 0; + sq.rightWheel = 0; + sq.leftWheel = 0; + sq.note = 0; + sq.led1 = 0; + sq.led2 = 0; + sq.ascii = 0; + sq.dot1 = 0; + sq.dot2 = 0; + sq.dot3 = 0; + sq.dot4 = 0; + sq.dot5 = 0; + sq.dot6 = 0; + sq.dot7 = 0; + sq.dot8 = 0; + } else if (direction == 'Drive') { + sq.rightWheel = 0; + sq.leftWheel = 0; + } else if (direction == 'Steering') { + sq.steering = 0; + } else if (direction == 'Sound') { + sq.note = 0; + } else if (direction == 'Light') { + sq.led1 = 0; + sq.led2 = 0; + } else if (direction == 'Display') { + sq.ascii = 0; + sq.dot1 = 0; + sq.dot2 = 0; + sq.dot3 = 0; + sq.dot4 = 0; + sq.dot5 = 0; + sq.dot6 = 0; + sq.dot7 = 0; + sq.dot8 = 0; + } + + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.stop(%1)'] }, + }, + altino_neo_steering: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_Steering_Angle_Center, 'Center'], + [Lang.Blocks.altino_neo_Steering_Angle_Left5, 'Left5'], + [Lang.Blocks.altino_neo_Steering_Angle_Left10, 'Left10'], + [Lang.Blocks.altino_neo_Steering_Angle_Left15, 'Left15'], + [Lang.Blocks.altino_neo_Steering_Angle_Left20, 'Left20'], + [Lang.Blocks.altino_neo_Steering_Angle_Right5, 'Right5'], + [Lang.Blocks.altino_neo_Steering_Angle_Right10, 'Right10'], + [Lang.Blocks.altino_neo_Steering_Angle_Right15, 'Right15'], + [Lang.Blocks.altino_neo_Steering_Angle_Right20, 'Right20'], + ], + value: 'Center', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'altino_neo_steering', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'altino_neo_output', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + var direction = script.getField('DIRECTION', script); + + if (direction == 'Center') { + sq.steering = 0; + } else if (direction == 'Left5') { + sq.steering = 0xe0; + } else if (direction == 'Left10') { + sq.steering = 0xc0; + } else if (direction == 'Left15') { + sq.steering = 0xa1; + } else if (direction == 'Left20') { + sq.steering = 0x81; + } else if (direction == 'Right5') { + sq.steering = 31; + } else if (direction == 'Right10') { + sq.steering = 63; + } else if (direction == 'Right15') { + sq.steering = 94; + } else if (direction == 'Right20') { + sq.steering = 126; + } + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.steering(%1)'] }, + }, + altino_neo_steering_hex: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'text', + params: ['0'], + }, + null, + ], + type: 'altino_neo_steering_hex', + }, + paramsKeyMap: { + steerVal: 0, + }, + class: 'altino_neo_expert', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + sq.steering = parseInt(Number(script.getStringValue('steerVal')), 10); + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.steering_hex(%1)'] }, + }, + altino_neo_sound_hex: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'text', + params: ['0'], + }, + null, + ], + type: 'altino_neo_sound_hex', + }, + paramsKeyMap: { + soundVal: 0, + }, + class: 'altino_neo_expert', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + sq.note = parseInt(Number(script.getStringValue('soundVal')), 10); + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.sound_hex(%1)'] }, + }, + altino_neo_rear_wheel: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'text', + params: ['300'], + }, + { + type: 'text', + params: ['300'], + }, + null, + ], + type: 'altino_neo_rear_wheel', + }, + paramsKeyMap: { + leftWheel: 0, + rightWheel: 1, + }, + class: 'altino_neo_output', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + + sq.rightWheel = script.getNumberValue('rightWheel'); + sq.leftWheel = script.getNumberValue('leftWheel'); + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.rear_wheel(%1, %2)'] }, + }, + altino_neo_sound: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['1-' + Lang.Blocks.altino_neo_sound_oct, '1'], + ['2-' + Lang.Blocks.altino_neo_sound_oct, '2'], + ['3-' + Lang.Blocks.altino_neo_sound_oct, '3'], + ['4-' + Lang.Blocks.altino_neo_sound_oct, '4'], + ['5-' + Lang.Blocks.altino_neo_sound_oct, '5'], + ['6-' + Lang.Blocks.altino_neo_sound_oct, '6'], + ['7-' + Lang.Blocks.altino_neo_sound_oct, '7'], + ['8-' + Lang.Blocks.altino_neo_sound_oct, '8'], + ], + value: '4', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_h, 'NOT'], + [Lang.Blocks.altino_neo_c, 'C'], + [Lang.Blocks.altino_neo_c2, 'C#'], + [Lang.Blocks.altino_neo_d, 'D'], + [Lang.Blocks.altino_neo_d2, 'D#'], + [Lang.Blocks.altino_neo_e, 'E'], + [Lang.Blocks.altino_neo_f, 'F'], + [Lang.Blocks.altino_neo_f2, 'F#'], + [Lang.Blocks.altino_neo_g, 'G'], + [Lang.Blocks.altino_neo_g2, 'G#'], + [Lang.Blocks.altino_neo_a, 'A'], + [Lang.Blocks.altino_neo_a2, 'A#'], + [Lang.Blocks.altino_neo_b, 'B'], + ], + value: 'NOT', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'altino_neo_sound', + }, + paramsKeyMap: { + OCTAVE: 0, + NOTE: 1, + }, + class: 'altino_neo_output', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + var octave = script.getStringField('OCTAVE', script); + var note = script.getStringField('NOTE', script); + var octave_int = octave + note; + + if (note == 'NOT') sq.note = 0; + else if (octave_int == '1C') sq.note = 1; + else if (octave_int == '1C#') sq.note = 2; + else if (octave_int == '1D') sq.note = 3; + else if (octave_int == '1D#') sq.note = 4; + else if (octave_int == '1E') sq.note = 5; + else if (octave_int == '1F') sq.note = 6; + else if (octave_int == '1F#') sq.note = 7; + else if (octave_int == '1G') sq.note = 8; + else if (octave_int == '1G#') sq.note = 9; + else if (octave_int == '1A') sq.note = 10; + else if (octave_int == '1A#') sq.note = 11; + else if (octave_int == '1B') sq.note = 12; + else if (octave_int == '2C') sq.note = 13; + else if (octave_int == '2C#') sq.note = 14; + else if (octave_int == '2D') sq.note = 15; + else if (octave_int == '2D#') sq.note = 16; + else if (octave_int == '2E') sq.note = 17; + else if (octave_int == '2F') sq.note = 18; + else if (octave_int == '2F#') sq.note = 19; + else if (octave_int == '2G') sq.note = 20; + else if (octave_int == '2G#') sq.note = 21; + else if (octave_int == '2A') sq.note = 22; + else if (octave_int == '2A#') sq.note = 23; + else if (octave_int == '2B') sq.note = 24; + else if (octave_int == '3C') sq.note = 25; + else if (octave_int == '3C#') sq.note = 26; + else if (octave_int == '3D') sq.note = 27; + else if (octave_int == '3D#') sq.note = 28; + else if (octave_int == '3E') sq.note = 29; + else if (octave_int == '3F') sq.note = 30; + else if (octave_int == '3F#') sq.note = 31; + else if (octave_int == '3G') sq.note = 32; + else if (octave_int == '3G#') sq.note = 33; + else if (octave_int == '3A') sq.note = 34; + else if (octave_int == '3A#') sq.note = 35; + else if (octave_int == '3B') sq.note = 36; + else if (octave_int == '4C') sq.note = 37; + else if (octave_int == '4C#') sq.note = 38; + else if (octave_int == '4D') sq.note = 39; + else if (octave_int == '4D#') sq.note = 40; + else if (octave_int == '4E') sq.note = 41; + else if (octave_int == '4F') sq.note = 42; + else if (octave_int == '4F#') sq.note = 43; + else if (octave_int == '4G') sq.note = 44; + else if (octave_int == '4G#') sq.note = 45; + else if (octave_int == '4A') sq.note = 46; + else if (octave_int == '4A#') sq.note = 47; + else if (octave_int == '4B') sq.note = 48; + else if (octave_int == '5C') sq.note = 49; + else if (octave_int == '5C#') sq.note = 50; + else if (octave_int == '5D') sq.note = 51; + else if (octave_int == '5D#') sq.note = 52; + else if (octave_int == '5E') sq.note = 53; + else if (octave_int == '5F') sq.note = 54; + else if (octave_int == '5F#') sq.note = 55; + else if (octave_int == '5G') sq.note = 56; + else if (octave_int == '5G#') sq.note = 57; + else if (octave_int == '5A') sq.note = 58; + else if (octave_int == '5A#') sq.note = 59; + else if (octave_int == '5B') sq.note = 60; + else if (octave_int == '6C') sq.note = 61; + else if (octave_int == '6C#') sq.note = 62; + else if (octave_int == '6D') sq.note = 63; + else if (octave_int == '6D#') sq.note = 64; + else if (octave_int == '6E') sq.note = 65; + else if (octave_int == '6F') sq.note = 66; + else if (octave_int == '6F#') sq.note = 67; + else if (octave_int == '6G') sq.note = 68; + else if (octave_int == '6G#') sq.note = 69; + else if (octave_int == '6A') sq.note = 70; + else if (octave_int == '6A#') sq.note = 71; + else if (octave_int == '6B') sq.note = 72; + else if (octave_int == '7C') sq.note = 73; + else if (octave_int == '7C#') sq.note = 74; + else if (octave_int == '7D') sq.note = 75; + else if (octave_int == '7D#') sq.note = 76; + else if (octave_int == '7E') sq.note = 77; + else if (octave_int == '7F') sq.note = 78; + else if (octave_int == '7F#') sq.note = 79; + else if (octave_int == '7G') sq.note = 80; + else if (octave_int == '7G#') sq.note = 81; + else if (octave_int == '7A') sq.note = 82; + else if (octave_int == '7A#') sq.note = 83; + else if (octave_int == '7B') sq.note = 84; + else if (octave_int == '8C') sq.note = 85; + else if (octave_int == '8C#') sq.note = 86; + else if (octave_int == '8D') sq.note = 87; + else if (octave_int == '8D#') sq.note = 88; + else if (octave_int == '8E') sq.note = 89; + else if (octave_int == '8F') sq.note = 90; + else if (octave_int == '8F#') sq.note = 91; + else if (octave_int == '8G') sq.note = 92; + else if (octave_int == '8G#') sq.note = 93; + else if (octave_int == '8A') sq.note = 94; + else if (octave_int == '8A#') sq.note = 95; + else if (octave_int == '8B') sq.note = 96; + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.sound(%1, %2)'] }, + }, + altino_neo_light: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_Led_Forward_Light, '2'], + [Lang.Blocks.altino_neo_Led_Turn_Left_Light, '5'], + [Lang.Blocks.altino_neo_Led_Turn_Right_Light, '6'], + [Lang.Blocks.altino_neo_Led_Brake_Light, '4'], + [Lang.Blocks.altino_neo_Led_Backward_Light, '3'], + ], + value: '2', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_h2, '255'], + [Lang.Blocks.altino_neo_h, '0'], + ], + value: '255', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'altino_neo_light', + }, + paramsKeyMap: { + SELECT: 0, + ONOFF: 1, + }, + class: 'altino_neo_output', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + var select = script.getStringField('SELECT', script); + var onoff = script.getStringField('ONOFF', script); + + if (select == '2' && onoff == '255') { + sq.led2 = sq.led2 | 0x03; + } else if (select == '2' && onoff == '0') { + sq.led2 = sq.led2 & 0xfc; + } + + if (select == '3' && onoff == '255') { + sq.led2 = sq.led2 | 0x0c; + } else if (select == '3' && onoff == '0') { + sq.led2 = sq.led2 & 0xf3; + } + + if (select == '4' && onoff == '255') { + sq.led1 = sq.led1 | 0x03; + } else if (select == '4' && onoff == '0') { + sq.led1 = sq.led1 & 0xfc; + } + + if (select == '5' && onoff == '255') { + sq.led2 = sq.led2 | 0xa0; + } else if (select == '5' && onoff == '0') { + sq.led2 = sq.led2 & 0x5f; + } + + if (select == '6' && onoff == '255') { + sq.led2 = sq.led2 | 0x50; + } else if (select == '6' && onoff == '0') { + sq.led2 = sq.led2 & 0xaf; + } + //sq.led = 0xff; + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.light(%1, %2)'] }, + }, + altino_neo_dot_display_matrix_on: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'text', + params: ['1'], + }, + { + type: 'text', + params: ['1'], + }, + null, + ], + type: 'altino_neo_dot_display_matrix_on', + }, + paramsKeyMap: { + VALUE1: 0, + VALUE2: 1, + }, + class: 'altino_neo_expert', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + var nx = script.getNumberValue('VALUE1'); + var ny = script.getNumberValue('VALUE2'); + var mask = 1; + + sq.ascii = 0xff; + + if (ny >= 1 && ny <= 8) { + ny = ny - 1; + mask = mask << ny; + if (nx == 1) { + sq.dot8 |= mask; + } else if (nx == 2) { + sq.dot7 |= mask; + } else if (nx == 3) { + sq.dot6 |= mask; + } else if (nx == 4) { + sq.dot5 |= mask; + } else if (nx == 5) { + sq.dot4 |= mask; + } else if (nx == 6) { + sq.dot3 |= mask; + } else if (nx == 7) { + sq.dot2 |= mask; + } else if (nx == 8) { + sq.dot1 |= mask; + } + } + + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.dot_display_matrix_on(%1, %2)'] }, + }, + altino_neo_dot_display_matrix_off: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'text', + params: ['1'], + }, + { + type: 'text', + params: ['1'], + }, + null, + ], + type: 'altino_neo_dot_display_matrix_off', + }, + paramsKeyMap: { + VALUE1: 0, + VALUE2: 1, + }, + class: 'altino_neo_expert', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + var nx = script.getNumberValue('VALUE1'); + var ny = script.getNumberValue('VALUE2'); + var mask = 1; + + sq.ascii = 0xff; + + if (ny >= 1 && ny <= 8) { + ny = ny - 1; + mask = mask << ny; + if (nx == 1) { + sq.dot8 &= ~mask; + } else if (nx == 2) { + sq.dot7 &= ~mask; + } else if (nx == 3) { + sq.dot6 &= ~mask; + } else if (nx == 4) { + sq.dot5 &= ~mask; + } else if (nx == 5) { + sq.dot4 &= ~mask; + } else if (nx == 6) { + sq.dot3 &= ~mask; + } else if (nx == 7) { + sq.dot2 &= ~mask; + } else if (nx == 8) { + sq.dot1 &= ~mask; + } + } + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.dot_display_matrix_off(%1, %2)'] }, + }, + altino_neo_light_hex: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + } + ], + events: {}, + def: { + params: [ + { + type: 'text', + params: ['0x00'], + }, + { + type: 'text', + params: ['0x00'], + }, + null, + ], + type: 'altino_neo_light_hex' + }, + paramsKeyMap: { + MSB: 0, + LSB: 1, + }, + class: 'altino_neo_expert', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + // var sq = Entry.hw.sendQueue; + // var lsb = parseInt(Number(script.getStringValue('LSB')), 10); + // sq.led = lsb; + + var sq = Entry.hw.sendQueue; + var msb = parseInt(Number(script.getStringValue('MSB')), 10); + var lsb = parseInt(Number(script.getStringValue('LSB')), 10); + + sq.led1 = (msb & 0x03) | (sq.led1 & 0xfc); + sq.led2 = lsb; + + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.light_hex(%1, %2)'] }, + }, + altino_neo_dot_display: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'text', + params: ['A'], + }, + null, + ], + type: 'altino_neo_dot_display', + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'altino_neo_output', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + var str = script.getStringValue('VALUE'); + sq.ascii = str.charCodeAt(0); + + return script.callReturn(); + }, + syntax: { + js: [], + py: [ + { + syntax: 'AltinoNeo.dot_display(%1)', + textParams: [ + { + type: 'Block', + accept: 'string', + }, + ], + }, + ], + }, + }, + altino_neo_dot_display_line: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_dot_line_1, '1'], + [Lang.Blocks.altino_neo_dot_line_2, '2'], + [Lang.Blocks.altino_neo_dot_line_3, '3'], + [Lang.Blocks.altino_neo_dot_line_4, '4'], + [Lang.Blocks.altino_neo_dot_line_5, '5'], + [Lang.Blocks.altino_neo_dot_line_6, '6'], + [Lang.Blocks.altino_neo_dot_line_7, '7'], + [Lang.Blocks.altino_neo_dot_line_8, '8'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_h2, '1'], + [Lang.Blocks.altino_neo_h, '0'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_h2, '1'], + [Lang.Blocks.altino_neo_h, '0'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_h2, '1'], + [Lang.Blocks.altino_neo_h, '0'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_h2, '1'], + [Lang.Blocks.altino_neo_h, '0'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_h2, '1'], + [Lang.Blocks.altino_neo_h, '0'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_h2, '1'], + [Lang.Blocks.altino_neo_h, '0'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_h2, '1'], + [Lang.Blocks.altino_neo_h, '0'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.altino_neo_h2, '1'], + [Lang.Blocks.altino_neo_h, '0'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null, null, null, null, null, null, null, null], + type: 'altino_neo_dot_display_line', + }, + paramsKeyMap: { + LINE: 0, + SW1: 1, + SW2: 2, + SW3: 3, + SW4: 4, + SW5: 5, + SW6: 6, + SW7: 7, + SW8: 8, + }, + class: 'altino_neo_output', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + var line = script.getStringField('LINE', script); + + sq.ascii = 0xff; + + var dots = [ + script.getStringField('SW1', script), + script.getStringField('SW2', script), + script.getStringField('SW3', script), + script.getStringField('SW4', script), + script.getStringField('SW5', script), + script.getStringField('SW6', script), + script.getStringField('SW7', script), + script.getStringField('SW8', script), + ]; + + var mask = 0; + + if (line == '1') { + mask = 0x01; + } else if (line == '2') { + mask = 0x02; + } else if (line == '3') { + mask = 0x04; + } else if (line == '4') { + mask = 0x08; + } else if (line == '5') { + mask = 0x10; + } else if (line == '6') { + mask = 0x20; + } else if (line == '7') { + mask = 0x40; + } else if (line == '8') { + mask = 0x80; + } + + if (dots[7] == '1') { + sq.dot1 |= mask; + } else { + sq.dot1 &= ~mask; + } + + if (dots[6] == '1') { + sq.dot2 |= mask; + } else { + sq.dot2 &= ~mask; + } + + if (dots[5] == '1') { + sq.dot3 |= mask; + } else { + sq.dot3 &= ~mask; + } + + if (dots[4] == '1') { + sq.dot4 |= mask; + } else { + sq.dot4 &= ~mask; + } + + if (dots[3] == '1') { + sq.dot5 |= mask; + } else { + sq.dot5 &= ~mask; + } + + if (dots[2] == '1') { + sq.dot6 |= mask; + } else { + sq.dot6 &= ~mask; + } + + if (dots[1] == '1') { + sq.dot7 |= mask; + } else { + sq.dot7 &= ~mask; + } + + if (dots[0] == '1') { + sq.dot8 |= mask; + } else { + sq.dot8 &= ~mask; + } + + //sq.led = 0xff; + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.dot_display_line(%1, %2, %3, %4, %5, %6, %7, %8)'] }, + }, + altino_neo_dot_display_hex: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'text', + params: ['0x00'], + }, + { + type: 'text', + params: ['0x00'], + }, + { + type: 'text', + params: ['0x00'], + }, + { + type: 'text', + params: ['0x00'], + }, + { + type: 'text', + params: ['0x00'], + }, + { + type: 'text', + params: ['0x00'], + }, + { + type: 'text', + params: ['0x00'], + }, + { + type: 'text', + params: ['0x00'], + }, + null, + ], + type: 'altino_neo_dot_display_hex', + }, + paramsKeyMap: { + VALUE1: 0, + VALUE2: 1, + VALUE3: 2, + VALUE4: 3, + VALUE5: 4, + VALUE6: 5, + VALUE7: 6, + VALUE8: 7, + }, + class: 'altino_neo_expert', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + sq.ascii = 0xff; + sq.dot1 = parseInt(Number(script.getStringValue('VALUE8')), 10); + sq.dot2 = parseInt(Number(script.getStringValue('VALUE7')), 10); + sq.dot3 = parseInt(Number(script.getStringValue('VALUE6')), 10); + sq.dot4 = parseInt(Number(script.getStringValue('VALUE5')), 10); + sq.dot5 = parseInt(Number(script.getStringValue('VALUE4')), 10); + sq.dot6 = parseInt(Number(script.getStringValue('VALUE3')), 10); + sq.dot7 = parseInt(Number(script.getStringValue('VALUE2')), 10); + sq.dot8 = parseInt(Number(script.getStringValue('VALUE1')), 10); + + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.dot_display_hex(%1, %2, %3, %4, %5, %6, %7, %8)'] }, + }, + altino_neo_ir_reset: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + ], + type: 'altino_neo_ir_reset', + }, + paramsKeyMap: { + DEVICE : 0, + }, + class: 'altino_neo_output', + isNotFor: ['altino_neo'], + func: function(sprite, script) { + var sq = Entry.hw.sendQueue; + + sq.ir = 6; + return script.callReturn(); + }, + syntax: { js: [], py: ['AltinoNeo.ir_reset'] }, + }, + //endregion Altino 알티노 + }; +}; + +module.exports = Entry.AltinoNeo; diff --git a/src/playground/scope.js b/src/playground/scope.js index 01dd09ef05..bcf714db76 100644 --- a/src/playground/scope.js +++ b/src/playground/scope.js @@ -13,10 +13,14 @@ class Scope { } getParam(index) { - const fieldBlock = this.block.params[index]; - const newScope = new Entry.Scope(fieldBlock, this.executor); - const result = newScope.run(this.entity, true); - return result; + const param = this.block.params[index]; + if (param instanceof Entry.Block) { + const newScope = new Entry.Scope(param, this.executor); + const result = newScope.run(this.entity, true); + return result; + } else { + return this.filterReservedKeywords(param); + } } // 클래스 레벨에서 한 번만 생성 @@ -27,11 +31,10 @@ class Scope { } getParams() { - const that = this; return this.block.params.map((param) => { if (param instanceof Entry.Block) { const fieldBlock = param; - const newScope = new Entry.Scope(fieldBlock, that.executor); + const newScope = new Entry.Scope(fieldBlock, this.executor); return newScope.run(this.entity, true); } else { return this.filterReservedKeywords(param); @@ -185,7 +188,6 @@ class Scope { } const values = this.getParams(); const isPromise = values.some((value) => value instanceof Promise); - // const schema = this.block.getSchema(); if (!schema.func) { return; }