From 26067a9287b494b43d494c544467cebc0d09aca0 Mon Sep 17 00:00:00 2001 From: Valerie R Young Date: Thu, 6 Dec 2018 16:49:43 -0500 Subject: [PATCH 01/32] Draft of goforce blocks --- src/extension-support/extension-manager.js | 4 +- src/extensions/scratch3_goforce/index.js | 190 +++++++++++++++++++++ 2 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/extensions/scratch3_goforce/index.js diff --git a/src/extension-support/extension-manager.js b/src/extension-support/extension-manager.js index 86a335989..11b6f3366 100644 --- a/src/extension-support/extension-manager.js +++ b/src/extension-support/extension-manager.js @@ -17,6 +17,7 @@ const Scratch3VideoSensingBlocks = require('../extensions/scratch3_video_sensing const Scratch3Speech2TextBlocks = require('../extensions/scratch3_speech2text'); const Scratch3Ev3Blocks = require('../extensions/scratch3_ev3'); const Scratch3MakeyMakeyBlocks = require('../extensions/scratch3_makeymakey'); +const Scratch3GoForceBlocks = require('../extensions/scratch3_goforce'); const builtinExtensions = { pen: Scratch3PenBlocks, @@ -28,7 +29,8 @@ const builtinExtensions = { videoSensing: Scratch3VideoSensingBlocks, speech2text: Scratch3Speech2TextBlocks, ev3: Scratch3Ev3Blocks, - makeymakey: Scratch3MakeyMakeyBlocks + makeymakey: Scratch3MakeyMakeyBlocks, + goforce: Scratch3GoForceBlocks }; /** diff --git a/src/extensions/scratch3_goforce/index.js b/src/extensions/scratch3_goforce/index.js new file mode 100644 index 000000000..d7ae9b65b --- /dev/null +++ b/src/extensions/scratch3_goforce/index.js @@ -0,0 +1,190 @@ +const ArgumentType = require('../../extension-support/argument-type'); +const BlockType = require('../../extension-support/block-type'); +const log = require('../../util/log'); +const cast = require('../../util/cast'); +const formatMessage = require('format-message'); +const BLE = require('../../io/ble'); +const Base64Util = require('../../util/base64-util'); + +/** + * Icon png to be displayed at the left edge of each extension block, encoded as a data URI. + * @type {string} + */ +// eslint-disable-next-line max-len +const blockIconURI = 'data:image/png;base64,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'; + +const CompareOptionsMenu = ['>', '<', '=']; + +const DirectionOptionsMenu = ['x', 'y', 'z']; + + +/** + * Scratch 3.0 blocks to interact with a GoForce peripheral. + */ +class Scratch3GoForceBlocks { + + /** + * Construct a set of GoForce blocks. + * @param {Runtime} runtime - the Scratch 3.0 runtime. + */ + constructor (runtime) { + /** + * The Scratch 3.0 runtime. + * @type {Runtime} + */ + this.runtime = runtime; + } + + /** + * @returns {object} metadata for this extension and its blocks. + */ + getInfo () { + return { + id: Scratch3GoForceBlocks.EXTENSION_ID, + name: Scratch3GoForceBlocks.EXTENSION_NAME, + blockIconURI: blockIconURI, + showStatusButton: true, + blocks: [ + { + opcode: 'whenAccelerationCompare', + text: formatMessage({ + id: 'ev3.whenAccelerationCompare', + default: 'when acceleration [DIRECTION] [COMPARE] [VALUE] m/s\u{00B2}', + description: 'when the value measured by the acceleration sensor is compared to some value' + }), + blockType: BlockType.HAT, + arguments: { + DIRECTION: { + type: ArgumentType.STRING, + menu: 'directionOptions', + defaultValue: 0 + }, + COMPARE: { + type: ArgumentType.STRING, + menu: 'compareOptions', + defaultValue: 0 + }, + VALUE: { + type: ArgumentType.NUMBER, + defaultValue: 5 + } + } + }, + { + opcode: 'whenTiltCompare', + text: formatMessage({ + id: 'ev3.whenTitleCompare', + default: 'when tilt [DIRECTION] [COMPARE] [VALUE] rad/s', + description: 'when the value measured by the acceleration sensor is compared to some value' + }), + blockType: BlockType.HAT, + arguments: { + DIRECTION: { + type: ArgumentType.STRING, + menu: 'directionOptions', + defaultValue: 0 + }, + COMPARE: { + type: ArgumentType.STRING, + menu: 'compareOptions', + defaultValue: 0 + }, + VALUE: { + type: ArgumentType.NUMBER, + defaultValue: 5 + } + } + }, + { + opcode: 'whenForceCompare', + text: formatMessage({ + id: 'ev3.whenForceCompare', + default: 'when force [COMPARE] [VALUE] N', + description: 'when the value measured by the force sensor is compared to some value' + }), + blockType: BlockType.HAT, + arguments: { + COMPARE: { + type: ArgumentType.STRING, + menu: 'compareOptions', + defaultValue: 0 + }, + VALUE: { + type: ArgumentType.NUMBER, + defaultValue: 5 + } + } + }, + { + opcode: 'getAcceleration', + text: formatMessage({ + id: 'ev3.getAcceleration', + default: 'acceleration [DIRECTION]', + description: 'gets acceleration' + }), + blockType: BlockType.REPORTER, + arguments: { + DIRECTION: { + type: ArgumentType.STRING, + menu: 'directionOptions', + defaultValue: 0 + } + } + }, + { + opcode: 'getTilt', + text: formatMessage({ + id: 'ev3.getTitle', + default: 'tilt [DIRECTION]', + description: 'gets tilt' + }), + blockType: BlockType.REPORTER, + arguments: { + DIRECTION: { + type: ArgumentType.STRING, + menu: 'directionOptions', + defaultValue: 0 + } + } + }, + { + opcode: 'getForce', + text: formatMessage({ + id: 'ev3.getForce', + default: 'force', + description: 'gets force' + }), + blockType: BlockType.REPORTER + } + ], + menus: { + directionOptions: this._formatMenu(DirectionOptionsMenu), + compareOptions: this._formatMenu(CompareOptionsMenu), + motorPorts: this._formatMenu(Ev3MotorMenu), + sensorPorts: this._formatMenu(Ev3SensorMenu) + } + }; + } + + whenAccelerationCompare (args) { + return Promise.resolve(); + } + whenTiltCompare (args) { + return Promise.resolve(); + } + whenForceCompare (args) { + return Promise.resolve(); + } + getAcceleration (args) { + return Promise.resolve(); + } + getTilt (args) { + return Promise.resolve(); + } + getForce (args) { + return Promise.resolve(); + } + +} + +module.exports = Scratch3GoForceBlocks; From 1503b0add97bb32a33161dcf4b1a956ef8590e27 Mon Sep 17 00:00:00 2001 From: Valerie R Young Date: Thu, 6 Dec 2018 17:08:24 -0500 Subject: [PATCH 02/32] Add some names --- src/extensions/scratch3_goforce/index.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/extensions/scratch3_goforce/index.js b/src/extensions/scratch3_goforce/index.js index d7ae9b65b..02d1b6483 100644 --- a/src/extensions/scratch3_goforce/index.js +++ b/src/extensions/scratch3_goforce/index.js @@ -23,6 +23,20 @@ const DirectionOptionsMenu = ['x', 'y', 'z']; */ class Scratch3GoForceBlocks { + /** + * @return {string} - the name of this extension. + */ + static get EXTENSION_NAME () { + return 'Go!Force'; + } + + /** + * @return {string} - the ID of this extension. + */ + static get EXTENSION_ID () { + return 'goforce'; + } + /** * Construct a set of GoForce blocks. * @param {Runtime} runtime - the Scratch 3.0 runtime. From e209ec32409367e1601284979a87bb91cd76db56 Mon Sep 17 00:00:00 2001 From: Valerie R Young Date: Thu, 6 Dec 2018 17:33:44 -0500 Subject: [PATCH 03/32] satisfy linter --- src/extensions/scratch3_goforce/index.js | 38 +++++++++++------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/extensions/scratch3_goforce/index.js b/src/extensions/scratch3_goforce/index.js index 02d1b6483..d52d1b238 100644 --- a/src/extensions/scratch3_goforce/index.js +++ b/src/extensions/scratch3_goforce/index.js @@ -1,10 +1,10 @@ const ArgumentType = require('../../extension-support/argument-type'); const BlockType = require('../../extension-support/block-type'); -const log = require('../../util/log'); -const cast = require('../../util/cast'); +// const log = require('../../util/log'); +// const cast = require('../../util/cast'); const formatMessage = require('format-message'); -const BLE = require('../../io/ble'); -const Base64Util = require('../../util/base64-util'); +// const BLE = require('../../io/ble'); +// const Base64Util = require('../../util/base64-util'); /** * Icon png to be displayed at the left edge of each extension block, encoded as a data URI. @@ -27,7 +27,7 @@ class Scratch3GoForceBlocks { * @return {string} - the name of this extension. */ static get EXTENSION_NAME () { - return 'Go!Force'; + return 'Go! Force'; } /** @@ -62,7 +62,7 @@ class Scratch3GoForceBlocks { { opcode: 'whenAccelerationCompare', text: formatMessage({ - id: 'ev3.whenAccelerationCompare', + id: 'goforce.whenAccelerationCompare', default: 'when acceleration [DIRECTION] [COMPARE] [VALUE] m/s\u{00B2}', description: 'when the value measured by the acceleration sensor is compared to some value' }), @@ -87,7 +87,7 @@ class Scratch3GoForceBlocks { { opcode: 'whenTiltCompare', text: formatMessage({ - id: 'ev3.whenTitleCompare', + id: 'goforce.whenTitleCompare', default: 'when tilt [DIRECTION] [COMPARE] [VALUE] rad/s', description: 'when the value measured by the acceleration sensor is compared to some value' }), @@ -112,7 +112,7 @@ class Scratch3GoForceBlocks { { opcode: 'whenForceCompare', text: formatMessage({ - id: 'ev3.whenForceCompare', + id: 'goforce.whenForceCompare', default: 'when force [COMPARE] [VALUE] N', description: 'when the value measured by the force sensor is compared to some value' }), @@ -132,7 +132,7 @@ class Scratch3GoForceBlocks { { opcode: 'getAcceleration', text: formatMessage({ - id: 'ev3.getAcceleration', + id: 'goforce.getAcceleration', default: 'acceleration [DIRECTION]', description: 'gets acceleration' }), @@ -148,7 +148,7 @@ class Scratch3GoForceBlocks { { opcode: 'getTilt', text: formatMessage({ - id: 'ev3.getTitle', + id: 'goforce.getTitle', default: 'tilt [DIRECTION]', description: 'gets tilt' }), @@ -164,7 +164,7 @@ class Scratch3GoForceBlocks { { opcode: 'getForce', text: formatMessage({ - id: 'ev3.getForce', + id: 'goforce.getForce', default: 'force', description: 'gets force' }), @@ -173,29 +173,27 @@ class Scratch3GoForceBlocks { ], menus: { directionOptions: this._formatMenu(DirectionOptionsMenu), - compareOptions: this._formatMenu(CompareOptionsMenu), - motorPorts: this._formatMenu(Ev3MotorMenu), - sensorPorts: this._formatMenu(Ev3SensorMenu) + compareOptions: this._formatMenu(CompareOptionsMenu) } }; } - whenAccelerationCompare (args) { + whenAccelerationCompare () { return Promise.resolve(); } - whenTiltCompare (args) { + whenTiltCompare () { return Promise.resolve(); } - whenForceCompare (args) { + whenForceCompare () { return Promise.resolve(); } - getAcceleration (args) { + getAcceleration () { return Promise.resolve(); } - getTilt (args) { + getTilt () { return Promise.resolve(); } - getForce (args) { + getForce () { return Promise.resolve(); } From e4d9f9cdffd99d5a5d87c44bfe09996a734f03fd Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Tue, 11 Dec 2018 12:31:42 -0500 Subject: [PATCH 04/32] tilt to speed --- src/extensions/scratch3_goforce/index.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/extensions/scratch3_goforce/index.js b/src/extensions/scratch3_goforce/index.js index d52d1b238..9290b5885 100644 --- a/src/extensions/scratch3_goforce/index.js +++ b/src/extensions/scratch3_goforce/index.js @@ -85,11 +85,11 @@ class Scratch3GoForceBlocks { } }, { - opcode: 'whenTiltCompare', + opcode: 'whenAngularSpeedCompare', text: formatMessage({ - id: 'goforce.whenTitleCompare', - default: 'when tilt [DIRECTION] [COMPARE] [VALUE] rad/s', - description: 'when the value measured by the acceleration sensor is compared to some value' + id: 'goforce.whenAngularSpeedCompare', + default: 'when angular speed [DIRECTION] [COMPARE] [VALUE] rad/s', + description: 'when the value measured by the gyroscope sensor is compared to some value' }), blockType: BlockType.HAT, arguments: { @@ -146,10 +146,10 @@ class Scratch3GoForceBlocks { } }, { - opcode: 'getTilt', + opcode: 'getAngularSpeed', text: formatMessage({ - id: 'goforce.getTitle', - default: 'tilt [DIRECTION]', + id: 'goforce.getAngularSpeed', + default: 'angular speed [DIRECTION]', description: 'gets tilt' }), blockType: BlockType.REPORTER, @@ -181,7 +181,7 @@ class Scratch3GoForceBlocks { whenAccelerationCompare () { return Promise.resolve(); } - whenTiltCompare () { + whenAngularSpeedCompare () { return Promise.resolve(); } whenForceCompare () { @@ -190,7 +190,7 @@ class Scratch3GoForceBlocks { getAcceleration () { return Promise.resolve(); } - getTilt () { + getAngularSpeed () { return Promise.resolve(); } getForce () { From c305379393baed9975e9e631e9aa13e54015a4a4 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Tue, 11 Dec 2018 14:53:38 -0500 Subject: [PATCH 05/32] format menu --- src/extensions/scratch3_goforce/index.js | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/extensions/scratch3_goforce/index.js b/src/extensions/scratch3_goforce/index.js index 9290b5885..d858a7bb6 100644 --- a/src/extensions/scratch3_goforce/index.js +++ b/src/extensions/scratch3_goforce/index.js @@ -197,6 +197,35 @@ class Scratch3GoForceBlocks { return Promise.resolve(); } + /** + * Formats menus into a format suitable for block menus, and loading previously + * saved projects: + * [ + * { + * text: label, + * value: index + * }, + * { + * text: label, + * value: index + * }, + * etc... + * ] + * + * @param {array} menu - a menu to format. + * @return {object} - a formatted menu as an object. + * @private + */ + _formatMenu (menu) { + const m = []; + for (let i = 0; i < menu.length; i++) { + const obj = {}; + obj.text = menu[i]; + obj.value = i.toString(); + m.push(obj); + } + return m; + } } module.exports = Scratch3GoForceBlocks; From a0bf69f17cacc49ee50fa056bc386ed2da89c196 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Tue, 11 Dec 2018 14:56:19 -0500 Subject: [PATCH 06/32] Change extension name --- src/extension-support/extension-manager.js | 4 +-- .../index.js | 28 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) rename src/extensions/{scratch3_goforce => scratch3_gdx_for}/index.js (94%) diff --git a/src/extension-support/extension-manager.js b/src/extension-support/extension-manager.js index 11b6f3366..50f11dcdb 100644 --- a/src/extension-support/extension-manager.js +++ b/src/extension-support/extension-manager.js @@ -17,7 +17,7 @@ const Scratch3VideoSensingBlocks = require('../extensions/scratch3_video_sensing const Scratch3Speech2TextBlocks = require('../extensions/scratch3_speech2text'); const Scratch3Ev3Blocks = require('../extensions/scratch3_ev3'); const Scratch3MakeyMakeyBlocks = require('../extensions/scratch3_makeymakey'); -const Scratch3GoForceBlocks = require('../extensions/scratch3_goforce'); +const Scratch3GdxForBlocks = require('../extensions/scratch3_gdx_for'); const builtinExtensions = { pen: Scratch3PenBlocks, @@ -30,7 +30,7 @@ const builtinExtensions = { speech2text: Scratch3Speech2TextBlocks, ev3: Scratch3Ev3Blocks, makeymakey: Scratch3MakeyMakeyBlocks, - goforce: Scratch3GoForceBlocks + gdxfor: Scratch3GdxForBlocks }; /** diff --git a/src/extensions/scratch3_goforce/index.js b/src/extensions/scratch3_gdx_for/index.js similarity index 94% rename from src/extensions/scratch3_goforce/index.js rename to src/extensions/scratch3_gdx_for/index.js index d858a7bb6..8cb75627e 100644 --- a/src/extensions/scratch3_goforce/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -19,26 +19,26 @@ const DirectionOptionsMenu = ['x', 'y', 'z']; /** - * Scratch 3.0 blocks to interact with a GoForce peripheral. + * Scratch 3.0 blocks to interact with a GDX-FOR peripheral. */ -class Scratch3GoForceBlocks { +class Scratch3GdxForBlocks { /** * @return {string} - the name of this extension. */ static get EXTENSION_NAME () { - return 'Go! Force'; + return 'GDX-FOR'; } /** * @return {string} - the ID of this extension. */ static get EXTENSION_ID () { - return 'goforce'; + return 'gdxfor'; } /** - * Construct a set of GoForce blocks. + * Construct a set of GDX-FOR blocks. * @param {Runtime} runtime - the Scratch 3.0 runtime. */ constructor (runtime) { @@ -54,15 +54,15 @@ class Scratch3GoForceBlocks { */ getInfo () { return { - id: Scratch3GoForceBlocks.EXTENSION_ID, - name: Scratch3GoForceBlocks.EXTENSION_NAME, + id: Scratch3GdxForBlocks.EXTENSION_ID, + name: Scratch3GdxForBlocks.EXTENSION_NAME, blockIconURI: blockIconURI, showStatusButton: true, blocks: [ { opcode: 'whenAccelerationCompare', text: formatMessage({ - id: 'goforce.whenAccelerationCompare', + id: 'gdxfor.whenAccelerationCompare', default: 'when acceleration [DIRECTION] [COMPARE] [VALUE] m/s\u{00B2}', description: 'when the value measured by the acceleration sensor is compared to some value' }), @@ -87,7 +87,7 @@ class Scratch3GoForceBlocks { { opcode: 'whenAngularSpeedCompare', text: formatMessage({ - id: 'goforce.whenAngularSpeedCompare', + id: 'gdxfor.whenAngularSpeedCompare', default: 'when angular speed [DIRECTION] [COMPARE] [VALUE] rad/s', description: 'when the value measured by the gyroscope sensor is compared to some value' }), @@ -112,7 +112,7 @@ class Scratch3GoForceBlocks { { opcode: 'whenForceCompare', text: formatMessage({ - id: 'goforce.whenForceCompare', + id: 'gdxfor.whenForceCompare', default: 'when force [COMPARE] [VALUE] N', description: 'when the value measured by the force sensor is compared to some value' }), @@ -132,7 +132,7 @@ class Scratch3GoForceBlocks { { opcode: 'getAcceleration', text: formatMessage({ - id: 'goforce.getAcceleration', + id: 'gdxfor.getAcceleration', default: 'acceleration [DIRECTION]', description: 'gets acceleration' }), @@ -148,7 +148,7 @@ class Scratch3GoForceBlocks { { opcode: 'getAngularSpeed', text: formatMessage({ - id: 'goforce.getAngularSpeed', + id: 'gdxfor.getAngularSpeed', default: 'angular speed [DIRECTION]', description: 'gets tilt' }), @@ -164,7 +164,7 @@ class Scratch3GoForceBlocks { { opcode: 'getForce', text: formatMessage({ - id: 'goforce.getForce', + id: 'gdxfor.getForce', default: 'force', description: 'gets force' }), @@ -228,4 +228,4 @@ class Scratch3GoForceBlocks { } } -module.exports = Scratch3GoForceBlocks; +module.exports = Scratch3GdxForBlocks; From d70fb96d0106e820edf42406c249264371707b1f Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Mon, 17 Dec 2018 18:07:46 -0500 Subject: [PATCH 07/32] Force working with vernier node module --- src/extensions/scratch3_gdx_for/index.js | 277 ++++++++++++++++++++++- 1 file changed, 274 insertions(+), 3 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index 8cb75627e..bc244a227 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -3,8 +3,11 @@ const BlockType = require('../../extension-support/block-type'); // const log = require('../../util/log'); // const cast = require('../../util/cast'); const formatMessage = require('format-message'); -// const BLE = require('../../io/ble'); -// const Base64Util = require('../../util/base64-util'); +const BLE = require('../../io/ble'); +const Base64Util = require('../../util/base64-util'); +const GdxCommands = require('./gdx-commands'); +//const ScratchLinkProxy = require('./scratch-link-proxy'); +const createDevice = require('@vernier/godirect/src/godirect').default.createDevice; /** * Icon png to be displayed at the left edge of each extension block, encoded as a data URI. @@ -13,6 +16,271 @@ const formatMessage = require('format-message'); // eslint-disable-next-line max-len const blockIconURI = 'data:image/png;base64,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'; +/** + * Enum for GDX-FOR protocol. + * @readonly + * @enum {string} + */ +const BLEUUID = { + service: 'd91714ef-28b9-4f91-ba16-f0d9a604f112', + txChar: 'f4bf14a6-c7d5-4b6d-8aa8-df1a7c83adcb', + rxChar: 'b41e6675-a329-40e0-aa01-44d2f444babe' +}; + +const BLETimeout = 4500; + +/** + * Manage communication with a GDX-FOR peripheral over a Scratch Link client socket. + */ +class GdxFor { + + /** + * Construct a GDX-FOR communication object. + * @param {Runtime} runtime - the Scratch 3.0 runtime + * @param {string} extensionId - the id of the extension + */ + constructor (runtime, extensionId) { + + /** + * The Scratch 3.0 runtime used to trigger the green flag button. + * @type {Runtime} + * @private + */ + this._runtime = runtime; + + /** + * The BluetoothLowEnergy connection socket for reading/writing peripheral data. + * @type {BLE} + * @private + */ + this._ble = null; + this._runtime.registerPeripheralExtension(extensionId, this); + + /** + * The id of the extension this peripheral belongs to. + */ + this._extensionId = extensionId; + + /** + * The most recently received value for each sensor. + * @type {Object.} + * @private + */ + this._sensors = { + force: 0, + accelerationX: 0, + accelerationY: 0, + accelerationX: 0, + angularVelocityX: 0, + angularVelocityY: 0, + angularVelocityX: 0, + }; + + /** + * Interval ID for data reading timeout. + * @type {number} + * @private + */ + this._timeoutID = null; + + /** + * A flag that is true while we are busy sending data to the BLE socket. + * @type {boolean} + * @private + */ + this._busy = false; + + /** + * ID for a timeout which is used to clear the busy flag if it has been + * true for a long time. + */ + this._busyTimeoutID = null; + + this.disconnect = this.disconnect.bind(this); + this._onConnect = this._onConnect.bind(this); + this._onMessage = this._onMessage.bind(this); + + this._connected = false; + } + + + /** + * Called by the runtime when user wants to scan for a peripheral. + */ + scan () { + if (this._ble) { + this._ble.close(); + // this._ble.disconnect(); //scratch-link + } + + console.log("Requesting Device"); + navigator.bluetooth.requestDevice({ + filters: [{ namePrefix: 'GDX' }], + optionalServices: ['d91714ef-28b9-4f91-ba16-f0d9a604f112'] + }).then((bleWbtDevice) => { + console.log("Got device: ", bleWbtDevice); + return createDevice(bleWbtDevice, {open: false}); + }).then((device) => { + console.log("Created BLE object: ", device); + this._ble = device; + this._ble.open(false); // should emit a "device-opened" event when opened + this._ble.on('device-opened', this._onConnect); + this._ble.on('device-closed', this._onClose); + }).catch((error) => { + console.log(error); + }); + + + // scratch-link + // this._ble = new BLE(this._runtime, this._extensionId, { + // filters: [ + // { namePrefix: 'GDX' } + // ], + // optionalServices: [ + // BLEUUID.service + // ] + // }, this._onConnect); + } + + /** + * Called by the runtime when user wants to connect to a certain peripheral. + * @param {number} id - the id of the peripheral to connect to. + */ + connect (id) { + if (this._ble) { + this._ble.connectPeripheral(id); + } + } + + /** + * Called by the runtime when a use exits the connection popup. + * Disconnect from the micro:bit. + */ + disconnect () { + // TODO: This funciton is called when you exist the connection popup. + // When using Web Bluetooth, we don't use the connection popup. + // When switching over from web bluetooth, make sure to figure out to handle + // this disconnection. + window.clearInterval(this._timeoutID); + if (this._ble) { + //this._ble.disconnect(); + } + } + + /** + * Return true if connected to the micro:bit. + * @return {boolean} - whether the micro:bit is connected. + */ + isConnected () { + let connected = false; + if (this._ble) { + connected = this._connected; //this._ble.isConnected(); + } + console.log("Is connected: ", connected); + return connected; + } + + /** + * Send a message to the peripheral BLE socket. + * @param {number} command - the BLE command hex. + * @param {Uint8Array} message - the message to write + */ + send (command, message) { + if (!this.isConnected()) return; + + debugger; + + const output = new Uint8Array(message.length + 1); + output[0] = command; // attach command to beginning of message + for (let i = 0; i < message.length; i++) { + output[i + 1] = message[i]; + } + //const output = [0x58, 0x19, 0xfe, 0x3f, 0x1a, 0xa5, 0x4a, 0x06, 0x49, 0x07, 0x48, 0x08, 0x47, 0x09, 0x46, 0x0a, 0x45, 0x0b, 0x44, 0x0c, 0x43, 0x0d, 0x42, 0x0e, 0x41]; + + //const output = new Uint8Array([0x58, 0x19, 0xfe, 0x3f, 0x1a, 0xa5, 0x4a, 0x06, 0x49, 0x07, 0x48, 0x08, 0x47, 0x09, 0x46, 0x0a, 0x45, 0x0b, 0x44, 0x0c, 0x43, 0x0d, 0x42, 0x0e, 0x41]); + console.log(output); + + const data = Base64Util.uint8ArrayToBase64(output); + console.log(data); + // WBn+PxqlSgZJB0gIRwlGCkULRAxDDUIOQQ== + + this._ble.write(BLEUUID.service, BLEUUID.txChar, data, 'base64', true).then( + () => { + this._busy = false; + } + ); + } + + /** + * Starts reading data from peripheral after BLE has connected to it. + * @private + */ + _onConnect () { + console.log("CONNNECTED"); + this._connected = true; + + this._ble.sensors.forEach(sensor => { + sensor.setEnabled(true); + + // do some calculations? + sensor.on('value-changed', (sensor) => { + + // We don't need this list, essentially. + if (sensor.values.length > 1000) { + sensor.clear(); + } + }); + + }); + this._ble.start(); // Can set period here. + //this.send(GdxCommands.INIT, ''); + + //this._ble.read(BLEUUID.service, BLEUUID.rxChar, true, this._onMessage); + + //this._timeoutID = window.setInterval(this.disconnect, BLETimeout); + } + + getForce () { + return this._ble.getSensor(1).value; + } + + _onClose () { + this._connected = false; + } + + /** + * Process the sensor data from the incoming BLE characteristic. + * @param {object} base64 - the incoming BLE data. + * @private + */ + _onMessage (base64) { + console.log("In _onMessage"); + // parse data + const data = Base64Util.base64ToUint8Array(base64); + console.log("data: ", data); + + // this._sensors.tiltX = data[1] | (data[0] << 8); + // if (this._sensors.tiltX > (1 << 15)) this._sensors.tiltX -= (1 << 16); + // this._sensors.tiltY = data[3] | (data[2] << 8); + // if (this._sensors.tiltY > (1 << 15)) this._sensors.tiltY -= (1 << 16); + + // this._sensors.buttonA = data[4]; + // this._sensors.buttonB = data[5]; + + // this._sensors.touchPins[0] = data[6]; + // this._sensors.touchPins[1] = data[7]; + // this._sensors.touchPins[2] = data[8]; + + // this._sensors.gestureState = data[9]; + + // // cancel disconnect timeout and start a new one + // window.clearInterval(this._timeoutID); + // this._timeoutID = window.setInterval(this.disconnect, BLETimeout); + } + +} + + const CompareOptionsMenu = ['>', '<', '=']; const DirectionOptionsMenu = ['x', 'y', 'z']; @@ -47,6 +315,9 @@ class Scratch3GdxForBlocks { * @type {Runtime} */ this.runtime = runtime; + + // Create a new GdxFor peripheral instance + this._peripheral = new GdxFor(this.runtime, Scratch3GdxForBlocks.EXTENSION_ID); } /** @@ -194,7 +465,7 @@ class Scratch3GdxForBlocks { return Promise.resolve(); } getForce () { - return Promise.resolve(); + return this._peripheral.getForce(); } /** From 14712486579022038b331934b318c624e8f98461 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Mon, 17 Dec 2018 21:04:15 -0500 Subject: [PATCH 08/32] Clean up and all sensors working --- src/extensions/scratch3_gdx_for/index.js | 284 +++++++++-------------- 1 file changed, 104 insertions(+), 180 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index bc244a227..ec29cb713 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -1,11 +1,10 @@ const ArgumentType = require('../../extension-support/argument-type'); const BlockType = require('../../extension-support/block-type'); -// const log = require('../../util/log'); +const log = require('../../util/log'); // const cast = require('../../util/cast'); const formatMessage = require('format-message'); const BLE = require('../../io/ble'); const Base64Util = require('../../util/base64-util'); -const GdxCommands = require('./gdx-commands'); //const ScratchLinkProxy = require('./scratch-link-proxy'); const createDevice = require('@vernier/godirect/src/godirect').default.createDevice; @@ -16,19 +15,6 @@ const createDevice = require('@vernier/godirect/src/godirect').default.createDev // eslint-disable-next-line max-len const blockIconURI = 'data:image/png;base64,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'; -/** - * Enum for GDX-FOR protocol. - * @readonly - * @enum {string} - */ -const BLEUUID = { - service: 'd91714ef-28b9-4f91-ba16-f0d9a604f112', - txChar: 'f4bf14a6-c7d5-4b6d-8aa8-df1a7c83adcb', - rxChar: 'b41e6675-a329-40e0-aa01-44d2f444babe' -}; - -const BLETimeout = 4500; - /** * Manage communication with a GDX-FOR peripheral over a Scratch Link client socket. */ @@ -76,29 +62,8 @@ class GdxFor { angularVelocityX: 0, }; - /** - * Interval ID for data reading timeout. - * @type {number} - * @private - */ - this._timeoutID = null; - - /** - * A flag that is true while we are busy sending data to the BLE socket. - * @type {boolean} - * @private - */ - this._busy = false; - - /** - * ID for a timeout which is used to clear the busy flag if it has been - * true for a long time. - */ - this._busyTimeoutID = null; - this.disconnect = this.disconnect.bind(this); this._onConnect = this._onConnect.bind(this); - this._onMessage = this._onMessage.bind(this); this._connected = false; } @@ -110,36 +75,19 @@ class GdxFor { scan () { if (this._ble) { this._ble.close(); - // this._ble.disconnect(); //scratch-link } - console.log("Requesting Device"); navigator.bluetooth.requestDevice({ filters: [{ namePrefix: 'GDX' }], optionalServices: ['d91714ef-28b9-4f91-ba16-f0d9a604f112'] }).then((bleWbtDevice) => { - console.log("Got device: ", bleWbtDevice); return createDevice(bleWbtDevice, {open: false}); }).then((device) => { - console.log("Created BLE object: ", device); this._ble = device; - this._ble.open(false); // should emit a "device-opened" event when opened + this._ble.open(false); // false prevents starting of measurements this._ble.on('device-opened', this._onConnect); this._ble.on('device-closed', this._onClose); - }).catch((error) => { - console.log(error); }); - - - // scratch-link - // this._ble = new BLE(this._runtime, this._extensionId, { - // filters: [ - // { namePrefix: 'GDX' } - // ], - // optionalServices: [ - // BLEUUID.service - // ] - // }, this._onConnect); } /** @@ -157,13 +105,8 @@ class GdxFor { * Disconnect from the micro:bit. */ disconnect () { - // TODO: This funciton is called when you exist the connection popup. - // When using Web Bluetooth, we don't use the connection popup. - // When switching over from web bluetooth, make sure to figure out to handle - // this disconnection. - window.clearInterval(this._timeoutID); if (this._ble) { - //this._ble.disconnect(); + this._ble.close(); } } @@ -174,55 +117,22 @@ class GdxFor { isConnected () { let connected = false; if (this._ble) { - connected = this._connected; //this._ble.isConnected(); + connected = this._connected; } - console.log("Is connected: ", connected); return connected; } - /** - * Send a message to the peripheral BLE socket. - * @param {number} command - the BLE command hex. - * @param {Uint8Array} message - the message to write - */ - send (command, message) { - if (!this.isConnected()) return; - - debugger; - - const output = new Uint8Array(message.length + 1); - output[0] = command; // attach command to beginning of message - for (let i = 0; i < message.length; i++) { - output[i + 1] = message[i]; - } - //const output = [0x58, 0x19, 0xfe, 0x3f, 0x1a, 0xa5, 0x4a, 0x06, 0x49, 0x07, 0x48, 0x08, 0x47, 0x09, 0x46, 0x0a, 0x45, 0x0b, 0x44, 0x0c, 0x43, 0x0d, 0x42, 0x0e, 0x41]; - - //const output = new Uint8Array([0x58, 0x19, 0xfe, 0x3f, 0x1a, 0xa5, 0x4a, 0x06, 0x49, 0x07, 0x48, 0x08, 0x47, 0x09, 0x46, 0x0a, 0x45, 0x0b, 0x44, 0x0c, 0x43, 0x0d, 0x42, 0x0e, 0x41]); - console.log(output); - - const data = Base64Util.uint8ArrayToBase64(output); - console.log(data); - // WBn+PxqlSgZJB0gIRwlGCkULRAxDDUIOQQ== - - this._ble.write(BLEUUID.service, BLEUUID.txChar, data, 'base64', true).then( - () => { - this._busy = false; - } - ); - } - /** * Starts reading data from peripheral after BLE has connected to it. * @private */ _onConnect () { - console.log("CONNNECTED"); this._connected = true; this._ble.sensors.forEach(sensor => { sensor.setEnabled(true); - // do some calculations? + // do some calculations here? sensor.on('value-changed', (sensor) => { // We don't need this list, essentially. @@ -232,58 +142,52 @@ class GdxFor { }); }); - this._ble.start(); // Can set period here. - //this.send(GdxCommands.INIT, ''); - - //this._ble.read(BLEUUID.service, BLEUUID.rxChar, true, this._onMessage); - - //this._timeoutID = window.setInterval(this.disconnect, BLETimeout); + this._ble.start(); // Can set period here if needed. } getForce () { return this._ble.getSensor(1).value; } + getAccelerationX () { + return this._ble.getSensor(2).value; + } + + getAccelerationY () { + return this._ble.getSensor(3).value; + } + + getAccelerationZ () { + return this._ble.getSensor(4).value; + } + + getAngularSpeedX () { + return this._ble.getSensor(5).value; + } + + getAngularSpeedY () { + return this._ble.getSensor(6).value; + } + + getAngularSpeedZ () { + return this._ble.getSensor(7).value; + } + + _onClose () { this._connected = false; } - - /** - * Process the sensor data from the incoming BLE characteristic. - * @param {object} base64 - the incoming BLE data. - * @private - */ - _onMessage (base64) { - console.log("In _onMessage"); - // parse data - const data = Base64Util.base64ToUint8Array(base64); - console.log("data: ", data); - - // this._sensors.tiltX = data[1] | (data[0] << 8); - // if (this._sensors.tiltX > (1 << 15)) this._sensors.tiltX -= (1 << 16); - // this._sensors.tiltY = data[3] | (data[2] << 8); - // if (this._sensors.tiltY > (1 << 15)) this._sensors.tiltY -= (1 << 16); - - // this._sensors.buttonA = data[4]; - // this._sensors.buttonB = data[5]; - - // this._sensors.touchPins[0] = data[6]; - // this._sensors.touchPins[1] = data[7]; - // this._sensors.touchPins[2] = data[8]; - - // this._sensors.gestureState = data[9]; - - // // cancel disconnect timeout and start a new one - // window.clearInterval(this._timeoutID); - // this._timeoutID = window.setInterval(this.disconnect, BLETimeout); - } - } - -const CompareOptionsMenu = ['>', '<', '=']; - -const DirectionOptionsMenu = ['x', 'y', 'z']; +/** + * Enum for comparison operations. + * @readonly + * @enum {string} + */ +const ComparisonOptions = { + LESS_THAN: 'less_than', + GREATER_THAN: 'greater_than' +}; /** @@ -305,6 +209,37 @@ class Scratch3GdxForBlocks { return 'gdxfor'; } + get DIRECTIONS_MENU () { + return [ + { + text: 'x', + value: 'x' + }, + { + text: 'y', + value: 'y' + }, + { + text: 'z', + value: 'z' + } + ]; + } + + get COMPARE_MENU () { + return [ + { + text: '<', + value: ComparisonOptions.LESS_THAN + }, + { + text: '>', + value: ComparisonOptions.GREATER_THAN + } + ]; + } + + /** * Construct a set of GDX-FOR blocks. * @param {Runtime} runtime - the Scratch 3.0 runtime. @@ -342,12 +277,12 @@ class Scratch3GdxForBlocks { DIRECTION: { type: ArgumentType.STRING, menu: 'directionOptions', - defaultValue: 0 + defaultValue: 'x' }, COMPARE: { type: ArgumentType.STRING, menu: 'compareOptions', - defaultValue: 0 + defaultValue: ComparisonOptions.GREATER_THAN }, VALUE: { type: ArgumentType.NUMBER, @@ -367,12 +302,12 @@ class Scratch3GdxForBlocks { DIRECTION: { type: ArgumentType.STRING, menu: 'directionOptions', - defaultValue: 0 + defaultValue: 'x' }, COMPARE: { type: ArgumentType.STRING, menu: 'compareOptions', - defaultValue: 0 + defaultValue: ComparisonOptions.GREATER_THAN }, VALUE: { type: ArgumentType.NUMBER, @@ -392,7 +327,7 @@ class Scratch3GdxForBlocks { COMPARE: { type: ArgumentType.STRING, menu: 'compareOptions', - defaultValue: 0 + defaultValue: 'x' }, VALUE: { type: ArgumentType.NUMBER, @@ -412,7 +347,7 @@ class Scratch3GdxForBlocks { DIRECTION: { type: ArgumentType.STRING, menu: 'directionOptions', - defaultValue: 0 + defaultValue: 'x' } } }, @@ -421,14 +356,14 @@ class Scratch3GdxForBlocks { text: formatMessage({ id: 'gdxfor.getAngularSpeed', default: 'angular speed [DIRECTION]', - description: 'gets tilt' + description: 'gets angular speed' }), blockType: BlockType.REPORTER, arguments: { DIRECTION: { type: ArgumentType.STRING, menu: 'directionOptions', - defaultValue: 0 + defaultValue: 'x' } } }, @@ -443,8 +378,8 @@ class Scratch3GdxForBlocks { } ], menus: { - directionOptions: this._formatMenu(DirectionOptionsMenu), - compareOptions: this._formatMenu(CompareOptionsMenu) + directionOptions: this.DIRECTIONS_MENU, + compareOptions: this.COMPARE_MENU, } }; } @@ -458,45 +393,34 @@ class Scratch3GdxForBlocks { whenForceCompare () { return Promise.resolve(); } - getAcceleration () { - return Promise.resolve(); + getAcceleration (args) { + console.log(args); + switch (args.DIRECTION) { + case 'x': + return this._peripheral.getAccelerationX(); + case 'y': + return this._peripheral.getAccelerationY(); + case 'z': + return this._peripheral.getAccelerationZ(); + default: + log.warn(`Unknown direction in getAcceleration: ${args.DIRECTION}`); + } } - getAngularSpeed () { - return Promise.resolve(); + getAngularSpeed (args) { + switch (args.DIRECTION) { + case 'x': + return this._peripheral.getAngularSpeedX(); + case 'y': + return this._peripheral.getAngularSpeedY(); + case 'z': + return this._peripheral.getAngularSpeedZ(); + default: + log.warn(`Unknown direction in getAngularSpeed: ${args.DIRECTION}`); + } } getForce () { return this._peripheral.getForce(); } - - /** - * Formats menus into a format suitable for block menus, and loading previously - * saved projects: - * [ - * { - * text: label, - * value: index - * }, - * { - * text: label, - * value: index - * }, - * etc... - * ] - * - * @param {array} menu - a menu to format. - * @return {object} - a formatted menu as an object. - * @private - */ - _formatMenu (menu) { - const m = []; - for (let i = 0; i < menu.length; i++) { - const obj = {}; - obj.text = menu[i]; - obj.value = i.toString(); - m.push(obj); - } - return m; - } } module.exports = Scratch3GdxForBlocks; From deab7dd209d644b6a9e56d0c34a6b2fef91906d7 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Wed, 19 Dec 2018 11:21:23 -0500 Subject: [PATCH 09/32] Add @vernier/godirect module --- package.json | 1 + src/extensions/scratch3_gdx_for/index.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 2a6a8c248..d535bbcc6 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "version": "json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\"" }, "dependencies": { + "@vernier/godirect": "^1.0.3", "arraybuffer-loader": "^1.0.6", "atob": "2.1.2", "btoa": "1.2.1", diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index ec29cb713..bf73bdf61 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -6,7 +6,7 @@ const formatMessage = require('format-message'); const BLE = require('../../io/ble'); const Base64Util = require('../../util/base64-util'); //const ScratchLinkProxy = require('./scratch-link-proxy'); -const createDevice = require('@vernier/godirect/src/godirect').default.createDevice; +const createDevice = require('@vernier/godirect').default.createDevice; /** * Icon png to be displayed at the left edge of each extension block, encoded as a data URI. From a0cccba3be0af22087019c9c2d9334eb25d6dfa4 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Thu, 20 Dec 2018 10:11:28 -0500 Subject: [PATCH 10/32] satisfy linter --- src/extensions/scratch3_gdx_for/index.js | 48 +++++++++++------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index bf73bdf61..eda7cebc8 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -3,9 +3,7 @@ const BlockType = require('../../extension-support/block-type'); const log = require('../../util/log'); // const cast = require('../../util/cast'); const formatMessage = require('format-message'); -const BLE = require('../../io/ble'); -const Base64Util = require('../../util/base64-util'); -//const ScratchLinkProxy = require('./scratch-link-proxy'); +// const ScratchLinkProxy = require('./scratch-link-proxy'); const createDevice = require('@vernier/godirect').default.createDevice; /** @@ -53,13 +51,13 @@ class GdxFor { * @private */ this._sensors = { - force: 0, - accelerationX: 0, - accelerationY: 0, - accelerationX: 0, - angularVelocityX: 0, - angularVelocityY: 0, - angularVelocityX: 0, + force: 0, + accelerationX: 0, + accelerationY: 0, + accelerationZ: 0, + angularVelocityX: 0, + angularVelocityY: 0, + angularVelocityZ: 0 }; this.disconnect = this.disconnect.bind(this); @@ -78,16 +76,15 @@ class GdxFor { } navigator.bluetooth.requestDevice({ - filters: [{ namePrefix: 'GDX' }], + filters: [{namePrefix: 'GDX'}], optionalServices: ['d91714ef-28b9-4f91-ba16-f0d9a604f112'] - }).then((bleWbtDevice) => { - return createDevice(bleWbtDevice, {open: false}); - }).then((device) => { - this._ble = device; - this._ble.open(false); // false prevents starting of measurements - this._ble.on('device-opened', this._onConnect); - this._ble.on('device-closed', this._onClose); - }); + }).then(bleWbtDevice => createDevice(bleWbtDevice, {open: false})) + .then(device => { + this._ble = device; + this._ble.open(false); // false prevents starting of measurements + this._ble.on('device-opened', this._onConnect); + this._ble.on('device-closed', this._onClose); + }); } /** @@ -133,16 +130,16 @@ class GdxFor { sensor.setEnabled(true); // do some calculations here? - sensor.on('value-changed', (sensor) => { + sensor.on('value-changed', changedSensor => { // We don't need this list, essentially. - if (sensor.values.length > 1000) { - sensor.clear(); + if (changedSensor.values.length > 1000) { + changedSensor.clear(); } }); }); - this._ble.start(); // Can set period here if needed. + this._ble.start(); // Can set period here if needed. } getForce () { @@ -251,7 +248,7 @@ class Scratch3GdxForBlocks { */ this.runtime = runtime; - // Create a new GdxFor peripheral instance + // Create a new GdxFor peripheral instance this._peripheral = new GdxFor(this.runtime, Scratch3GdxForBlocks.EXTENSION_ID); } @@ -379,7 +376,7 @@ class Scratch3GdxForBlocks { ], menus: { directionOptions: this.DIRECTIONS_MENU, - compareOptions: this.COMPARE_MENU, + compareOptions: this.COMPARE_MENU } }; } @@ -394,7 +391,6 @@ class Scratch3GdxForBlocks { return Promise.resolve(); } getAcceleration (args) { - console.log(args); switch (args.DIRECTION) { case 'x': return this._peripheral.getAccelerationX(); From 12d696808e71eaa720b22fd852f7015109028dd2 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Thu, 20 Dec 2018 10:46:54 -0500 Subject: [PATCH 11/32] update @vernier/godirect --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d535bbcc6..fa88d3c86 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "version": "json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\"" }, "dependencies": { - "@vernier/godirect": "^1.0.3", + "@vernier/godirect": "^1.1.1", "arraybuffer-loader": "^1.0.6", "atob": "2.1.2", "btoa": "1.2.1", From 9a3517d8784888badb7824cb659c757c5bebe087 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Thu, 20 Dec 2018 15:33:58 -0500 Subject: [PATCH 12/32] First draft communication with scratch link and vernier --- src/extensions/scratch3_gdx_for/index.js | 152 +++++++++++++----- .../scratch-link-device-adapter.js | 56 +++++++ 2 files changed, 172 insertions(+), 36 deletions(-) create mode 100644 src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index eda7cebc8..aa155b1ea 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -3,8 +3,9 @@ const BlockType = require('../../extension-support/block-type'); const log = require('../../util/log'); // const cast = require('../../util/cast'); const formatMessage = require('format-message'); -// const ScratchLinkProxy = require('./scratch-link-proxy'); +const BLE = require('../../io/ble'); const createDevice = require('@vernier/godirect').default.createDevice; +const ScratchLinkDeviceAdapter = require('./scratch-link-device-adapter'); /** * Icon png to be displayed at the left edge of each extension block, encoded as a data URI. @@ -13,6 +14,18 @@ const createDevice = require('@vernier/godirect').default.createDevice; // eslint-disable-next-line max-len const blockIconURI = 'data:image/png;base64,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'; +/** + * Enum for Vernier godirect protocol. + * @readonly + * @enum {string} + */ +const BLEUUID = { + service: 'd91714ef-28b9-4f91-ba16-f0d9a604f112', + commandChar: 'f4bf14a6-c7d5-4b6d-8aa8-df1a7c83adcb', + responseChar: 'b41e6675-a329-40e0-aa01-44d2f444babe' +}; + + /** * Manage communication with a GDX-FOR peripheral over a Scratch Link client socket. */ @@ -37,7 +50,15 @@ class GdxFor { * @type {BLE} * @private */ - this._ble = null; + this._scratchLinkSocket = null; + + /** + * A godirect device + * @type {@vernier/goDirect device} + * @private + */ + this._device = null; + this._runtime.registerPeripheralExtension(extensionId, this); /** @@ -71,20 +92,18 @@ class GdxFor { * Called by the runtime when user wants to scan for a peripheral. */ scan () { - if (this._ble) { - this._ble.close(); + if (this._device) { + this._device.close(); } - navigator.bluetooth.requestDevice({ - filters: [{namePrefix: 'GDX'}], - optionalServices: ['d91714ef-28b9-4f91-ba16-f0d9a604f112'] - }).then(bleWbtDevice => createDevice(bleWbtDevice, {open: false})) - .then(device => { - this._ble = device; - this._ble.open(false); // false prevents starting of measurements - this._ble.on('device-opened', this._onConnect); - this._ble.on('device-closed', this._onClose); - }); + this._scratchLinkSocket = new BLE(this._runtime, this._extensionId, { + filters: [ + {namePrefix: 'GDX-FOR'} + ], + optionalServices: [ + BLEUUID.service + ] + }, this._onConnect); } /** @@ -92,28 +111,60 @@ class GdxFor { * @param {number} id - the id of the peripheral to connect to. */ connect (id) { - if (this._ble) { - this._ble.connectPeripheral(id); + if (this._scratchLinkSocket) { + this._scratchLinkSocket.connectPeripheral(id); + } + } + + /** + * Called by the runtime when a user exits the connection popup. + * Disconnect from the Gdx Force. + */ + disconnect () { + if (this._device) { + this._device.close(); + } + } + + /** + * Return true if connected to the goforce devie. + * @return {boolean} - whether the goforce is connected. + */ + isConnected () { + let connected = false; + if (this._device) { + connected = this._connected; + } + return connected; + } + + /** + * Called by the runtime when user wants to connect to a certain peripheral. + * @param {number} id - the id of the peripheral to connect to. + */ + connect (id) { + if (this._scratchLinkSocket) { + this._scratchLinkSocket.connectPeripheral(id); } } /** * Called by the runtime when a use exits the connection popup. - * Disconnect from the micro:bit. + * Disconnect from the GDX FOR. */ disconnect () { - if (this._ble) { - this._ble.close(); + if (this._device) { + this._device.close(); } } /** - * Return true if connected to the micro:bit. - * @return {boolean} - whether the micro:bit is connected. + * Return true if connected to the goforce devie. + * @return {boolean} - whether the goforce is connected. */ isConnected () { let connected = false; - if (this._ble) { + if (this._device) { connected = this._connected; } return connected; @@ -125,49 +176,78 @@ class GdxFor { */ _onConnect () { this._connected = true; + const adapter = new ScratchLinkDeviceAdapter(this._scratchLinkSocket); + createDevice(adapter, {open: true, startMeasurements: false}).then(device => { + this._device = device; + this._device.on('device-closed', this._onClose); + this._startMeasurements(); + }); + } - this._ble.sensors.forEach(sensor => { + /** + * Enable and begin reading measurements + * @private + */ + _startMeasurements () { + this._device.sensors.forEach(sensor => { sensor.setEnabled(true); - - // do some calculations here? sensor.on('value-changed', changedSensor => { - - // We don't need this list, essentially. if (changedSensor.values.length > 1000) { changedSensor.clear(); } }); - }); - this._ble.start(); // Can set period here if needed. + this._device.start(); // Can set period here if needed. } + getForce () { - return this._ble.getSensor(1).value; + if (this._device) { + return this._device.getSensor(1).value; + } + return 0; } getAccelerationX () { - return this._ble.getSensor(2).value; + if (this._device && this._connected) { + return this._device.getSensor(2).value; + } + return 0; } getAccelerationY () { - return this._ble.getSensor(3).value; + if (this._device && this._connected) { + return this._device.getSensor(3).value; + } + return 0; } getAccelerationZ () { - return this._ble.getSensor(4).value; + if (this._device && this._connected) { + return this._device.getSensor(4).value; + } + return 0; } getAngularSpeedX () { - return this._ble.getSensor(5).value; + if (this._device && this._connected) { + return this._device.getSensor(5).value; + } + return 0; } getAngularSpeedY () { - return this._ble.getSensor(6).value; + if (this._device && this._connected) { + return this._device.getSensor(6).value; + } + return 0; } getAngularSpeedZ () { - return this._ble.getSensor(7).value; + if (this._device && this._connected) { + return this._device.getSensor(7).value; + } + return 0; } diff --git a/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js b/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js new file mode 100644 index 000000000..e3d8beb2a --- /dev/null +++ b/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js @@ -0,0 +1,56 @@ +const Base64Util = require('../../util/base64-util'); + +/** + * Enum for Vernier godirect protocol. + * @readonly + * @enum {string} + */ +const BLEUUID = { + service: 'd91714ef-28b9-4f91-ba16-f0d9a604f112', + commandChar: 'f4bf14a6-c7d5-4b6d-8aa8-df1a7c83adcb', + responseChar: 'b41e6675-a329-40e0-aa01-44d2f444babe' +}; + +/** + * Adapter class + */ +class ScratchLinkDeviceAdapter { + constructor (scratchLinkNativeDevice) { + this.scratchLinkNativeDevice = scratchLinkNativeDevice; + + this._onResponse = this._onResponse.bind(this); + this._deviceOnResponse = null; + } + + get godirectAdapter () { + return true; + } + + writeCommand (commandBuffer) { + const data = Base64Util.uint8ArrayToBase64(commandBuffer); + + return this.scratchLinkNativeDevice + .write(BLEUUID.service, BLEUUID.commandChar, data, 'base64', true); + } + + setup ({onClosed, onResponse}) { + this._deviceOnResponse = onResponse; + return this.scratchLinkNativeDevice + .startNotifications(BLEUUID.service, BLEUUID.responseChar, this._onResponse); + + // TODO: + // How do we find out from scratch link if communication closes? + } + + _onResponse (base64) { + const array = Base64Util.base64ToUint8Array(base64); + const response = new DataView(array.buffer); + return this._deviceOnResponse(response); + } + + close () { + return this.scratchLinkNativeDevice.disconnect(); + } +} + +module.exports = ScratchLinkDeviceAdapter; From fb0c6baeeb65b8d00b437e8ab2dbcbc09cb9bcae Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Mon, 7 Jan 2019 13:12:30 -0500 Subject: [PATCH 13/32] Update package-lock.json --- package-lock.json | 103 +++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 57 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2d230b7b7..8851eb3b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1088,6 +1088,11 @@ } } }, + "@vernier/godirect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@vernier/godirect/-/godirect-1.1.1.tgz", + "integrity": "sha512-fmlQwVsjU9L7/kJSUv9/jGOsacQj1aTN/m/FtKi+61ebh588IiEusYSlQQmCpsfrZPVdfUc0H+t1b+ty3ZfhYQ==" + }, "@webassemblyjs/ast": { "version": "1.5.13", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.5.13.tgz", @@ -1537,7 +1542,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", "dev": true }, "arr-union": { @@ -1713,7 +1718,7 @@ }, "aws4": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "resolved": "http://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" }, "babel-code-frame": { @@ -2177,7 +2182,7 @@ }, "bl": { "version": "1.2.2", - "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "dev": true, "requires": { @@ -2231,7 +2236,7 @@ "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8=", "dev": true }, "body-parser": { @@ -2338,7 +2343,7 @@ }, "brfs": { "version": "1.6.1", - "resolved": "http://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz", + "resolved": "https://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz", "integrity": "sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ==", "dev": true, "requires": { @@ -2470,7 +2475,7 @@ "buffer-indexof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "integrity": "sha1-Uvq8xqYG0aADAoAmSO9o9jnaJow=", "dev": true }, "buffer-shims": { @@ -2672,7 +2677,7 @@ "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=", "dev": true, "requires": { "inherits": "^2.0.1", @@ -2797,12 +2802,12 @@ "color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI=", "dev": true }, "colors": { "version": "0.6.2", - "resolved": "http://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", "dev": true }, @@ -2945,7 +2950,7 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", "dev": true }, "convert-source-map": { @@ -3286,7 +3291,7 @@ "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "integrity": "sha1-OWz58xN/A+S45TLFj2mCVOAPgOw=", "dev": true, "requires": { "browserify-cipher": "^1.0.0", @@ -4380,7 +4385,7 @@ "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=", "dev": true, "requires": { "md5.js": "^1.3.4", @@ -4480,7 +4485,7 @@ }, "source-map": { "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", "dev": true, "requires": { @@ -4950,7 +4955,7 @@ "dependencies": { "commander": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz", "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=", "dev": true } @@ -5315,7 +5320,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -5509,14 +5514,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5531,20 +5534,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5661,8 +5661,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5674,7 +5673,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5689,7 +5687,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5697,14 +5694,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5723,7 +5718,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5804,8 +5798,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -5817,7 +5810,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5939,7 +5931,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6654,7 +6645,7 @@ }, "source-map": { "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", "dev": true, "requires": { @@ -6857,12 +6848,12 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", "dev": true }, "is-builtin-module": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { @@ -7631,7 +7622,7 @@ }, "magic-string": { "version": "0.22.5", - "resolved": "http://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", "dev": true, "requires": { @@ -7901,7 +7892,7 @@ "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "integrity": "sha1-8IA1HIZbDcViqEYpZtqlNUPHik0=", "dev": true, "requires": { "bn.js": "^4.0.0", @@ -7911,7 +7902,7 @@ "mime": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "integrity": "sha1-Eh+evEnjdm8xGnbh+hyAA8SwOqY=", "dev": true }, "mime-db": { @@ -8169,7 +8160,7 @@ }, "multipipe": { "version": "0.3.1", - "resolved": "http://registry.npmjs.org/multipipe/-/multipipe-0.3.1.tgz", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.3.1.tgz", "integrity": "sha1-kmJVJXYboE/qoJYFtjgrziyR8R8=", "dev": true, "requires": { @@ -8335,7 +8326,7 @@ "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", "dev": true, "requires": { "hosted-git-info": "^2.1.4", @@ -8419,7 +8410,6 @@ "version": "0.1.4", "bundled": true, "dev": true, - "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -9602,8 +9592,7 @@ "longest": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "loose-envify": { "version": "1.3.1", @@ -11270,7 +11259,7 @@ "p-map": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "integrity": "sha1-5OlPMR6rvIYzoeeZCBZfyiYkG2s=", "dev": true }, "p-try": { @@ -11460,7 +11449,7 @@ "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", "dev": true }, "pngjs": { @@ -12184,9 +12173,9 @@ } }, "scratch-render": { - "version": "0.1.0-prerelease.20181220195236", - "resolved": "https://registry.npmjs.org/scratch-render/-/scratch-render-0.1.0-prerelease.20181220195236.tgz", - "integrity": "sha512-FcYezDaztkoQifUG9k4uOsIFbelMt8JaCMpHrQis0QVJmjSuQrCDB3DRUjwpMuyUrmV7B7GdBUvwt65VYPZJ6g==", + "version": "0.1.0-prerelease.20190107163047", + "resolved": "https://registry.npmjs.org/scratch-render/-/scratch-render-0.1.0-prerelease.20190107163047.tgz", + "integrity": "sha512-pvyiU4FiUVEuxPc484A1UE3Dry06SIvy3OUqDs2rYu1NMw5+iwIkQLsHcpb7WLjmIFf41mh3h8GHKHHoZAOM4Q==", "dev": true, "requires": { "grapheme-breaker": "0.3.2", @@ -12450,7 +12439,7 @@ "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=", "dev": true }, "sha.js": { @@ -12767,7 +12756,7 @@ "source-list-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", - "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "integrity": "sha1-qqR0A/eyRakvvJfqCPJQ1gh+0IU=", "dev": true }, "source-map": { @@ -13124,7 +13113,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -13542,7 +13531,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", "dev": true, "requires": { "os-tmpdir": "~1.0.2" @@ -13863,7 +13852,7 @@ "dependencies": { "pako": { "version": "0.2.9", - "resolved": "http://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", "dev": true } From 4529533aa892000df3fa8c41e7b4eca3ac669506 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Mon, 7 Jan 2019 17:45:03 -0500 Subject: [PATCH 14/32] Remove accidental double declarations --- src/extensions/scratch3_gdx_for/index.js | 55 +++++------------------- 1 file changed, 10 insertions(+), 45 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index aa155b1ea..d23c9340f 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -83,8 +83,6 @@ class GdxFor { this.disconnect = this.disconnect.bind(this); this._onConnect = this._onConnect.bind(this); - - this._connected = false; } @@ -116,38 +114,6 @@ class GdxFor { } } - /** - * Called by the runtime when a user exits the connection popup. - * Disconnect from the Gdx Force. - */ - disconnect () { - if (this._device) { - this._device.close(); - } - } - - /** - * Return true if connected to the goforce devie. - * @return {boolean} - whether the goforce is connected. - */ - isConnected () { - let connected = false; - if (this._device) { - connected = this._connected; - } - return connected; - } - - /** - * Called by the runtime when user wants to connect to a certain peripheral. - * @param {number} id - the id of the peripheral to connect to. - */ - connect (id) { - if (this._scratchLinkSocket) { - this._scratchLinkSocket.connectPeripheral(id); - } - } - /** * Called by the runtime when a use exits the connection popup. * Disconnect from the GDX FOR. @@ -164,8 +130,8 @@ class GdxFor { */ isConnected () { let connected = false; - if (this._device) { - connected = this._connected; + if (this._scratchLinkSocket) { + connected = this._scratchLinkSocket.isConnected(); } return connected; } @@ -175,7 +141,6 @@ class GdxFor { * @private */ _onConnect () { - this._connected = true; const adapter = new ScratchLinkDeviceAdapter(this._scratchLinkSocket); createDevice(adapter, {open: true, startMeasurements: false}).then(device => { this._device = device; @@ -202,49 +167,49 @@ class GdxFor { getForce () { - if (this._device) { + if (this.isConnected()) { return this._device.getSensor(1).value; } return 0; } getAccelerationX () { - if (this._device && this._connected) { + if (this.isConnected()) { return this._device.getSensor(2).value; } return 0; } getAccelerationY () { - if (this._device && this._connected) { + if (this.isConnected()) { return this._device.getSensor(3).value; } return 0; } getAccelerationZ () { - if (this._device && this._connected) { + if (this.isConnected()) { return this._device.getSensor(4).value; } return 0; } getAngularSpeedX () { - if (this._device && this._connected) { + if (this.isConnected()) { return this._device.getSensor(5).value; } return 0; } getAngularSpeedY () { - if (this._device && this._connected) { + if (this.isConnected()) { return this._device.getSensor(6).value; } return 0; } getAngularSpeedZ () { - if (this._device && this._connected) { + if (this.isConnected()) { return this._device.getSensor(7).value; } return 0; @@ -252,7 +217,7 @@ class GdxFor { _onClose () { - this._connected = false; + this._scratchLinkSocket.disconnect(); } } From 4d75f7776c9f555ebf433743d98d42cbf819f946 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Mon, 7 Jan 2019 18:09:23 -0500 Subject: [PATCH 15/32] Remove the onClose skeletons --- src/extensions/scratch3_gdx_for/index.js | 6 ------ .../scratch3_gdx_for/scratch-link-device-adapter.js | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index d23c9340f..50026da19 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -144,7 +144,6 @@ class GdxFor { const adapter = new ScratchLinkDeviceAdapter(this._scratchLinkSocket); createDevice(adapter, {open: true, startMeasurements: false}).then(device => { this._device = device; - this._device.on('device-closed', this._onClose); this._startMeasurements(); }); } @@ -214,11 +213,6 @@ class GdxFor { } return 0; } - - - _onClose () { - this._scratchLinkSocket.disconnect(); - } } /** diff --git a/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js b/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js index e3d8beb2a..15083544a 100644 --- a/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js +++ b/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js @@ -33,7 +33,7 @@ class ScratchLinkDeviceAdapter { .write(BLEUUID.service, BLEUUID.commandChar, data, 'base64', true); } - setup ({onClosed, onResponse}) { + setup ({onResponse}) { this._deviceOnResponse = onResponse; return this.scratchLinkNativeDevice .startNotifications(BLEUUID.service, BLEUUID.responseChar, this._onResponse); From 5696b76d9a1367d7011cd348b28c4fc06e22010b Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Mon, 7 Jan 2019 18:17:20 -0500 Subject: [PATCH 16/32] fix typo --- src/extensions/scratch3_gdx_for/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index 50026da19..35fb93b30 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -125,7 +125,7 @@ class GdxFor { } /** - * Return true if connected to the goforce devie. + * Return true if connected to the goforce device. * @return {boolean} - whether the goforce is connected. */ isConnected () { From b5decacee20f16c22706134fb5d3247aebbc1b73 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Mon, 7 Jan 2019 18:20:45 -0500 Subject: [PATCH 17/32] update name of variable --- .../scratch3_gdx_for/scratch-link-device-adapter.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js b/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js index 15083544a..f9cb69495 100644 --- a/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js +++ b/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js @@ -15,8 +15,8 @@ const BLEUUID = { * Adapter class */ class ScratchLinkDeviceAdapter { - constructor (scratchLinkNativeDevice) { - this.scratchLinkNativeDevice = scratchLinkNativeDevice; + constructor (scratchLinkSocket) { + this.scratchLinkSocket = scratchLinkSocket; this._onResponse = this._onResponse.bind(this); this._deviceOnResponse = null; @@ -29,13 +29,13 @@ class ScratchLinkDeviceAdapter { writeCommand (commandBuffer) { const data = Base64Util.uint8ArrayToBase64(commandBuffer); - return this.scratchLinkNativeDevice + return this.scratchLinkSocket .write(BLEUUID.service, BLEUUID.commandChar, data, 'base64', true); } setup ({onResponse}) { this._deviceOnResponse = onResponse; - return this.scratchLinkNativeDevice + return this.scratchLinkSocket .startNotifications(BLEUUID.service, BLEUUID.responseChar, this._onResponse); // TODO: @@ -49,7 +49,7 @@ class ScratchLinkDeviceAdapter { } close () { - return this.scratchLinkNativeDevice.disconnect(); + return this.scratchLinkSocket.disconnect(); } } From 6288cfdd93d5f92adbb325fd569aa101a618ffa4 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Tue, 8 Jan 2019 09:21:36 -0500 Subject: [PATCH 18/32] update @vernier/godirect 1.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fa88d3c86..5861f4a60 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "version": "json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\"" }, "dependencies": { - "@vernier/godirect": "^1.1.1", + "@vernier/godirect": "^1.2.0", "arraybuffer-loader": "^1.0.6", "atob": "2.1.2", "btoa": "1.2.1", From 61b46af74b6e6b51c5c4e69266e3ca0f455ac3b6 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Tue, 8 Jan 2019 09:29:22 -0500 Subject: [PATCH 19/32] Update package-lock.json --- package-lock.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8851eb3b9..a282db4ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1089,9 +1089,9 @@ } }, "@vernier/godirect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@vernier/godirect/-/godirect-1.1.1.tgz", - "integrity": "sha512-fmlQwVsjU9L7/kJSUv9/jGOsacQj1aTN/m/FtKi+61ebh588IiEusYSlQQmCpsfrZPVdfUc0H+t1b+ty3ZfhYQ==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vernier/godirect/-/godirect-1.2.0.tgz", + "integrity": "sha512-VkkTap4MMFHAqHERotlU9EQ6AZYGuFqD5kR3t834xybPH+xbX3iNaKOVwsyG7eLapycNSTDYqJHwh9LqSN7T2A==" }, "@webassemblyjs/ast": { "version": "1.5.13", @@ -4485,7 +4485,7 @@ }, "source-map": { "version": "0.1.43", - "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", "dev": true, "requires": { @@ -6645,7 +6645,7 @@ }, "source-map": { "version": "0.1.43", - "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", "dev": true, "requires": { From be35eb1f70463bbe9676bc79944d28d615f7a56e Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Tue, 8 Jan 2019 11:15:55 -0500 Subject: [PATCH 20/32] remove units --- src/extensions/scratch3_gdx_for/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index 35fb93b30..8125d432d 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -305,8 +305,8 @@ class Scratch3GdxForBlocks { opcode: 'whenAccelerationCompare', text: formatMessage({ id: 'gdxfor.whenAccelerationCompare', - default: 'when acceleration [DIRECTION] [COMPARE] [VALUE] m/s\u{00B2}', - description: 'when the value measured by the acceleration sensor is compared to some value' + default: 'when acceleration [DIRECTION] [COMPARE] [VALUE]', + description: 'when the meters/second^2 value measured by the acceleration sensor is compared to some value' }), blockType: BlockType.HAT, arguments: { @@ -330,8 +330,8 @@ class Scratch3GdxForBlocks { opcode: 'whenAngularSpeedCompare', text: formatMessage({ id: 'gdxfor.whenAngularSpeedCompare', - default: 'when angular speed [DIRECTION] [COMPARE] [VALUE] rad/s', - description: 'when the value measured by the gyroscope sensor is compared to some value' + default: 'when angular speed [DIRECTION] [COMPARE] [VALUE]', + description: 'when the degrees/second value measured by the gyroscope sensor is compared to some value' }), blockType: BlockType.HAT, arguments: { @@ -355,7 +355,7 @@ class Scratch3GdxForBlocks { opcode: 'whenForceCompare', text: formatMessage({ id: 'gdxfor.whenForceCompare', - default: 'when force [COMPARE] [VALUE] N', + default: 'when force [COMPARE] [VALUE]', description: 'when the value measured by the force sensor is compared to some value' }), blockType: BlockType.HAT, From a0e1b5aa5b75d54876619b1051d63adae768a108 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Tue, 8 Jan 2019 11:53:51 -0500 Subject: [PATCH 21/32] Rename spin speed, make hat blocks work --- src/extensions/scratch3_gdx_for/index.js | 104 ++++++++++++++++++----- 1 file changed, 81 insertions(+), 23 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index 8125d432d..c7330c572 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -1,7 +1,7 @@ const ArgumentType = require('../../extension-support/argument-type'); const BlockType = require('../../extension-support/block-type'); const log = require('../../util/log'); -// const cast = require('../../util/cast'); +const Cast = require('../../util/cast'); const formatMessage = require('format-message'); const BLE = require('../../io/ble'); const createDevice = require('@vernier/godirect').default.createDevice; @@ -193,21 +193,21 @@ class GdxFor { return 0; } - getAngularSpeedX () { + getSpinSpeedX () { if (this.isConnected()) { return this._device.getSensor(5).value; } return 0; } - getAngularSpeedY () { + getSpinSpeedY () { if (this.isConnected()) { return this._device.getSensor(6).value; } return 0; } - getAngularSpeedZ () { + getSpinSpeedZ () { if (this.isConnected()) { return this._device.getSensor(7).value; } @@ -327,10 +327,10 @@ class Scratch3GdxForBlocks { } }, { - opcode: 'whenAngularSpeedCompare', + opcode: 'whenSpinSpeedCompare', text: formatMessage({ - id: 'gdxfor.whenAngularSpeedCompare', - default: 'when angular speed [DIRECTION] [COMPARE] [VALUE]', + id: 'gdxfor.whenSpinSpeedCompare', + default: 'when spin speed [DIRECTION] [COMPARE] [VALUE]', description: 'when the degrees/second value measured by the gyroscope sensor is compared to some value' }), blockType: BlockType.HAT, @@ -363,7 +363,7 @@ class Scratch3GdxForBlocks { COMPARE: { type: ArgumentType.STRING, menu: 'compareOptions', - defaultValue: 'x' + defaultValue: ComparisonOptions.GREATER_THAN }, VALUE: { type: ArgumentType.NUMBER, @@ -388,11 +388,11 @@ class Scratch3GdxForBlocks { } }, { - opcode: 'getAngularSpeed', + opcode: 'getSpinSpeed', text: formatMessage({ - id: 'gdxfor.getAngularSpeed', - default: 'angular speed [DIRECTION]', - description: 'gets angular speed' + id: 'gdxfor.getSpinSpeed', + default: 'spin speed [DIRECTION]', + description: 'gets spin speed' }), blockType: BlockType.REPORTER, arguments: { @@ -420,14 +420,72 @@ class Scratch3GdxForBlocks { }; } - whenAccelerationCompare () { - return Promise.resolve(); + whenAccelerationCompare (args) { + let currentVal = 0; + + switch (args.DIRECTION) { + case 'x': + currentVal = this._peripheral.getAccelerationX(); + break; + case 'y': + currentVal = this._peripheral.getAccelerationY(); + break; + case 'z': + currentVal = this._peripheral.getAccelerationZ(); + break; + default: + log.warn(`Unknown direction in whenAccelerationCompare: ${args.DIRECTION}`); + return false; + } + + switch (args.COMPARE) { + case ComparisonOptions.LESS_THAN: + return currentVal < Cast.toNumber(args.VALUE); + case ComparisonOptions.GREATER_THAN: + return currentVal > Cast.toNumber(args.VALUE); + default: + log.warn(`Unknown comparison operator in whenAccelerationCompare: ${args.COMPARE}`); + return false; + } } - whenAngularSpeedCompare () { - return Promise.resolve(); + whenSpinSpeedCompare (args) { + let currentVal = 0; + + switch (args.DIRECTION) { + case 'x': + currentVal = this._peripheral.getSpinSpeedX(); + break; + case 'y': + currentVal = this._peripheral.getSpinSpeedY(); + break; + case 'z': + currentVal = this._peripheral.getSpinSpeedZ(); + break; + default: + log.warn(`Unknown direction in whenSpinSpeedCompare: ${args.DIRECTION}`); + return false; + } + + switch (args.COMPARE) { + case ComparisonOptions.LESS_THAN: + return currentVal < Cast.toNumber(args.VALUE); + case ComparisonOptions.GREATER_THAN: + return currentVal > Cast.toNumber(args.VALUE); + default: + log.warn(`Unknown comparison operator in whenSpinSpeedCompare: ${args.COMPARE}`); + return false; + } } - whenForceCompare () { - return Promise.resolve(); + whenForceCompare (args) { + switch (args.COMPARE) { + case ComparisonOptions.LESS_THAN: + return this._peripheral.getForce() < Cast.toNumber(args.VALUE); + case ComparisonOptions.GREATER_THAN: + return this._peripheral.getForce() > Cast.toNumber(args.VALUE); + default: + log.warn(`Unknown comparison operator in whenForceCompare: ${args.COMPARE}`); + return false; + } } getAcceleration (args) { switch (args.DIRECTION) { @@ -441,16 +499,16 @@ class Scratch3GdxForBlocks { log.warn(`Unknown direction in getAcceleration: ${args.DIRECTION}`); } } - getAngularSpeed (args) { + getSpinSpeed (args) { switch (args.DIRECTION) { case 'x': - return this._peripheral.getAngularSpeedX(); + return this._peripheral.getSpinSpeedX(); case 'y': - return this._peripheral.getAngularSpeedY(); + return this._peripheral.getSpinSpeedY(); case 'z': - return this._peripheral.getAngularSpeedZ(); + return this._peripheral.getSpinSpeedZ(); default: - log.warn(`Unknown direction in getAngularSpeed: ${args.DIRECTION}`); + log.warn(`Unknown direction in getSpinSpeed: ${args.DIRECTION}`); } } getForce () { From da608f6f18aac9856cd26b59de8b965b21dab68d Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Tue, 8 Jan 2019 12:07:39 -0500 Subject: [PATCH 22/32] degrees/s instead of radians, normalize force --- src/extensions/scratch3_gdx_for/index.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index c7330c572..f0416e1af 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -25,7 +25,6 @@ const BLEUUID = { responseChar: 'b41e6675-a329-40e0-aa01-44d2f444babe' }; - /** * Manage communication with a GDX-FOR peripheral over a Scratch Link client socket. */ @@ -167,7 +166,17 @@ class GdxFor { getForce () { if (this.isConnected()) { - return this._device.getSensor(1).value; + let force = this._device.getSensor(1).value; + // Normalize the force, which can be measured between -50 and 50 N, + // to be a value between -100 and 100. + force = force * 2; + if (force > 100) { + return 100; + } + if (force < -100) { + return -100; + } + return force; } return 0; } @@ -195,21 +204,21 @@ class GdxFor { getSpinSpeedX () { if (this.isConnected()) { - return this._device.getSensor(5).value; + return this._device.getSensor(5).value * (180 / Math.PI); } return 0; } getSpinSpeedY () { if (this.isConnected()) { - return this._device.getSensor(6).value; + return this._device.getSensor(6).value * (180 / Math.PI); } return 0; } getSpinSpeedZ () { if (this.isConnected()) { - return this._device.getSensor(7).value; + return this._device.getSensor(7).value * (180 / Math.PI); } return 0; } From d3e5c7d928f7d941563a6de1cbf7b0c0e81317ca Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Wed, 9 Jan 2019 13:55:35 -0500 Subject: [PATCH 23/32] Remove directions option from hats and use magnitude --- src/extensions/scratch3_gdx_for/index.js | 68 ++++++++---------------- 1 file changed, 22 insertions(+), 46 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index f0416e1af..3f38c1561 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -4,7 +4,7 @@ const log = require('../../util/log'); const Cast = require('../../util/cast'); const formatMessage = require('format-message'); const BLE = require('../../io/ble'); -const createDevice = require('@vernier/godirect').default.createDevice; +const godirect = require('@vernier/godirect/dist/godirect.min.umd.js'); const ScratchLinkDeviceAdapter = require('./scratch-link-device-adapter'); /** @@ -141,7 +141,7 @@ class GdxFor { */ _onConnect () { const adapter = new ScratchLinkDeviceAdapter(this._scratchLinkSocket); - createDevice(adapter, {open: true, startMeasurements: false}).then(device => { + godirect.createDevice(adapter, {open: true, startMeasurements: false}).then(device => { this._device = device; this._startMeasurements(); }); @@ -314,16 +314,11 @@ class Scratch3GdxForBlocks { opcode: 'whenAccelerationCompare', text: formatMessage({ id: 'gdxfor.whenAccelerationCompare', - default: 'when acceleration [DIRECTION] [COMPARE] [VALUE]', + default: 'when acceleration [COMPARE] [VALUE]', description: 'when the meters/second^2 value measured by the acceleration sensor is compared to some value' }), blockType: BlockType.HAT, arguments: { - DIRECTION: { - type: ArgumentType.STRING, - menu: 'directionOptions', - defaultValue: 'x' - }, COMPARE: { type: ArgumentType.STRING, menu: 'compareOptions', @@ -339,16 +334,11 @@ class Scratch3GdxForBlocks { opcode: 'whenSpinSpeedCompare', text: formatMessage({ id: 'gdxfor.whenSpinSpeedCompare', - default: 'when spin speed [DIRECTION] [COMPARE] [VALUE]', + default: 'when spin speed [COMPARE] [VALUE]', description: 'when the degrees/second value measured by the gyroscope sensor is compared to some value' }), blockType: BlockType.HAT, arguments: { - DIRECTION: { - type: ArgumentType.STRING, - menu: 'directionOptions', - defaultValue: 'x' - }, COMPARE: { type: ArgumentType.STRING, menu: 'compareOptions', @@ -429,23 +419,20 @@ class Scratch3GdxForBlocks { }; } - whenAccelerationCompare (args) { - let currentVal = 0; + /** + * @return {number} - the magnitude of a three dimension vector. + */ + magnitude (x, y, z) { + return Math.sqrt(x*x + y*y + z*z); + } - switch (args.DIRECTION) { - case 'x': - currentVal = this._peripheral.getAccelerationX(); - break; - case 'y': - currentVal = this._peripheral.getAccelerationY(); - break; - case 'z': - currentVal = this._peripheral.getAccelerationZ(); - break; - default: - log.warn(`Unknown direction in whenAccelerationCompare: ${args.DIRECTION}`); - return false; - } + + whenAccelerationCompare (args) { + let currentVal = this.magnitude( + this._peripheral.getAccelerationX(), + this._peripheral.getAccelerationY(), + this._peripheral.getAccelerationZ() + ); switch (args.COMPARE) { case ComparisonOptions.LESS_THAN: @@ -458,22 +445,11 @@ class Scratch3GdxForBlocks { } } whenSpinSpeedCompare (args) { - let currentVal = 0; - - switch (args.DIRECTION) { - case 'x': - currentVal = this._peripheral.getSpinSpeedX(); - break; - case 'y': - currentVal = this._peripheral.getSpinSpeedY(); - break; - case 'z': - currentVal = this._peripheral.getSpinSpeedZ(); - break; - default: - log.warn(`Unknown direction in whenSpinSpeedCompare: ${args.DIRECTION}`); - return false; - } + let currentVal = this.magnitude( + this._peripheral.getSpinSpeedX(), + this._peripheral.getSpinSpeedY(), + this._peripheral.getSpinSpeedZ() + ); switch (args.COMPARE) { case ComparisonOptions.LESS_THAN: From abf84975bd5aaf7e662657c7f2c0b4e8953798e1 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Wed, 9 Jan 2019 17:08:01 -0500 Subject: [PATCH 24/32] Add tilt blocks --- src/extensions/scratch3_gdx_for/index.js | 140 ++++++++++++++++++++++- 1 file changed, 138 insertions(+), 2 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index 3f38c1561..9cb982b1d 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -181,6 +181,101 @@ class GdxFor { return 0; } + getTiltX () { + if (this.isConnected()) { + let x = this.getAccelerationX(); + let y = this.getAccelerationY(); + let z = this.getAccelerationZ(); + + let x_sign = 1; + let y_sign = 1; + let z_sign = 1; + + if (x < 0.0) { x *= -1.0; x_sign = -1; } + if (y < 0.0) { y *= -1.0; y_sign = -1; } + if (z < 0.0) { z *= -1.0; z_sign = -1; } + + // Compute the yz unit vector + let z2 = z * z; + let y2 = y * y; + let value = z2 + y2; + value = Math.sqrt(value); + + // For sufficiently small zy vector values we are essentially at 90 degrees. + // The following snaps to 90 and avoids divide-by-zero errors. + // The snap factor was derived through observation -- just enough to + // still allow single degree steps up to 90 (..., 87, 88, 89, 90). + if (value < 0.35) + { + value = 90; + } + else + { + // Compute the x-axis angle + value = x / value; + value = Math.atan(value); + value *= 57.2957795; // convert from rad to deg + } + // Manage the sign of the result + let yz_sign = y_sign; + if (z > y) yz_sign = z_sign; + if (yz_sign == -1) value = 180.0 - value; + value *= x_sign; + // Round the result to the nearest degree + value += 0.5; + return value; + } + return 0; + } + + getTiltY () { + if (this.isConnected()) { + let x = this.getAccelerationX(); + let y = this.getAccelerationY(); + let z = this.getAccelerationZ(); + + let x_sign = 1; + let y_sign = 1; + let z_sign = 1; + + if (x < 0.0) { x *= -1.0; x_sign = -1; } + if (y < 0.0) { y *= -1.0; y_sign = -1; } + if (z < 0.0) { z *= -1.0; z_sign = -1; } + + // Compute the yz unit vector + let z2 = z * z; + let x2 = x * x; + let value = z2 + x2; + value = Math.sqrt(value); + + // For sufficiently small zy vector values we are essentially at 90 degrees. + // The following snaps to 90 and avoids divide-by-zero errors. + // The snap factor was derived through observation -- just enough to + // still allow single degree steps up to 90 (..., 87, 88, 89, 90). + if (value < 0.35) + { + value = 90; + } + else + { + // Compute the x-axis angle + value = y / value; + value = Math.atan(value); + value *= 57.2957795; // convert from rad to deg + } + // Manage the sign of the result + let xz_sign = x_sign; + if (z > x) xz_sign = z_sign; + if (xz_sign == -1) value = 180.0 - value; + value *= y_sign; + // Round the result to the nearest degree + value += 0.5; + return value; + } + return 0; + } + + getAccelerationX () { if (this.isConnected()) { return this._device.getSensor(2).value; @@ -234,7 +329,6 @@ const ComparisonOptions = { GREATER_THAN: 'greater_than' }; - /** * Scratch 3.0 blocks to interact with a GDX-FOR peripheral. */ @@ -271,6 +365,19 @@ class Scratch3GdxForBlocks { ]; } + get TILT_MENU () { + return [ + { + text: 'x', + value: 'x' + }, + { + text: 'y', + value: 'y' + } + ]; + } + get COMPARE_MENU () { return [ { @@ -402,6 +509,22 @@ class Scratch3GdxForBlocks { } } }, + { + opcode: 'getTilt', + text: formatMessage({ + id: 'gdxfor.getTilt', + default: 'tilt [TILT]', + description: 'gets tilt' + }), + blockType: BlockType.REPORTER, + arguments: { + TILT: { + type: ArgumentType.STRING, + menu: 'tiltOptions', + defaultValue: 'x' + } + } + }, { opcode: 'getForce', text: formatMessage({ @@ -414,7 +537,8 @@ class Scratch3GdxForBlocks { ], menus: { directionOptions: this.DIRECTIONS_MENU, - compareOptions: this.COMPARE_MENU + compareOptions: this.COMPARE_MENU, + tiltOptions: this.TILT_MENU } }; } @@ -496,6 +620,18 @@ class Scratch3GdxForBlocks { log.warn(`Unknown direction in getSpinSpeed: ${args.DIRECTION}`); } } + getTilt (args) { + console.log(args); + + switch (args.TILT) { + case 'x': + return this._peripheral.getTiltX(); + case 'y': + return this._peripheral.getTiltY(); + default: + log.warn(`Unknown direction in getTilt: ${args.TILT}`); + } + } getForce () { return this._peripheral.getForce(); } From 338b30a17bb7befbf7fb4392d45555c256dcf0c1 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Wed, 9 Jan 2019 17:09:08 -0500 Subject: [PATCH 25/32] Increase speed of sample --- src/extensions/scratch3_gdx_for/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index 9cb982b1d..4a34b9d66 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -160,7 +160,7 @@ class GdxFor { } }); }); - this._device.start(); // Can set period here if needed. + this._device.start(5); // Can set period here if needed. } From c86b579b66317cbba686b2f181c8dcf955fed9ae Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Wed, 9 Jan 2019 17:10:59 -0500 Subject: [PATCH 26/32] @vernier/godirect 1.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5861f4a60..9dbfcc8e2 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "version": "json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\"" }, "dependencies": { - "@vernier/godirect": "^1.2.0", + "@vernier/godirect": "1.3.0", "arraybuffer-loader": "^1.0.6", "atob": "2.1.2", "btoa": "1.2.1", From 645246490e0e6360c3c6d0b261fa8e35f27b08c3 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Wed, 9 Jan 2019 17:31:57 -0500 Subject: [PATCH 27/32] Update package-lock.json --- package-lock.json | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index a282db4ea..e752fbaa2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1089,9 +1089,9 @@ } }, "@vernier/godirect": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vernier/godirect/-/godirect-1.2.0.tgz", - "integrity": "sha512-VkkTap4MMFHAqHERotlU9EQ6AZYGuFqD5kR3t834xybPH+xbX3iNaKOVwsyG7eLapycNSTDYqJHwh9LqSN7T2A==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@vernier/godirect/-/godirect-1.3.0.tgz", + "integrity": "sha512-vDdl1yCiKwPm/L/ca87cjSSDoFviWPx7IvT3SQxMqplYsACjCWrcW4yIECBfKuK9ok9cTFrXCSsmnpmDDApI8A==" }, "@webassemblyjs/ast": { "version": "1.5.13", @@ -12117,9 +12117,9 @@ } }, "scratch-audio": { - "version": "0.1.0-prerelease.20181023202904", - "resolved": "https://registry.npmjs.org/scratch-audio/-/scratch-audio-0.1.0-prerelease.20181023202904.tgz", - "integrity": "sha512-0cf+snpT04RFWFgMsMzbztzNVyh2PkUaT8mjlwNNoIRy5p7yDN3EMC2zGbR71nZMus1tO2EDxqrpan2ix4IWDw==", + "version": "0.1.0-prerelease.20190108181031", + "resolved": "https://registry.npmjs.org/scratch-audio/-/scratch-audio-0.1.0-prerelease.20190108181031.tgz", + "integrity": "sha512-Ygu+pN2u9det8HTIo+2wj8ibqe0QjAA624N9GxC62nrdGH39NxDRJyiwheeuZH/oEjM9RTsCSSOH+C9fXA9ekA==", "dev": true, "requires": { "audio-context": "1.0.1", @@ -12173,9 +12173,9 @@ } }, "scratch-render": { - "version": "0.1.0-prerelease.20190107163047", - "resolved": "https://registry.npmjs.org/scratch-render/-/scratch-render-0.1.0-prerelease.20190107163047.tgz", - "integrity": "sha512-pvyiU4FiUVEuxPc484A1UE3Dry06SIvy3OUqDs2rYu1NMw5+iwIkQLsHcpb7WLjmIFf41mh3h8GHKHHoZAOM4Q==", + "version": "0.1.0-prerelease.20190109203013", + "resolved": "https://registry.npmjs.org/scratch-render/-/scratch-render-0.1.0-prerelease.20190109203013.tgz", + "integrity": "sha512-yrkBuF1zLHrXEHQmbQhpATDxot/wqoN/oDW2aIjzV9ylxCy+zNdGI2XJ9tRy10bCcM5bdC879ROX9fCr+n6FwQ==", "dev": true, "requires": { "grapheme-breaker": "0.3.2", @@ -12185,8 +12185,29 @@ "minilog": "3.1.0", "raw-loader": "^0.5.1", "scratch-storage": "^1.0.0", - "scratch-svg-renderer": "0.2.0-prerelease.20181220183040", + "scratch-svg-renderer": "0.2.0-prerelease.20190109201344", "twgl.js": "4.4.0" + }, + "dependencies": { + "base64-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", + "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==", + "dev": true + }, + "scratch-svg-renderer": { + "version": "0.2.0-prerelease.20190109201344", + "resolved": "https://registry.npmjs.org/scratch-svg-renderer/-/scratch-svg-renderer-0.2.0-prerelease.20190109201344.tgz", + "integrity": "sha512-pRMvQrM5UA2wcqleaXVpFx0Pi6Q3GsRA5elJ0tJksdr6k8HYm5D6sW62VtEtMHjnkQDa+EFyqfHq9IEPnzFjeQ==", + "dev": true, + "requires": { + "base64-js": "1.2.1", + "base64-loader": "1.0.0", + "minilog": "3.1.0", + "scratch-render-fonts": "1.0.0-prerelease.20180906193204", + "transformation-matrix": "1.14.1" + } + } } }, "scratch-render-fonts": { From d2fec35fd875944329ac8cdea0df6f3be4bef77b Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Wed, 9 Jan 2019 17:50:25 -0500 Subject: [PATCH 28/32] Set the period to 10 milliseconds --- src/extensions/scratch3_gdx_for/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index 4a34b9d66..a41d861e5 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -160,7 +160,7 @@ class GdxFor { } }); }); - this._device.start(5); // Can set period here if needed. + this._device.start(10); // Set the period to 10 milliseconds } From ae889304c5afb04e7aac8ae8c6b408e0bcb7bd28 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Wed, 9 Jan 2019 17:51:56 -0500 Subject: [PATCH 29/32] satisfy linter --- src/extensions/scratch3_gdx_for/index.js | 52 +++++++++++++----------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index a41d861e5..5b287a6c8 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -191,13 +191,19 @@ class GdxFor { let y_sign = 1; let z_sign = 1; - if (x < 0.0) { x *= -1.0; x_sign = -1; } - if (y < 0.0) { y *= -1.0; y_sign = -1; } - if (z < 0.0) { z *= -1.0; z_sign = -1; } + if (x < 0.0) { + x *= -1.0; x_sign = -1; + } + if (y < 0.0) { + y *= -1.0; y_sign = -1; + } + if (z < 0.0) { + z *= -1.0; z_sign = -1; + } // Compute the yz unit vector - let z2 = z * z; - let y2 = y * y; + const z2 = z * z; + const y2 = y * y; let value = z2 + y2; value = Math.sqrt(value); @@ -205,12 +211,9 @@ class GdxFor { // The following snaps to 90 and avoids divide-by-zero errors. // The snap factor was derived through observation -- just enough to // still allow single degree steps up to 90 (..., 87, 88, 89, 90). - if (value < 0.35) - { + if (value < 0.35) { value = 90; - } - else - { + } else { // Compute the x-axis angle value = x / value; value = Math.atan(value); @@ -238,13 +241,19 @@ class GdxFor { let y_sign = 1; let z_sign = 1; - if (x < 0.0) { x *= -1.0; x_sign = -1; } - if (y < 0.0) { y *= -1.0; y_sign = -1; } - if (z < 0.0) { z *= -1.0; z_sign = -1; } + if (x < 0.0) { + x *= -1.0; x_sign = -1; + } + if (y < 0.0) { + y *= -1.0; y_sign = -1; + } + if (z < 0.0) { + z *= -1.0; z_sign = -1; + } // Compute the yz unit vector - let z2 = z * z; - let x2 = x * x; + const z2 = z * z; + const x2 = x * x; let value = z2 + x2; value = Math.sqrt(value); @@ -252,12 +261,9 @@ class GdxFor { // The following snaps to 90 and avoids divide-by-zero errors. // The snap factor was derived through observation -- just enough to // still allow single degree steps up to 90 (..., 87, 88, 89, 90). - if (value < 0.35) - { + if (value < 0.35) { value = 90; - } - else - { + } else { // Compute the x-axis angle value = y / value; value = Math.atan(value); @@ -547,12 +553,12 @@ class Scratch3GdxForBlocks { * @return {number} - the magnitude of a three dimension vector. */ magnitude (x, y, z) { - return Math.sqrt(x*x + y*y + z*z); + return Math.sqrt(x * x + y * y + z * z); } whenAccelerationCompare (args) { - let currentVal = this.magnitude( + const currentVal = this.magnitude( this._peripheral.getAccelerationX(), this._peripheral.getAccelerationY(), this._peripheral.getAccelerationZ() @@ -569,7 +575,7 @@ class Scratch3GdxForBlocks { } } whenSpinSpeedCompare (args) { - let currentVal = this.magnitude( + const currentVal = this.magnitude( this._peripheral.getSpinSpeedX(), this._peripheral.getSpinSpeedY(), this._peripheral.getSpinSpeedZ() From 5d4aebf30167c741fae1815913568ffcd7b61e41 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Wed, 9 Jan 2019 18:02:36 -0500 Subject: [PATCH 30/32] Satisfy linter --- src/extensions/scratch3_gdx_for/index.js | 145 ++++++++++++----------- 1 file changed, 74 insertions(+), 71 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index 5b287a6c8..e0cc5b76e 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -187,45 +187,45 @@ class GdxFor { let y = this.getAccelerationY(); let z = this.getAccelerationZ(); - let x_sign = 1; - let y_sign = 1; - let z_sign = 1; + let xSign = 1; + let ySign = 1; + let zSign = 1; - if (x < 0.0) { - x *= -1.0; x_sign = -1; + if (x < 0.0) { + x *= -1.0; xSign = -1; } - if (y < 0.0) { - y *= -1.0; y_sign = -1; + if (y < 0.0) { + y *= -1.0; ySign = -1; } - if (z < 0.0) { - z *= -1.0; z_sign = -1; + if (z < 0.0) { + z *= -1.0; zSign = -1; } - // Compute the yz unit vector - const z2 = z * z; - const y2 = y * y; - let value = z2 + y2; - value = Math.sqrt(value); + // Compute the yz unit vector + const z2 = z * z; + const y2 = y * y; + let value = z2 + y2; + value = Math.sqrt(value); - // For sufficiently small zy vector values we are essentially at 90 degrees. - // The following snaps to 90 and avoids divide-by-zero errors. - // The snap factor was derived through observation -- just enough to - // still allow single degree steps up to 90 (..., 87, 88, 89, 90). - if (value < 0.35) { - value = 90; - } else { - // Compute the x-axis angle - value = x / value; - value = Math.atan(value); - value *= 57.2957795; // convert from rad to deg - } - // Manage the sign of the result - let yz_sign = y_sign; - if (z > y) yz_sign = z_sign; - if (yz_sign == -1) value = 180.0 - value; - value *= x_sign; - // Round the result to the nearest degree - value += 0.5; + // For sufficiently small zy vector values we are essentially at 90 degrees. + // The following snaps to 90 and avoids divide-by-zero errors. + // The snap factor was derived through observation -- just enough to + // still allow single degree steps up to 90 (..., 87, 88, 89, 90). + if (value < 0.35) { + value = 90; + } else { + // Compute the x-axis angle + value = x / value; + value = Math.atan(value); + value *= 57.2957795; // convert from rad to deg + } + // Manage the sign of the result + let yzSign = ySign; + if (z > y) yzSign = zSign; + if (yzSign === -1) value = 180.0 - value; + value *= xSign; + // Round the result to the nearest degree + value += 0.5; return value; } return 0; @@ -237,45 +237,45 @@ class GdxFor { let y = this.getAccelerationY(); let z = this.getAccelerationZ(); - let x_sign = 1; - let y_sign = 1; - let z_sign = 1; + let xSign = 1; + let ySign = 1; + let zSign = 1; - if (x < 0.0) { - x *= -1.0; x_sign = -1; + if (x < 0.0) { + x *= -1.0; xSign = -1; } - if (y < 0.0) { - y *= -1.0; y_sign = -1; + if (y < 0.0) { + y *= -1.0; ySign = -1; } - if (z < 0.0) { - z *= -1.0; z_sign = -1; + if (z < 0.0) { + z *= -1.0; zSign = -1; } - // Compute the yz unit vector - const z2 = z * z; - const x2 = x * x; - let value = z2 + x2; - value = Math.sqrt(value); + // Compute the yz unit vector + const z2 = z * z; + const x2 = x * x; + let value = z2 + x2; + value = Math.sqrt(value); - // For sufficiently small zy vector values we are essentially at 90 degrees. - // The following snaps to 90 and avoids divide-by-zero errors. - // The snap factor was derived through observation -- just enough to - // still allow single degree steps up to 90 (..., 87, 88, 89, 90). - if (value < 0.35) { - value = 90; - } else { - // Compute the x-axis angle - value = y / value; - value = Math.atan(value); - value *= 57.2957795; // convert from rad to deg - } - // Manage the sign of the result - let xz_sign = x_sign; - if (z > x) xz_sign = z_sign; - if (xz_sign == -1) value = 180.0 - value; - value *= y_sign; - // Round the result to the nearest degree - value += 0.5; + // For sufficiently small zy vector values we are essentially at 90 degrees. + // The following snaps to 90 and avoids divide-by-zero errors. + // The snap factor was derived through observation -- just enough to + // still allow single degree steps up to 90 (..., 87, 88, 89, 90). + if (value < 0.35) { + value = 90; + } else { + // Compute the x-axis angle + value = y / value; + value = Math.atan(value); + value *= 57.2957795; // convert from rad to deg + } + // Manage the sign of the result + let xzSign = xSign; + if (z > x) xzSign = zSign; + if (xzSign === -1) value = 180.0 - value; + value *= ySign; + // Round the result to the nearest degree + value += 0.5; return value; } return 0; @@ -428,7 +428,8 @@ class Scratch3GdxForBlocks { text: formatMessage({ id: 'gdxfor.whenAccelerationCompare', default: 'when acceleration [COMPARE] [VALUE]', - description: 'when the meters/second^2 value measured by the acceleration sensor is compared to some value' + description: 'when the meters/second^2 value measured by the ' + + 'acceleration sensor is compared to some value' }), blockType: BlockType.HAT, arguments: { @@ -448,7 +449,8 @@ class Scratch3GdxForBlocks { text: formatMessage({ id: 'gdxfor.whenSpinSpeedCompare', default: 'when spin speed [COMPARE] [VALUE]', - description: 'when the degrees/second value measured by the gyroscope sensor is compared to some value' + description: 'when the degrees/second value measured by the ' + + 'gyroscope sensor is compared to some value' }), blockType: BlockType.HAT, arguments: { @@ -550,10 +552,13 @@ class Scratch3GdxForBlocks { } /** + * @param {number} x - x axis vector + * @param {number} y - y axis vector + * @param {number} z - z axis vector * @return {number} - the magnitude of a three dimension vector. */ magnitude (x, y, z) { - return Math.sqrt(x * x + y * y + z * z); + return Math.sqrt((x * x) + (y * y) + (z * z)); } @@ -627,8 +632,6 @@ class Scratch3GdxForBlocks { } } getTilt (args) { - console.log(args); - switch (args.TILT) { case 'x': return this._peripheral.getTiltX(); From 477c307304e0e6438d4e5624179740a9d0bfec1d Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Thu, 10 Jan 2019 10:11:46 -0500 Subject: [PATCH 31/32] Remove one copy of constants --- src/extensions/scratch3_gdx_for/index.js | 2 +- .../scratch-link-device-adapter.js | 20 ++++++------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index e0cc5b76e..be6b2812c 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -140,7 +140,7 @@ class GdxFor { * @private */ _onConnect () { - const adapter = new ScratchLinkDeviceAdapter(this._scratchLinkSocket); + const adapter = new ScratchLinkDeviceAdapter(this._scratchLinkSocket, BLEUUID); godirect.createDevice(adapter, {open: true, startMeasurements: false}).then(device => { this._device = device; this._startMeasurements(); diff --git a/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js b/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js index f9cb69495..33b5f2a02 100644 --- a/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js +++ b/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js @@ -1,23 +1,15 @@ const Base64Util = require('../../util/base64-util'); -/** - * Enum for Vernier godirect protocol. - * @readonly - * @enum {string} - */ -const BLEUUID = { - service: 'd91714ef-28b9-4f91-ba16-f0d9a604f112', - commandChar: 'f4bf14a6-c7d5-4b6d-8aa8-df1a7c83adcb', - responseChar: 'b41e6675-a329-40e0-aa01-44d2f444babe' -}; - /** * Adapter class */ class ScratchLinkDeviceAdapter { - constructor (scratchLinkSocket) { + constructor (scratchLinkSocket, { service, commandChar, responseChar }) { this.scratchLinkSocket = scratchLinkSocket; + this._service = service; + this._commandChar = commandChar; + this._responseChar = responseChar; this._onResponse = this._onResponse.bind(this); this._deviceOnResponse = null; } @@ -30,13 +22,13 @@ class ScratchLinkDeviceAdapter { const data = Base64Util.uint8ArrayToBase64(commandBuffer); return this.scratchLinkSocket - .write(BLEUUID.service, BLEUUID.commandChar, data, 'base64', true); + .write(this._service, this._commandChar, data, 'base64', true); } setup ({onResponse}) { this._deviceOnResponse = onResponse; return this.scratchLinkSocket - .startNotifications(BLEUUID.service, BLEUUID.responseChar, this._onResponse); + .startNotifications(this._service, this._responseChar, this._onResponse); // TODO: // How do we find out from scratch link if communication closes? From ac29927c2277c435e35408ce30f8ba26c75dc772 Mon Sep 17 00:00:00 2001 From: Valerie Young Date: Thu, 10 Jan 2019 10:21:32 -0500 Subject: [PATCH 32/32] other minor feedback --- src/extensions/scratch3_gdx_for/index.js | 31 +++++-------------- .../scratch-link-device-adapter.js | 2 +- 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/src/extensions/scratch3_gdx_for/index.js b/src/extensions/scratch3_gdx_for/index.js index be6b2812c..254a4ccc1 100644 --- a/src/extensions/scratch3_gdx_for/index.js +++ b/src/extensions/scratch3_gdx_for/index.js @@ -3,6 +3,7 @@ const BlockType = require('../../extension-support/block-type'); const log = require('../../util/log'); const Cast = require('../../util/cast'); const formatMessage = require('format-message'); +const MathUtil = require('../../util/math-util'); const BLE = require('../../io/ble'); const godirect = require('@vernier/godirect/dist/godirect.min.umd.js'); const ScratchLinkDeviceAdapter = require('./scratch-link-device-adapter'); @@ -52,8 +53,8 @@ class GdxFor { this._scratchLinkSocket = null; /** - * A godirect device - * @type {@vernier/goDirect device} + * An @vernier/godirect Device + * @type {Device} * @private */ this._device = null; @@ -65,21 +66,6 @@ class GdxFor { */ this._extensionId = extensionId; - /** - * The most recently received value for each sensor. - * @type {Object.} - * @private - */ - this._sensors = { - force: 0, - accelerationX: 0, - accelerationY: 0, - accelerationZ: 0, - angularVelocityX: 0, - angularVelocityY: 0, - angularVelocityZ: 0 - }; - this.disconnect = this.disconnect.bind(this); this._onConnect = this._onConnect.bind(this); } @@ -154,6 +140,9 @@ class GdxFor { _startMeasurements () { this._device.sensors.forEach(sensor => { sensor.setEnabled(true); + + // For now, clear the save sensor values. The unlimited saving + // will be fixed in a future @vernier/godirect release. sensor.on('value-changed', changedSensor => { if (changedSensor.values.length > 1000) { changedSensor.clear(); @@ -169,13 +158,7 @@ class GdxFor { let force = this._device.getSensor(1).value; // Normalize the force, which can be measured between -50 and 50 N, // to be a value between -100 and 100. - force = force * 2; - if (force > 100) { - return 100; - } - if (force < -100) { - return -100; - } + force = MathUtil.clamp(force * 2, -100, 100); return force; } return 0; diff --git a/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js b/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js index 33b5f2a02..a9a61d4ae 100644 --- a/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js +++ b/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js @@ -4,7 +4,7 @@ const Base64Util = require('../../util/base64-util'); * Adapter class */ class ScratchLinkDeviceAdapter { - constructor (scratchLinkSocket, { service, commandChar, responseChar }) { + constructor (scratchLinkSocket, {service, commandChar, responseChar}) { this.scratchLinkSocket = scratchLinkSocket; this._service = service;