From 67b5afd73a27e3a8605e65f708a68da014aa8e79 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Tue, 21 Jun 2016 11:17:34 -0700 Subject: [PATCH 01/42] integrating docs about "devices" namespace --- docs/reference.md | 6 +++--- docs/reference/devices.md | 19 +++++++++++++++++++ libs/microbit-bluetooth/bluetooth.cpp | 4 ++++ libs/microbit-devices/devices.cpp | 4 +++- libs/microbit-devices/shims.d.ts | 4 +++- 5 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 docs/reference/devices.md diff --git a/docs/reference.md b/docs/reference.md index c64b5d6a..823d3be7 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -26,11 +26,11 @@ control.inBackground(() => { ## Advanced ```namespaces -bluetooth.onBluetoothConnected(() => { - -}); +devices.tellCameraTo(MesCameraEvent.TakePhoto); +bluetooth.onBluetoothConnected(() => {}); ``` ```package +microbit-devices microbit-bluetooth ``` \ No newline at end of file diff --git a/docs/reference/devices.md b/docs/reference/devices.md new file mode 100644 index 00000000..c8b88d88 --- /dev/null +++ b/docs/reference/devices.md @@ -0,0 +1,19 @@ +# Devices + +Control a phone with the BBC micro:bit via Bluetooth. + +```cards +devices.tellCameraTo(MesCameraEvent.TakePhoto); +devices.tellRemoteControlTo(MesRemoteControlEvent.play); +devices.raiseAlertTo(MesAlertEvent.DisplayToast); +devices.onNotified(MesDeviceInfo.IncomingCall, () => { + +}); +devices.onGamepadButton(MesDpadButtonInfo.ADown, () => { + +}); +devices.signalStrength(); +devices.onSignalStrengthChanged(() => { + +}); +``` diff --git a/libs/microbit-bluetooth/bluetooth.cpp b/libs/microbit-bluetooth/bluetooth.cpp index ab995204..1ba1beed 100644 --- a/libs/microbit-bluetooth/bluetooth.cpp +++ b/libs/microbit-bluetooth/bluetooth.cpp @@ -2,6 +2,10 @@ #include "MESEvents.h" using namespace pxt; + +/** + * Support for additional Bluetooth services. + */ //% color=#0082FB weight=20 namespace bluetooth { /** diff --git a/libs/microbit-devices/devices.cpp b/libs/microbit-devices/devices.cpp index 3c1b51cf..9e672020 100644 --- a/libs/microbit-devices/devices.cpp +++ b/libs/microbit-devices/devices.cpp @@ -120,7 +120,9 @@ enum class MesDpadButtonInfo { _4Up = MES_DPAD_BUTTON_4_UP, }; - +/** + * Control a phone with the BBC micro:bit via Bluetooth. + */ //% color=156 weight=80 namespace devices { static void genEvent(int id, int event) { diff --git a/libs/microbit-devices/shims.d.ts b/libs/microbit-devices/shims.d.ts index 64fdb60c..9b152593 100644 --- a/libs/microbit-devices/shims.d.ts +++ b/libs/microbit-devices/shims.d.ts @@ -1,7 +1,9 @@ // Auto-generated. Do not edit. - + /** + * Control a phone with the BBC micro:bit via Bluetooth. + */ //% color=156 weight=80 declare namespace devices { From 34effcefc69f714c348a48b26b48a337bd2582a5 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Tue, 21 Jun 2016 14:30:05 -0700 Subject: [PATCH 02/42] jsdoc on bluetooth --- libs/microbit-bluetooth/shims.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/microbit-bluetooth/shims.d.ts b/libs/microbit-bluetooth/shims.d.ts index 9d7d49b5..05442eff 100644 --- a/libs/microbit-bluetooth/shims.d.ts +++ b/libs/microbit-bluetooth/shims.d.ts @@ -1,7 +1,9 @@ // Auto-generated. Do not edit. - + /** + * Support for additional Bluetooth services. + */ //% color=#0082FB weight=20 declare namespace bluetooth { From b150ee873fd06f0af12e17ef8745ecdb1b63c85e Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Wed, 22 Jun 2016 09:25:01 -0700 Subject: [PATCH 03/42] updated bluetooth docs --- .../bluetooth/on-bluetooth-disconnected.md | 26 +++++++++++-------- .../bluetooth/start-accelerometer-service.md | 24 ++++++++++------- .../bluetooth/start-button-service.md | 24 ++++++++++------- .../bluetooth/start-io-pin-service.md | 24 ++++++++++------- docs/reference/bluetooth/start-led-service.md | 24 ++++++++++------- .../bluetooth/start-magnetometer-service.md | 23 +++++++++------- .../bluetooth/start-temperature-service.md | 24 ++++++++++------- 7 files changed, 100 insertions(+), 69 deletions(-) diff --git a/docs/reference/bluetooth/on-bluetooth-disconnected.md b/docs/reference/bluetooth/on-bluetooth-disconnected.md index 34674e83..3bfd3859 100755 --- a/docs/reference/bluetooth/on-bluetooth-disconnected.md +++ b/docs/reference/bluetooth/on-bluetooth-disconnected.md @@ -1,33 +1,37 @@ # On Bluetooth Disconnected +### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. This block starts an [event handler](/reference/event-handler) which in this case will run when a device which is connected to your micro:bit over Bluetooth disconnects. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. + +### ~ + +This block starts an [event handler](/reference/event-handler) which in this case will run when a device which is connected to your micro:bit over Bluetooth disconnects. You could use this event handler to display a letter "D" on the micro:bit LED grid so you know that the Bluetooth connection has been closed. -~~~~sig +```sig bluetooth.onBluetoothDisconnected(() => { }); -~~~~ +``` ### Example: Displaying "D" when a Bluetooth connection to the micro:bit is closed -~~~~blocks +```blocks bluetooth.onBluetoothDisconnected(() => { basic.showString("D"); }); -~~~~ +``` ### Video - on Bluetooth disconnected -[![micro:bit Bluetooth demo video](/static/bluetooth/microbit_on_disconnected.png)]( - http://www.youtube.com/watch?v=HyBcsD9Eh6I "Click to launch YouTube video" - ) +http://www.youtube.com/watch?v=HyBcsD9Eh6I ### See also -[Bluetooth SIG](https://www.bluetooth.com) - -[Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) +[Bluetooth SIG](https://www.bluetooth.com), [Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) +```package +microbit-bluetooth +``` diff --git a/docs/reference/bluetooth/start-accelerometer-service.md b/docs/reference/bluetooth/start-accelerometer-service.md index 2c8ddec6..140c3f77 100755 --- a/docs/reference/bluetooth/start-accelerometer-service.md +++ b/docs/reference/bluetooth/start-accelerometer-service.md @@ -1,30 +1,33 @@ # Bluetooth Accelerometer Service +### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. + +### ~ + The Bluetooth accelerometer service allows another device such as a smartphone to wirelessly receive data from the micro:bit's accelerometer. An accelerometer detects motion. More precisely, it measures acceleration in one or more of three directions which we call X, Y and Z. Using the Bluetooth accelerometer service you could, for example, create a smartphone application which makes a loud noise whenever your micro:bit (or the important thing you've attached it to) is moved. Or you could use your micro:bit to control the movement of a cartoon character in a game on your smartphone just by tilting the micro:bit in the direction you want the character to move in. No additional code is needed on the micro:bit to use the Bluetooth accelerometer service from another device. -~~~~sig +```sig bluetooth.startAccelerometerService(); -~~~~ +``` ### Example: Starting the Bluetooth accelerometer service The following code shows the Bluetooth accelerometer service being started: -~~~~blocks +```blocks bluetooth.startAccelerometerService(); -~~~~ +``` ### Video - Accelerometer service demo - Starts at 0:18 -[![micro:bit Bluetooth demo video](/static/bluetooth/microbit_accelerometer.png)]( - http://www.youtube.com/watch?v=aep_GVowKfs "Click to launch YouTube video" - ) +http://www.youtube.com/watch?v=aep_GVowKfs ### Advanced @@ -32,7 +35,8 @@ For more advanced information on the micro:bit Bluetooth accelerometer service i ### See also -[Bluetooth SIG](https://www.bluetooth.com) - -[Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) +[Bluetooth SIG](https://www.bluetooth.com), [Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) +```package +microbit-bluetooth +``` diff --git a/docs/reference/bluetooth/start-button-service.md b/docs/reference/bluetooth/start-button-service.md index 05e96c21..64c9b625 100755 --- a/docs/reference/bluetooth/start-button-service.md +++ b/docs/reference/bluetooth/start-button-service.md @@ -1,7 +1,12 @@ # Bluetooth Button Service +### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. + +### ~ + The Bluetooth button service makes it possible for another device such as a smartphone to be notified wirelessly whenever a button on the front of a micro:bit is pressed. Each of the two micro:bit buttons can be in one of three possible states: * Not pressed @@ -12,23 +17,21 @@ The button service allows you to make other things which are connected to your m No additional code is needed on the micro:bit to use the Bluetooth button service from another device. -~~~~sig +```sig bluetooth.startButtonService(); -~~~~ +``` ### Example: Starting the Bluetooth button service The following code shows the Bluetooth button service being started: -~~~~blocks +```blocks bluetooth.startButtonService(); -~~~~ +``` ### Video - Button service demo - Starts at 0:59 -[![micro:bit Bluetooth demo video](/static/bluetooth/microbit_button.png)]( - http://www.youtube.com/watch?v=aep_GVowKfs "Click to launch YouTube video" - ) +http://www.youtube.com/watch?v=aep_GVowKfs ### Advanced @@ -36,7 +39,8 @@ For more advanced information on the micro:bit Bluetooth button service includin ### See also -[Bluetooth SIG](https://www.bluetooth.com) - -[Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) +[Bluetooth SIG](https://www.bluetooth.com),[Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) +```package +microbit-bluetooth +``` diff --git a/docs/reference/bluetooth/start-io-pin-service.md b/docs/reference/bluetooth/start-io-pin-service.md index 5d947a91..77d349e1 100755 --- a/docs/reference/bluetooth/start-io-pin-service.md +++ b/docs/reference/bluetooth/start-io-pin-service.md @@ -1,28 +1,31 @@ # Bluetooth IO Pin Service +### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. + +### ~ + The Bluetooth IO pin service makes it possible for another device such as a smartphone to communicate with other electronic 'things' connected to a micro:bit's edge connector. You could for example, use your smartphone to switch on or off a light which is connected to the micro:bit or your smartphone could receive data collected from a sensor connected to the micro:bit. In fact you could do both of these things at the same time since the Bluetooth IO pin service lets you interact with multiple 'pins' on the edge conector in different ways all at the same time. No additional code is needed on the micro:bit to use the Bluetooth IO pin service from another device. -~~~~sig +```sig bluetooth.startIOPinService(); -~~~~ +``` ### Example: Starting the Bluetooth IO pin service The following code shows the Bluetooth IO pin service being started: -~~~~blocks +```blocks bluetooth.startIOPinService(); -~~~~ +``` ### Video - IO pin service demo starts at 3:49 -[![micro:bit Bluetooth demo video](/static/bluetooth/microbit_pin_io.png)]( - http://www.youtube.com/watch?v=aep_GVowKfs "Click to launch YouTube video" - ) +http://www.youtube.com/watch?v=aep_GVowKfs ### Advanced @@ -30,7 +33,8 @@ For more advanced information on the micro:bit Bluetooth IO pin service includin ### See also -[Bluetooth SIG](https://www.bluetooth.com) - -[Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) +[Bluetooth SIG](https://www.bluetooth.com), [Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) +```package +microbit-bluetooth +``` diff --git a/docs/reference/bluetooth/start-led-service.md b/docs/reference/bluetooth/start-led-service.md index 3f0a7c19..b05098fd 100755 --- a/docs/reference/bluetooth/start-led-service.md +++ b/docs/reference/bluetooth/start-led-service.md @@ -1,30 +1,33 @@ # Bluetooth LED Service +### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. + +### ~ + The Bluetooth LED service allows another device such as a smartphone to send short text strings or patterns over a Bluetooth connection to a micro:bit for display on its LED matrix. Text will scroll across the micro:bit and the speed at which it scrolls can also be controlled using the Bluetooth LED service. Devices using the LED service may also read the current state of the micro:bit's LED matrix. So you could, for example, draw a smiley face in a smartphone app and at the press of a button, have it magically appear on your micro:bit on the other side of the room. Or you could program your smartphone to send a message to your micro:bit whenever your phone receives an email, SMS or social media message so you could wear your micro:bit like a smart watch and leave your phone in your bag. No additional code is needed on the micro:bit to use the Bluetooth LED service from another device. -~~~~sig +```sig bluetooth.startLEDService(); -~~~~ +``` ### Example: Starting the Bluetooth LED service The following code shows the Bluetooth LED service being started: -~~~~blocks +```blocks bluetooth.startLEDService(); -~~~~ +``` ### Video - LED service demo starts at 2:00 -[![micro:bit Bluetooth demo video](/static/bluetooth/microbit_led.png)]( - http://www.youtube.com/watch?v=aep_GVowKfs "Click to launch YouTube video" - ) +http://www.youtube.com/watch?v=aep_GVowKfs ### Advanced @@ -32,7 +35,8 @@ For more advanced information on the micro:bit Bluetooth LED service including i ### See also -[Bluetooth SIG](https://www.bluetooth.com) - -[Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) +[Bluetooth SIG](https://www.bluetooth.com), [Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) +```package +microbit-bluetooth +``` diff --git a/docs/reference/bluetooth/start-magnetometer-service.md b/docs/reference/bluetooth/start-magnetometer-service.md index 3208135f..8869a713 100755 --- a/docs/reference/bluetooth/start-magnetometer-service.md +++ b/docs/reference/bluetooth/start-magnetometer-service.md @@ -1,30 +1,33 @@ # Bluetooth Magnetometer Service +### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. + +### ~ + The Bluetooth magnetometer service allows another device such as a smartphone to wirelessly receive data from the micro:bit's magnetometer. The magnetometer measures the strength and direction of magnetic fields including the earth's and so it can be used as a digital compass and indicate the way the micro:bit is pointing relative to magnetic north. Using the Bluetooth magnetometer service you could, for example, create a smartphone application which displays your direction of travel, updating it in real time. No additional code is needed on the micro:bit to use the Bluetooth magnetometer service from another device. -~~~~sig +```sig bluetooth.startMagnetometerService(); -~~~~ +``` ### Example: Starting the Bluetooth magnetometer service The following code shows the Bluetooth magnetometer service being started: -~~~~blocks +```blocks bluetooth.startMagnetometerService(); -~~~~ +``` ### Video - Magnetometer service demo -[![micro:bit Bluetooth demo video](/static/bluetooth/microbit_magnetometer.png)]( - http://www.youtube.com/watch?v=C_0VL4Gp4_U "Click to launch YouTube video" - ) +http://www.youtube.com/watch?v=C_0VL4Gp4_U ### Advanced @@ -32,7 +35,9 @@ For more advanced information on the micro:bit Bluetooth magnetometer service in ### See also -[Bluetooth SIG](https://www.bluetooth.com) +[Bluetooth SIG](https://www.bluetooth.com), [Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) -[Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) +```package +microbit-bluetooth +``` diff --git a/docs/reference/bluetooth/start-temperature-service.md b/docs/reference/bluetooth/start-temperature-service.md index 298c9a63..4f695da6 100755 --- a/docs/reference/bluetooth/start-temperature-service.md +++ b/docs/reference/bluetooth/start-temperature-service.md @@ -1,30 +1,33 @@ # Bluetooth Temperature Service +### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. + +### ~ + A micro:bit is able to provide a rough measure of the current environmental temperature. It's an approximation only as in fact the temperature value is inferred from the temperature of its main processor. The Bluetooth temperature service allows another device such as a smartphone to wirelessly find out the micro:bit's current temperature reading or to receive a constant stream of temperature data values. Temperature values are expressed in degrees celsius. Using the Bluetooth temperature service you could turn your smartphone or tablet into a graphical thermometer using your micro:bit as the sensor. No additional code is needed on the micro:bit to use the Bluetooth temperature service from another device. -~~~~sig +```sig bluetooth.startTemperatureService(); -~~~~ +``` ### Example: Starting the Bluetooth temperature service The following code shows the Bluetooth temperature service being started: -~~~~blocks +```blocks bluetooth.startTemperatureService(); -~~~~ +``` ### Video - Temperature service demo - Starts at 3:05 -[![micro:bit Bluetooth demo video](/static/bluetooth/microbit_temperature.png)]( - http://www.youtube.com/watch?v=aep_GVowKfs "Click to launch YouTube video" - ) +http://www.youtube.com/watch?v=aep_GVowKfs ### Advanced @@ -32,7 +35,10 @@ For more advanced information on the micro:bit Bluetooth temperature service inc ### See also -[Bluetooth SIG](https://www.bluetooth.com) +[Bluetooth SIG](https://www.bluetooth.com), [Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) -[Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) + +```package +microbit-bluetooth +``` From 64826db4aa66be5b7f22c81b417fb5a9c9a14003 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Wed, 22 Jun 2016 09:43:03 -0700 Subject: [PATCH 04/42] importing chrome extension --- clients/chrome/README.md | 26 ++++++++++ clients/chrome/background.js | 68 +++++++++++++++++++++++++ clients/chrome/background.ts | 92 ++++++++++++++++++++++++++++++++++ clients/chrome/logo128.png | Bin 0 -> 6051 bytes clients/chrome/logo48.png | Bin 0 -> 2251 bytes clients/chrome/manifest.json | 28 +++++++++++ clients/chrome/screenshot.png | Bin 0 -> 141590 bytes clients/chrome/tsconfig.json | 7 +++ 8 files changed, 221 insertions(+) create mode 100644 clients/chrome/README.md create mode 100644 clients/chrome/background.js create mode 100644 clients/chrome/background.ts create mode 100644 clients/chrome/logo128.png create mode 100644 clients/chrome/logo48.png create mode 100644 clients/chrome/manifest.json create mode 100644 clients/chrome/screenshot.png create mode 100644 clients/chrome/tsconfig.json diff --git a/clients/chrome/README.md b/clients/chrome/README.md new file mode 100644 index 00000000..b3261250 --- /dev/null +++ b/clients/chrome/README.md @@ -0,0 +1,26 @@ +# microbit-chrome +Prototype chrome addon that exposes the micro:bit's serial output to webpages. +* watch the [demo video](https://vimeo.com/146207766) + +# Installation +See [developer.chrome.com](https://developer.chrome.com/extensions/getstarted#unpacked) +for instructions on how to install the local version into your chrome browser. + +# Requirements +* Chrome 48 or later. + +# Sample page +The `demo.html` webpage goes along with the +https://github.com/Microsoft/microbit-touchdevelop/blob/master/examples/tcs34725.cpp +program. Run `http-server` from this directory, then visit +http://localhost:8080/demo.html +(keep in mind that pages served from `file://` cannot open ports). + +# Building + +Open a command prompt and run the following commands. + +```` +npm install +typings update +```` \ No newline at end of file diff --git a/clients/chrome/background.js b/clients/chrome/background.js new file mode 100644 index 00000000..777b73ae --- /dev/null +++ b/clients/chrome/background.js @@ -0,0 +1,68 @@ +/// +var connections = []; +// A list of "ports", i.e. connected clients (such as web pages). Multiple web +// pages can connect to our service: they all receive the same data. +var ports = []; +function byPath(path) { + return connections.filter(function (x) { return x.path == path; }); +} +function byId(id) { + return connections.filter(function (x) { return x.id == id; }); +} +function onReceive(data, id) { + if (ports.length == 0) + return; + var view = new DataView(data); + var decoder = new TextDecoder("utf-8"); + var decodedString = decoder.decode(view); + ports.forEach(function (port) { return port.postMessage({ + type: "serial", + data: decodedString, + id: id + }); }); +} +function findNewDevices() { + chrome.serial.getDevices(function (serialPorts) { + serialPorts.forEach(function (serialPort) { + if (byPath(serialPort.path).length == 0 && + serialPort.displayName == "mbed Serial Port") { + chrome.serial.connect(serialPort.path, { bitrate: 115200 }, function (info) { + // In case the [connect] operation takes more than five seconds... + if (info && byPath(serialPort.path).length == 0) + connections.push({ + id: info.connectionId, + path: serialPort.path + }); + }); + } + }); + }); +} +function main() { + // Register new clients in the [ports] global variable. + chrome.runtime.onConnectExternal.addListener(function (port) { + if (/^(micro:bit|touchdevelop|yelm|pxt|codemicrobit|codethemicrobit)$/.test(port.name)) { + ports.push(port); + port.onDisconnect.addListener(function () { + ports = ports.filter(function (x) { return x != port; }); + }); + } + }); + // When receiving data for one of the connections that we're tracking, forward + // it to all connected clients. + chrome.serial.onReceive.addListener(function (info) { + if (byId(info.connectionId).length > 0) + onReceive(info.data, info.connectionId); + }); + // When it looks like we've been disconnected, drop the corresponding + // connection object from the [connections] global variable. + chrome.serial.onReceiveError.addListener(function (info) { + if (info.error == "system_error" || info.error == "disconnected" || info.error == "device_lost") + connections = connections.filter(function (x) { return x.id != info.connectionId; }); + }); + // Probe serial connections at regular intervals. In case we find an mbed port + // we haven't yet connected to, connect to it. + setInterval(findNewDevices, 5000); + findNewDevices(); +} +document.addEventListener("DOMContentLoaded", main); diff --git a/clients/chrome/background.ts b/clients/chrome/background.ts new file mode 100644 index 00000000..8925a363 --- /dev/null +++ b/clients/chrome/background.ts @@ -0,0 +1,92 @@ +// A list of: { +// id: number; +// path: string; +// } where [id] is the [connectionId] (internal to Chrome) and [path] is the +// OS' name for the device (e.g. "COM4"). +interface Connection { + id: string; + path: string; +} +let connections: Connection[] = []; + +// A list of "ports", i.e. connected clients (such as web pages). Multiple web +// pages can connect to our service: they all receive the same data. +let ports = []; + +interface Message { + type: string; + data: string; + id: string; +} + +function byPath(path: string): Connection[] { + return connections.filter((x) => x.path == path); +} + +function byId(id: string): Connection[] { + return connections.filter((x) => x.id == id); +} + +function onReceive(data, id: string) { + if (ports.length == 0) return; + + let view = new DataView(data); + let decoder = new TextDecoder("utf-8"); + let decodedString = decoder.decode(view); + ports.forEach(port => port.postMessage({ + type: "serial", + data: decodedString, + id: id, + })); +} + +function findNewDevices() { + chrome.serial.getDevices(function (serialPorts) { + serialPorts.forEach(function (serialPort) { + if (byPath(serialPort.path).length == 0 && + serialPort.displayName == "mbed Serial Port") { + chrome.serial.connect(serialPort.path, { bitrate: 115200 }, function (info) { + // In case the [connect] operation takes more than five seconds... + if (info && byPath(serialPort.path).length == 0) + connections.push({ + id: info.connectionId, + path: serialPort.path + }); + }); + } + }); + }); +} + +function main() { + // Register new clients in the [ports] global variable. + chrome.runtime.onConnectExternal.addListener(function (port) { + if (/^(micro:bit|touchdevelop|yelm|pxt|codemicrobit|codethemicrobit)$/.test(port.name)) { + ports.push(port); + port.onDisconnect.addListener(function () { + ports = ports.filter(function (x) { return x != port }); + }); + } + }); + + // When receiving data for one of the connections that we're tracking, forward + // it to all connected clients. + chrome.serial.onReceive.addListener(function (info) { + if (byId(info.connectionId).length > 0) + onReceive(info.data, info.connectionId); + }); + + // When it looks like we've been disconnected, drop the corresponding + // connection object from the [connections] global variable. + chrome.serial.onReceiveError.addListener(function (info) { + if (info.error == "system_error" || info.error == "disconnected" || info.error == "device_lost") + connections = connections.filter((x) => x.id != info.connectionId); + }); + + // Probe serial connections at regular intervals. In case we find an mbed port + // we haven't yet connected to, connect to it. + setInterval(findNewDevices, 5000); + findNewDevices(); +} + +document.addEventListener("DOMContentLoaded", main); diff --git a/clients/chrome/logo128.png b/clients/chrome/logo128.png new file mode 100644 index 0000000000000000000000000000000000000000..eae35f4c347bd3b7e0c026f3c33d16046dda5f32 GIT binary patch literal 6051 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 literal 0 HcmV?d00001 diff --git a/clients/chrome/logo48.png b/clients/chrome/logo48.png new file mode 100644 index 0000000000000000000000000000000000000000..0af483f8ec7b2f38248ffbffcf6969301c246abb GIT binary patch literal 2251 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 Date: Wed, 22 Jun 2016 09:43:41 -0700 Subject: [PATCH 05/42] migration to codethemicrobit.com --- README.md | 6 +- ...xt.io.jsproj => codethemicrobitapp.jsproj} | 0 clients/win10/app/package.appxmanifest | 4 +- .../winuploader/CodeTheMicroBit.Loader.sln | 22 ------- clients/winuploader/CodeTheMicroBit.sln | 66 +++++++++++++++++++ ...Uploader.csproj => CodeTheMicrobit.csproj} | 2 +- .../LicenseDialog.Designer.cs | 2 +- .../Microbit.Uploader/MainForm.Designer.cs | 3 +- .../winuploader/Microbit.Uploader/MainForm.cs | 11 ++-- docs/reference/offline.md | 2 +- docs/windows10.md | 12 +--- pxtarget.json | 10 +-- 12 files changed, 90 insertions(+), 50 deletions(-) rename clients/win10/app/{m.pxt.io.jsproj => codethemicrobitapp.jsproj} (100%) delete mode 100644 clients/winuploader/CodeTheMicroBit.Loader.sln create mode 100644 clients/winuploader/CodeTheMicroBit.sln rename clients/winuploader/Microbit.Uploader/{CodeTheMicrobit.Uploader.csproj => CodeTheMicrobit.csproj} (98%) diff --git a/README.md b/README.md index ef81e233..0d435614 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This target allow to program a [BBC micro:bit](https://www.microbit.co.uk/) using PXT ([Microsoft Programming Experience Toolkit](https://github.com/Microsoft/pxt)). -* [Try it live](https://m.pxt.io) +* [Try it live](https://codethemicrobit.com) [![Build Status](https://travis-ci.org/Microsoft/pxt-microbit.svg?branch=master)](https://travis-ci.org/Microsoft/pxt-microbit) @@ -47,12 +47,12 @@ More instructions at https://github.com/Microsoft/pxt#running-a-target-from-loca ## Universal Windows App The Windows 10 app is a [Universal Windows Hosted Web App](https://microsoftedge.github.io/WebAppsDocs/en-US/win10/CreateHWA.htm) -that wraps ``m.pxt.io`` and provides additional features. +that wraps ``codethemicrobit.com`` and provides additional features. ### Building * Install Visual Studio 2015 Update 2 or higher. Make sure the Windows 10 templates are installed. -* open the ``win10/app.sln`` solution and launch the ``m.pxt.io`` project. +* open the ``win10/app.sln`` solution and launch the ``codethemicrobit`` project. ## Code of Conduct diff --git a/clients/win10/app/m.pxt.io.jsproj b/clients/win10/app/codethemicrobitapp.jsproj similarity index 100% rename from clients/win10/app/m.pxt.io.jsproj rename to clients/win10/app/codethemicrobitapp.jsproj diff --git a/clients/win10/app/package.appxmanifest b/clients/win10/app/package.appxmanifest index 74ee73b2..2915d938 100644 --- a/clients/win10/app/package.appxmanifest +++ b/clients/win10/app/package.appxmanifest @@ -14,13 +14,13 @@ - + - + diff --git a/clients/winuploader/CodeTheMicroBit.Loader.sln b/clients/winuploader/CodeTheMicroBit.Loader.sln deleted file mode 100644 index 9c82e656..00000000 --- a/clients/winuploader/CodeTheMicroBit.Loader.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeTheMicrobit.Uploader", "Microbit.Uploader\CodeTheMicrobit.Uploader.csproj", "{7DC6CA45-FD75-44BC-805E-708C812CD4BF}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/clients/winuploader/CodeTheMicroBit.sln b/clients/winuploader/CodeTheMicroBit.sln new file mode 100644 index 00000000..4401ca6e --- /dev/null +++ b/clients/winuploader/CodeTheMicroBit.sln @@ -0,0 +1,66 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeTheMicrobit", "Microbit.Uploader\CodeTheMicrobit.csproj", "{7DC6CA45-FD75-44BC-805E-708C812CD4BF}" +EndProject +Project("{262852C6-CD72-467D-83FE-5EEB1973A190}") = "codethemicrobitapp", "..\win10\app\codethemicrobitapp.jsproj", "{39122940-AB16-4CD4-A0CE-79A3EB863ECF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Debug|ARM.ActiveCfg = Debug|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Debug|ARM.Build.0 = Debug|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Debug|x64.ActiveCfg = Debug|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Debug|x64.Build.0 = Debug|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Debug|x86.ActiveCfg = Debug|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Debug|x86.Build.0 = Debug|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Release|Any CPU.Build.0 = Release|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Release|ARM.ActiveCfg = Release|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Release|ARM.Build.0 = Release|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Release|x64.ActiveCfg = Release|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Release|x64.Build.0 = Release|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Release|x86.ActiveCfg = Release|Any CPU + {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Release|x86.Build.0 = Release|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|ARM.ActiveCfg = Debug|ARM + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|ARM.Build.0 = Debug|ARM + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|ARM.Deploy.0 = Debug|ARM + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|x64.ActiveCfg = Debug|x64 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|x64.Build.0 = Debug|x64 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|x64.Deploy.0 = Debug|x64 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|x86.ActiveCfg = Debug|x86 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|x86.Build.0 = Debug|x86 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|x86.Deploy.0 = Debug|x86 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|Any CPU.Build.0 = Release|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|Any CPU.Deploy.0 = Release|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|ARM.ActiveCfg = Release|ARM + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|ARM.Build.0 = Release|ARM + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|ARM.Deploy.0 = Release|ARM + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|x64.ActiveCfg = Release|x64 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|x64.Build.0 = Release|x64 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|x64.Deploy.0 = Release|x64 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|x86.ActiveCfg = Release|x86 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|x86.Build.0 = Release|x86 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/clients/winuploader/Microbit.Uploader/CodeTheMicrobit.Uploader.csproj b/clients/winuploader/Microbit.Uploader/CodeTheMicrobit.csproj similarity index 98% rename from clients/winuploader/Microbit.Uploader/CodeTheMicrobit.Uploader.csproj rename to clients/winuploader/Microbit.Uploader/CodeTheMicrobit.csproj index 077710b6..0436a0f6 100644 --- a/clients/winuploader/Microbit.Uploader/CodeTheMicrobit.Uploader.csproj +++ b/clients/winuploader/Microbit.Uploader/CodeTheMicrobit.csproj @@ -8,7 +8,7 @@ WinExe Properties Microsoft.MicroBit - Microbit.Uploader + CodeTheMicrobit v2.0 512 true diff --git a/clients/winuploader/Microbit.Uploader/LicenseDialog.Designer.cs b/clients/winuploader/Microbit.Uploader/LicenseDialog.Designer.cs index bf8ed131..70ca5739 100644 --- a/clients/winuploader/Microbit.Uploader/LicenseDialog.Designer.cs +++ b/clients/winuploader/Microbit.Uploader/LicenseDialog.Designer.cs @@ -79,7 +79,7 @@ this.MinimizeBox = false; this.Name = "LicenseDialog"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "code the micro:bit uploader Terms Of Use"; + this.Text = "code the micro:bit terms of use"; this.ResumeLayout(false); } diff --git a/clients/winuploader/Microbit.Uploader/MainForm.Designer.cs b/clients/winuploader/Microbit.Uploader/MainForm.Designer.cs index cf9a6d0c..a27b4fa5 100644 --- a/clients/winuploader/Microbit.Uploader/MainForm.Designer.cs +++ b/clients/winuploader/Microbit.Uploader/MainForm.Designer.cs @@ -116,6 +116,7 @@ this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; this.pictureBox1.TabIndex = 5; this.pictureBox1.TabStop = false; + this.pictureBox1.Click += new System.EventHandler(this.pictureBox1_Click); // // linkLabel1 // @@ -148,7 +149,7 @@ this.ShowInTaskbar = false; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "code the micro:bit uploader"; + this.Text = "code the micro:bit"; this.Load += new System.EventHandler(this.MainForm_Load); ((System.ComponentModel.ISupportInitialize)(this.backgroundPictureBox)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); diff --git a/clients/winuploader/Microbit.Uploader/MainForm.cs b/clients/winuploader/Microbit.Uploader/MainForm.cs index 2800bda3..beba1b58 100644 --- a/clients/winuploader/Microbit.Uploader/MainForm.cs +++ b/clients/winuploader/Microbit.Uploader/MainForm.cs @@ -243,11 +243,7 @@ namespace Microsoft.MicroBit private void backgroundPictureBox_Click(object sender, EventArgs e) { - try - { - Process.Start("https://codethemicrobit.com"); - } - catch (IOException) { } + this.openEditor(); } private void SettingsLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) @@ -262,5 +258,10 @@ namespace Microsoft.MicroBit { this.openEditor(); } + + private void pictureBox1_Click(object sender, EventArgs e) + { + this.openEditor(); + } } } diff --git a/docs/reference/offline.md b/docs/reference/offline.md index e40e9b46..028f3dc8 100644 --- a/docs/reference/offline.md +++ b/docs/reference/offline.md @@ -4,7 +4,7 @@ The micro:bit pins. ## How to work offline -If you have loaded the web app at some time in the past (by clicking on "my scripts" from the home page), then if you later open the same browser (whether you are online or offline) and type in [https://m.pxt.io/](https://m.pxt.io/), you will be able to access all the features of the web app. Note that it is important to end the URL with "/". +If you have loaded the web app at some time in the past (by clicking on "my scripts" from the home page), then if you later open the same browser (whether you are online or offline) and type in [https://codethemicrobit.com/](https://codethemicrobit.com/), you will be able to access all the features of the web app. Note that it is important to end the URL with "/". ## Save and load code using files diff --git a/docs/windows10.md b/docs/windows10.md index dcb8d66b..3f79bbc3 100644 --- a/docs/windows10.md +++ b/docs/windows10.md @@ -2,17 +2,11 @@ ## Features -The Windows 10 App provides all the existing features of [m.pxt.io](https://m.pxt.io) plus the following ones: +The Windows 10 App provides all the existing features of [codethemicrobit](https://codethemicrobit.com) plus the following ones: * **auto-upload**: the compiled .hex file is automatically deployed to all connected BBC micro:bits * **serial piping**: all serial data sent by connected BBC micro:bit is automatically imported and analyzed in the editor. -## Installing the pre-release app +## Installing the app -The following instructions allow to side-load the Windows 10 app. This is required until the app is in the store. - -* Search for “developer settings” in Windows 10 and put your computer in “Developer mode”. -* Download https://m.pxt.io/codemicrobit.appx and unzip it. **DO NOT try to install from a zipped folder.** -* Open the extracted folder, right-click on `Add-AppDevPackage.ps1` and click on `Run with PowerShell`. Follow the prompts… - -4) In order to communicate with the micro:bit via serial, you need to install the [ARM mbed driver](https://developer.mbed.org/handbook/Windows-serial-configuration). +Coming to the store soon! \ No newline at end of file diff --git a/pxtarget.json b/pxtarget.json index 1cd50988..93138988 100644 --- a/pxtarget.json +++ b/pxtarget.json @@ -1,7 +1,7 @@ { "id": "microbit", - "name": "m.pxt.io", - "title": "m.pxt.io", + "name": "code the micro:bit", + "title": "code the micro:bit", "corepkg": "microbit", "bundleddirs": [ "libs/microbit", @@ -81,14 +81,14 @@ }, "appTheme": { "accentColor": "#5C005C", - "logoUrl": "https://m.pxt.io/about", + "logoUrl": "https://codethemicrobit.com/about", "logo": "./static/microbit.simplified.svg", "docsLogo": "./static/microbit.simplified.svg", "portraitLogo": "./static/microbit.simplified.svg", "footerLogo": "./static/microbit.simplified.svg", "organizationLogo": "./static/Microsoft-logo_rgb_c-gray.png", - "homeUrl": "https://m.pxt.io/", - "embedUrl": "https://m.pxt.io/", + "homeUrl": "https://codethemicrobit.com/", + "embedUrl": "https://codethemicrobit.com/", "privacyUrl": "https://go.microsoft.com/fwlink/?LinkId=521839", "termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977", "boardName": "BBC micro:bit", From 597f0c895be0760081cf625536a20289552562f6 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Wed, 22 Jun 2016 12:17:40 -0700 Subject: [PATCH 06/42] Bump pxt-core to 0.2.187 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 42a22644..8f2d18b8 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,6 @@ "typescript": "^1.8.7" }, "dependencies": { - "pxt-core": "0.2.185" + "pxt-core": "0.2.187" } } From 18feea45bbcf5bf30ea183befc4de84554ac01b6 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Wed, 22 Jun 2016 12:17:43 -0700 Subject: [PATCH 07/42] 0.2.175 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8f2d18b8..5a2b8bbc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pxt-microbit", - "version": "0.2.174", + "version": "0.2.175", "description": "BBC micro:bit target for PXT", "keywords": [ "JavaScript", From 1f203269ff9a395fbc190c421e67e65592a63688 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Wed, 22 Jun 2016 14:48:51 -0700 Subject: [PATCH 08/42] updated chrome manifest --- clients/chrome/manifest.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clients/chrome/manifest.json b/clients/chrome/manifest.json index ae3adecb..a94c62a6 100644 --- a/clients/chrome/manifest.json +++ b/clients/chrome/manifest.json @@ -7,11 +7,13 @@ "manifest_version": 2, "name": "code the micro:bit", - "version": "0.1.0", + "version": "0.6.0", "author": "Microsoft Corporation", "short_name": "code the micro:bit", - "description": "This extension reads the serial output from connected BBC micro:bit and sends it to https://codethemicrobit.com.", + "description": "Extension for https://codethemicrobit.com.", + "homepage_url": "https://codethemicrobit.com", + "offline_enabled": "true", "icons": { "48": "logo48.png", "128": "logo128.png" @@ -23,6 +25,6 @@ ], "externally_connectable": { - "matches": [ "*://localhost/*", "https://*.pxt.io/*", "https://codethemicrobit.com/*" ] + "matches": [ "*://localhost/*", "https://codethemicrobit.com/*", "https://*.codethemicrobit.com/*" ] } } From e65a521bd42d1e50084ee6e5a0fed5d3ef302441 Mon Sep 17 00:00:00 2001 From: Ron Hale-Evans Date: Wed, 22 Jun 2016 15:19:10 -0700 Subject: [PATCH 09/42] Rewrote in simple language. Added second example. --- docs/reference/pins/digital-read-pin.md | 46 ++++++++++++++++++++----- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/docs/reference/pins/digital-read-pin.md b/docs/reference/pins/digital-read-pin.md index 22ff2443..baa98dbe 100644 --- a/docs/reference/pins/digital-read-pin.md +++ b/docs/reference/pins/digital-read-pin.md @@ -1,24 +1,32 @@ # Digital Read Pin -The digital read pin function. - -Digitally read the specified [pin](/device/pins) (``P0``, ``P1``, ``P2``, ...) as digital. **Some pins are also used by the display, read the [pin documentation ](/device/pins) carefully.** +Read a **digital** (`0` or `1`) signal from a [pin](/device/pins) on +the micro:bit board. ```sig pins.digitalReadPin(DigitalPin.P3) ``` +### ~avatar + +Some pins are also used by the [LED screen](/device/screen). +Please read the [page about pins](/device/pins) carefully. + +### ~ + ### Parameters -* name - the pin name ``P0``, ``P1``, ``P2``, ... +* a [string](/reference/types/string) that stores the name of the pin (``P0``, ``P1``, or ``P2``, up through ``P20``) ### Returns -* [Number](/reference/types/number) - 0 or 1 +* a [number](/reference/types/number) that can be `0` or `1` ### Example: football score keeper -The following example reads `P0` to determine when a goal is scored. When `P0 = 1`, the code uses `digital write pin` to play a buzzer sound: +This program reads pin `P0` to find when a goal is scored. When `P0` +is `1`, the program makes the score bigger and plays a buzzer sound +through `P2` with ``digital write pin``. ```blocks let score = 0 @@ -34,7 +42,29 @@ basic.forever(() => { }) ``` +This program is a remote control for the score keeper program. If you +connect `P1` on the remote control micro:bit to `P0` on the score +keeper micro:bit, you can press button `B` on the remote to buzz and +make the score bigger on the other micro:bit. + +```blocks +input.onButtonPressed(Button.B, () => { + pins.digitalWritePin(DigitalPin.P1, 1); + basic.pause(500); + pins.digitalWritePin(DigitalPin.P1, 0); +}); +``` +#### ~hint + +Remember to connect `GND` on both micro:bits together! + +#### ~ + ### See also -[micro:bit pins](/device/pins), [digital write pin](/reference/pins/digital-write-pin), [analog read pin](/reference/pins/analog-read-pin), [analog write pin](/reference/pins/analog-write-pin), [on pin pressed](/reference/input/on-pin-pressed), [pin is pressed](/reference/input/pin-is-pressed) - +[micro:bit pins](/device/pins), +[digital write pin](/reference/pins/digital-write-pin), +[analog read pin](/reference/pins/analog-read-pin), +[analog write pin](/reference/pins/analog-write-pin), +[on pin pressed](/reference/input/on-pin-pressed), +[pin is pressed](/reference/input/pin-is-pressed) From c0a75d1845632f178c6cc3fd44e28f2f6af9ecb8 Mon Sep 17 00:00:00 2001 From: Ron Hale-Evans Date: Wed, 22 Jun 2016 15:35:20 -0700 Subject: [PATCH 10/42] Rewrote in simpler language. Added another example. --- docs/reference/pins/digital-write-pin.md | 38 ++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/docs/reference/pins/digital-write-pin.md b/docs/reference/pins/digital-write-pin.md index 90d862de..72771996 100644 --- a/docs/reference/pins/digital-write-pin.md +++ b/docs/reference/pins/digital-write-pin.md @@ -1,19 +1,29 @@ # Digital Write Pin -Write the value ``0`` or ``1`` to the specified (digital) [pin](/device/pins). **Some pins are also used by the display, read the [pin documentation ](/device/pins) carefully.** +Write a **digital** (`0` or `1`) signal to a [pin](/device/pins) on +the micro:bit board. ```sig pins.digitalWritePin(DigitalPin.P1, 1) ``` +### ~avatar + +Some pins are also used by the [LED screen](/device/screen). +Please read the [page about pins](/device/pins) carefully. + +### ~ + ### Parameters -* name - the pin name (``P0``, ``P1``, ``P2``, ...) -* value - [Number](/reference/types/number); 0 or 1 +* a [string](/reference/types/string) that stores the name of the pin (``P0``, ``P1``, or ``P2``, up through ``P20``) +* a [number](/reference/types/number) that can be either `0` or `1` ### Example: football score keeper -The following example reads `P0` to determine when a goal is scored. When `P0 = 1`, the code uses `digital write pin` to play a buzzer sound: +This program reads pin `P0` to find when a goal is scored. When `P0` +is `1`, the program makes the score bigger and plays a buzzer sound +through `P2` with ``digital write pin``. ```blocks let score = 0 @@ -29,7 +39,25 @@ basic.forever(() => { }) ``` +This program is a remote control for the score keeper program. If you +connect `P1` on the remote control micro:bit to `P0` on the score +keeper micro:bit, you can press button `B` on the remote. This program +will use ``digital write pin`` to make the other micro:bit buzz and +make the score bigger. + +```blocks +input.onButtonPressed(Button.B, () => { + pins.digitalWritePin(DigitalPin.P1, 1); + basic.pause(500); + pins.digitalWritePin(DigitalPin.P1, 0); +}); +``` + ### See also -[micro:bit pins](/device/pins), [digital read pin](/reference/pins/digital-read-pin), [analog read pin](/reference/pins/analog-read-pin), [analog write pin](/reference/pins/analog-write-pin), [on pin pressed](/reference/input/on-pin-pressed) +[micro:bit pins](/device/pins), +[digital read pin](/reference/pins/digital-read-pin), +[analog read pin](/reference/pins/analog-read-pin), +[analog write pin](/reference/pins/analog-write-pin), +[on pin pressed](/reference/input/on-pin-pressed) From ccf405e64cf3b9d06e78be2c28d46b4d83f33847 Mon Sep 17 00:00:00 2001 From: Ron Hale-Evans Date: Wed, 22 Jun 2016 16:24:14 -0700 Subject: [PATCH 11/42] Rewrote in simple language --- docs/reference/pins/analog-read-pin.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/reference/pins/analog-read-pin.md b/docs/reference/pins/analog-read-pin.md index d1ee83bd..12768b3f 100644 --- a/docs/reference/pins/analog-read-pin.md +++ b/docs/reference/pins/analog-read-pin.md @@ -1,6 +1,7 @@ # Analog Read Pin -Read the specified [pin](/device/pins) (P0, P1, P2) as analog. +Read an **analog** signal (`0` through `1023`) from the +[pin](/device/pins) you say. ```sig pins.analogReadPin(AnalogPin.P0) @@ -8,13 +9,14 @@ pins.analogReadPin(AnalogPin.P0) ### Parameters -* name - the pin name (`P0`, `P1`, or `P2`) +* a [string](/reference/types/string) that stores the pin you say (`P0` through `P4`, or `P10`) ### Returns -* [Number](/reference/types/number) - a number between 0 and 1023 (included) +* a [number](/reference/types/number) from `0` through `1024` -The following code reads `P1` and charts it on the screen: +This program reads pin `P1` and shows the number as a +[bar graph](/reference/led/plot-bar-graph). ```blocks basic.forever(() => { @@ -25,5 +27,9 @@ basic.forever(() => { ### See also -[micro:bit pins](/device/pins), [on pin pressed](/reference/input/on-pin-pressed), [analog write pin](/reference/pins/analog-write-pin), [digital read pin](/reference/pins/digital-read-pin), [digital write pin](/reference/pins/digital-write-pin) +[micro:bit pins](/device/pins), +[on pin pressed](/reference/input/on-pin-pressed), +[analog write pin](/reference/pins/analog-write-pin), +[digital read pin](/reference/pins/digital-read-pin), +[digital write pin](/reference/pins/digital-write-pin) From 9d71f46e7886a3175922031af4b04a3d0c66837a Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Wed, 22 Jun 2016 20:24:41 -0700 Subject: [PATCH 12/42] removed old test --- testconv.json | 1 - 1 file changed, 1 deletion(-) diff --git a/testconv.json b/testconv.json index ae8b3095..c80cba75 100644 --- a/testconv.json +++ b/testconv.json @@ -142,7 +142,6 @@ "fbpnng", "fbyrog", "fcfoox", - "fcgdzt", "fcicvk", "fcjlto", "fcvwvj", From 7cd8ee1e23eaa5b30ccd18e0031c681d1c303bed Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Wed, 22 Jun 2016 20:25:02 -0700 Subject: [PATCH 13/42] 0.2.176 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a2b8bbc..b26b229b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pxt-microbit", - "version": "0.2.175", + "version": "0.2.176", "description": "BBC micro:bit target for PXT", "keywords": [ "JavaScript", From 82e34d852caf1118a911d32ae912f590ba35fa2f Mon Sep 17 00:00:00 2001 From: Martin Woolley Date: Thu, 23 Jun 2016 08:05:49 +0100 Subject: [PATCH 14/42] checking in --- libs/microbit-bluetooth/bluetooth.cpp | 16 ++++++++++++++-- libs/microbit-bluetooth/shims.d.ts | 7 +++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/libs/microbit-bluetooth/bluetooth.cpp b/libs/microbit-bluetooth/bluetooth.cpp index ab995204..0d86661e 100644 --- a/libs/microbit-bluetooth/bluetooth.cpp +++ b/libs/microbit-bluetooth/bluetooth.cpp @@ -1,5 +1,7 @@ #include "pxt.h" #include "MESEvents.h" +#include "MicroBitUARTService.h" +MicroBitUARTService *uart; using namespace pxt; //% color=#0082FB weight=20 @@ -77,6 +79,16 @@ namespace bluetooth { void onBluetoothDisconnected(Action body) { registerWithDal(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_DISCONNECTED, body); } - - + + /** + * Starts the Bluetooth UART service + */ + //% help=bluetooth/start-uart-service + //% blockId=bluetooth_start_uart_service block="bluetooth|uart|service" blockGap=8 + + void startUartService() { + // 32 octet buffer size is + uart = new MicroBitUARTService(*uBit.ble, 32, 32); + } + } diff --git a/libs/microbit-bluetooth/shims.d.ts b/libs/microbit-bluetooth/shims.d.ts index 9d7d49b5..f618c4ba 100644 --- a/libs/microbit-bluetooth/shims.d.ts +++ b/libs/microbit-bluetooth/shims.d.ts @@ -62,6 +62,13 @@ declare namespace bluetooth { //% help=bluetooth/on-bluetooth-disconnected //% blockId=bluetooth_on_disconnected block="on bluetooth disconnected" shim=bluetooth::onBluetoothDisconnected function onBluetoothDisconnected(body: () => void): void; + + /** + * Starts the Bluetooth UART service + */ + //% help=bluetooth/start-uart-service + //% blockId=bluetooth_start_uart_service block="bluetooth|uart|service" blockGap=8 shim=bluetooth::startUartService + function startUartService(): void; } // Auto-generated. Do not edit. Really. From 76005841fa841fd2adb26a46f285977e8fdc0d3e Mon Sep 17 00:00:00 2001 From: Martin Woolley Date: Thu, 23 Jun 2016 11:38:23 +0100 Subject: [PATCH 15/42] Increased default power to 6, added UART write block --- .../bluetooth/start-accelerometer-service.md | 2 +- .../reference/bluetooth/start-uart-service.md | 44 ++++++++++++++++ docs/reference/bluetooth/uart-write.md | 52 +++++++++++++++++++ libs/microbit-bluetooth/bluetooth.cpp | 28 +++++++++- libs/microbit-bluetooth/pxt.json | 2 +- libs/microbit-bluetooth/shims.d.ts | 15 ++++++ 6 files changed, 139 insertions(+), 4 deletions(-) create mode 100755 docs/reference/bluetooth/start-uart-service.md create mode 100755 docs/reference/bluetooth/uart-write.md diff --git a/docs/reference/bluetooth/start-accelerometer-service.md b/docs/reference/bluetooth/start-accelerometer-service.md index 140c3f77..a96e9bcd 100755 --- a/docs/reference/bluetooth/start-accelerometer-service.md +++ b/docs/reference/bluetooth/start-accelerometer-service.md @@ -27,7 +27,7 @@ bluetooth.startAccelerometerService(); ### Video - Accelerometer service demo - Starts at 0:18 -http://www.youtube.com/watch?v=aep_GVowKfs +http://www.youtube.com/watch?v=aep_GVowKfs#t=18s ### Advanced diff --git a/docs/reference/bluetooth/start-uart-service.md b/docs/reference/bluetooth/start-uart-service.md new file mode 100755 index 00000000..6b8d5784 --- /dev/null +++ b/docs/reference/bluetooth/start-uart-service.md @@ -0,0 +1,44 @@ +# Bluetooth UART Service + +### ~hint +![](/static/bluetooth/Bluetooth_SIG.png) + +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. + +### ~ + +The Bluetooth UART service allows another device such as a smartphone to exchange any data it wants to with the micro:bit, in small chunks which are intended to be joined together. [UART[(https://en.wikipedia.org/wiki/Universal_asynchronous_receiver/transmitter) stands for Universal Asynchronous Receiver Transmitter and is one way in which serial data communications can be performed, usually between two devices connected by a physical, wired connection. The Bluetooth UART service emulates the behaviour of a physical UART system and allows the exchange of a maximum of 20 bytes of data at a time in either direction. + +When this service is used, the micro:bit sets up a 60 byte buffer and data it receives will be accumulated in the buffer until it is full. When using the UART service from your micro:bit code, you can indicate a special character which will be used to mean that the entire message in at most three chunks has now been sent by the other, connected device, at which point the micro:bit will release the entire contents of its buffer to any code trying to read it. In other words this special character, known as a 'delimiter' is used by the device connected to the micro:bit to mean "I've sent my whole message, you can now use it". + +You could use the UART service for many things. It doesn't care what you put in messages which makes it very flexible. You could create a guessing game, with questions and answers passing between micro:bit and a smartphone or you could connect a camera to the micro:bit and transmit image data obtained from the edge connector, in chunks over Bluetooth to a smartphone. There are a great many possibilities. + +To use the Bluetooth UART service from another device you'll need additional micro:bit code which reads and uses data from the UART buffer and / or writes data to the buffer for transmission over Bluetooth to another device. + +```sig +bluetooth.startUartService(); +``` + +### Example: Starting the Bluetooth UART service + +The following code shows the Bluetooth UART service being started: + +```blocks +bluetooth.startUartService(); +``` + +### Video - UART service guessing game + +https://www.youtube.com/watch?v=PgGeWddMAZ0 + +### Advanced + +For more advanced information on the micro:bit Bluetooth UART service including information on using a smartphone, see the [Lancaster University micro:bit runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/uart-service/) + +### See also + +[Bluetooth SIG](https://www.bluetooth.com), [Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) + +```package +microbit-bluetooth +``` diff --git a/docs/reference/bluetooth/uart-write.md b/docs/reference/bluetooth/uart-write.md new file mode 100755 index 00000000..0f308b8e --- /dev/null +++ b/docs/reference/bluetooth/uart-write.md @@ -0,0 +1,52 @@ +# UART Write + +### ~hint +![](/static/bluetooth/Bluetooth_SIG.png) + +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. + +### ~ + +The [Bluetooth UART service](start-uart-service.md) allows another device such as a smartphone to exchange any data it wants to with the micro:bit, in small chunks. + +With the Bluetooth UART service running, this block allows a micro:bit to send data to a Bluetooth connected device. + +```sig +bluetooth.uartWrite(""); +``` + +### Example: Starting the Bluetooth UART service and then sending "HELLO" whenever button A is pressed and another device has connected over Bluetooth + +```blocks +let connected = 0; +bluetooth.onBluetoothConnected(() => { + basic.showString("C"); + connected = 1; +}); +bluetooth.onBluetoothDisconnected(() => { + basic.showString("D"); + connected = 0; +}); +bluetooth.startUartService(); +input.onButtonPressed(Button.A, () => { + if (connected == 1) { + bluetooth.uartWrite("HELLO"); + } +}); +``` + +### Video - UART service guessing game + +https://www.youtube.com/watch?v=PgGeWddMAZ0 + +### Advanced + +For more advanced information on the micro:bit Bluetooth UART service including information on using a smartphone, see the [Lancaster University micro:bit runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/uart-service/) + +### See also + +[Bluetooth SIG](https://www.bluetooth.com), [Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) + +```package +microbit-bluetooth +``` diff --git a/libs/microbit-bluetooth/bluetooth.cpp b/libs/microbit-bluetooth/bluetooth.cpp index 3bb46d0d..d9c89d00 100644 --- a/libs/microbit-bluetooth/bluetooth.cpp +++ b/libs/microbit-bluetooth/bluetooth.cpp @@ -91,8 +91,32 @@ namespace bluetooth { //% blockId=bluetooth_start_uart_service block="bluetooth|uart|service" blockGap=8 void startUartService() { - // 32 octet buffer size is - uart = new MicroBitUARTService(*uBit.ble, 32, 32); + // 61 octet buffer size is 3 x (MTU - 3) + 1 + // MTU on nRF51822 is 23 octets. 3 are used by Attribute Protocol header data leaving 20 octets for payload + // So we allow a buffer that can contain 3 x max length messages plus one octet for a terminator character + uart = new MicroBitUARTService(*uBit.ble, 61, 60); } + + + /** + * Reads the Bluetooth UART service buffer, returning when a specified 'end of message' delimiter character is encountered + * @param eom End of Message delimiter character + */ + //% help=bluetooth/uart-read + //% blockId=bluetooth_uart_read block="bluetooth|uart|read %eom" blockGap=8 + StringData* uartRead(char* eom) { + // temp hard coding of : as eom delimiter + char delim[6] = {':', 0}; + return uart->readUntil(delim).leakData(); + } + + /** + * Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device. + */ + //% help=bluetooth/uart-write + //% blockId=bluetooth_uart_write block="bluetooth|uart|write %data" blockGap=8 + void uartWrite(StringData* data) { + uart->send(ManagedString(data)); + } } diff --git a/libs/microbit-bluetooth/pxt.json b/libs/microbit-bluetooth/pxt.json index 584ea366..bfa289f0 100644 --- a/libs/microbit-bluetooth/pxt.json +++ b/libs/microbit-bluetooth/pxt.json @@ -21,7 +21,7 @@ "open": 0, "whitelist": 1, "advertising_timeout": 0, - "tx_power": 0, + "tx_power": 6, "dfu_service": 1, "event_service": 1, "device_info_service": 1 diff --git a/libs/microbit-bluetooth/shims.d.ts b/libs/microbit-bluetooth/shims.d.ts index 5de9f0e0..ae918647 100644 --- a/libs/microbit-bluetooth/shims.d.ts +++ b/libs/microbit-bluetooth/shims.d.ts @@ -71,6 +71,21 @@ declare namespace bluetooth { //% help=bluetooth/start-uart-service //% blockId=bluetooth_start_uart_service block="bluetooth|uart|service" blockGap=8 shim=bluetooth::startUartService function startUartService(): void; + + /** + * Reads the Bluetooth UART service buffer, returning when a specified 'end of message' delimiter character is encountered + * @param eom End of Message delimiter character + */ + //% help=bluetooth/uart-read + //% blockId=bluetooth_uart_read block="bluetooth|uart|read %eom" blockGap=8 shim=bluetooth::uartRead + function uartRead(eom: char*): string; + + /** + * Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device. + */ + //% help=bluetooth/uart-write + //% blockId=bluetooth_uart_write block="bluetooth|uart|write %data" blockGap=8 shim=bluetooth::uartWrite + function uartWrite(data: string): void; } // Auto-generated. Do not edit. Really. From 0ecf3dc2b4ea0f1a676f923b25d26e25807820d8 Mon Sep 17 00:00:00 2001 From: Ron Hale-Evans Date: Thu, 23 Jun 2016 14:29:32 -0700 Subject: [PATCH 16/42] Rewrote in simple language. Updated example (needs work). --- docs/reference/pins/analog-read-pin.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/reference/pins/analog-read-pin.md b/docs/reference/pins/analog-read-pin.md index 12768b3f..fceccfe0 100644 --- a/docs/reference/pins/analog-read-pin.md +++ b/docs/reference/pins/analog-read-pin.md @@ -9,19 +9,20 @@ pins.analogReadPin(AnalogPin.P0) ### Parameters -* a [string](/reference/types/string) that stores the pin you say (`P0` through `P4`, or `P10`) +* a [string](/reference/types/string) that stores the name of the pin + you say (`P0` through `P4`, or `P10`) ### Returns -* a [number](/reference/types/number) from `0` through `1024` +* a [number](/reference/types/number) from `0` through `1023` -This program reads pin `P1` and shows the number as a -[bar graph](/reference/led/plot-bar-graph). +This program reads pin `P1` and shows the number +on the LED screen. ```blocks basic.forever(() => { let value = pins.analogReadPin(AnalogPin.P1) - led.plotBarGraph(value, 1023) + basic.showNumber(value) }); ``` @@ -32,4 +33,3 @@ basic.forever(() => { [analog write pin](/reference/pins/analog-write-pin), [digital read pin](/reference/pins/digital-read-pin), [digital write pin](/reference/pins/digital-write-pin) - From 8617f0f3b496d059bfccd8dc96bc0e5ebd628b54 Mon Sep 17 00:00:00 2001 From: Ron Hale-Evans Date: Thu, 23 Jun 2016 15:25:56 -0700 Subject: [PATCH 17/42] Expanded stub. Rewrote in simple language. --- docs/reference/control/reset.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/reference/control/reset.md b/docs/reference/control/reset.md index 16c985ee..59ba8cbe 100644 --- a/docs/reference/control/reset.md +++ b/docs/reference/control/reset.md @@ -1,8 +1,37 @@ # Reset -Reset the BBC micro:bit (as if you pushed the reset button on the back of the device), which causes the program to start again. +Reset the BBC micro:bit and start the program again. + +This function is like pressing the reset button on the back of the micro:bit. ```sig control.reset() ``` +### Example + +This program will count as high as you like when you press button `A`. +When you get tired of counting, press button `B` to reset the +micro:bit and start the program over. + +```blocks +let item = 0; +basic.showNumber(item); +input.onButtonPressed(Button.A, () => { + item = item + 1; + basic.showNumber(item); +}); +input.onButtonPressed(Button.B, () => { + control.reset(); +}); +``` + +#### ~hint + +This program works better on a real micro:bit than in the simulator. + +#### ~ + +### See Also + +[clear screen](/reference/basic/clear-screen), [game over](/reference/game/game-over) From 9378e5e90c8614e6fafa21776d266818fda13da2 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Thu, 23 Jun 2016 16:29:26 -0700 Subject: [PATCH 18/42] updated manifest --- clients/win10/app/codethemicrobitapp.sln | 48 ++++++++++++++++++++++++ clients/win10/app/package.appxmanifest | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 clients/win10/app/codethemicrobitapp.sln diff --git a/clients/win10/app/codethemicrobitapp.sln b/clients/win10/app/codethemicrobitapp.sln new file mode 100644 index 00000000..ae487bac --- /dev/null +++ b/clients/win10/app/codethemicrobitapp.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{262852C6-CD72-467D-83FE-5EEB1973A190}") = "codethemicrobitapp", "codethemicrobitapp.jsproj", "{39122940-AB16-4CD4-A0CE-79A3EB863ECF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|ARM.ActiveCfg = Debug|ARM + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|ARM.Build.0 = Debug|ARM + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|ARM.Deploy.0 = Debug|ARM + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|x64.ActiveCfg = Debug|x64 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|x64.Build.0 = Debug|x64 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|x64.Deploy.0 = Debug|x64 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|x86.ActiveCfg = Debug|x86 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|x86.Build.0 = Debug|x86 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Debug|x86.Deploy.0 = Debug|x86 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|Any CPU.Build.0 = Release|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|Any CPU.Deploy.0 = Release|Any CPU + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|ARM.ActiveCfg = Release|ARM + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|ARM.Build.0 = Release|ARM + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|ARM.Deploy.0 = Release|ARM + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|x64.ActiveCfg = Release|x64 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|x64.Build.0 = Release|x64 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|x64.Deploy.0 = Release|x64 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|x86.ActiveCfg = Release|x86 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|x86.Build.0 = Release|x86 + {39122940-AB16-4CD4-A0CE-79A3EB863ECF}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/clients/win10/app/package.appxmanifest b/clients/win10/app/package.appxmanifest index 2915d938..8eee874c 100644 --- a/clients/win10/app/package.appxmanifest +++ b/clients/win10/app/package.appxmanifest @@ -20,7 +20,7 @@ - + From 8d5c5daaaf1c23b677416113e354e046bbacd6df Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Thu, 23 Jun 2016 23:22:46 -0700 Subject: [PATCH 19/42] added streaming page --- docs/device.md | 14 +++++++++----- docs/streaming.md | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 docs/streaming.md diff --git a/docs/device.md b/docs/device.md index 15f5d1ae..b722d430 100644 --- a/docs/device.md +++ b/docs/device.md @@ -23,13 +23,13 @@ When you have downloaded and run your code onto your micro:bit, press Button R t ### USB connection -When you plug in your micro:bit, it should appear as MICROBIT. +When you plug in your micro:bit, it should appear as ``MICROBIT``. If you accidentally hold down the reset button as you’re plugging in your micro:bit, -the micro:bit will appear as a MAINTENANCE drive instead of MICROBIT. This is known as maintenance mode.** +the micro:bit will appear as a MAINTENANCE drive instead of ``MICROBIT``. This is known as maintenance mode.** -To continue programming your micro:bit YOU MUST unplug your USB and reconnect it. Check that the drive now shows as MICROBIT. +To continue programming your micro:bit YOU MUST unplug your USB and reconnect it. Check that the drive now shows as ``MICROBIT``. -**Use with caution. If you click on the drive while it shows as MAINTENANCE, +**Use with caution. If you click on the drive while it shows as ``MAINTENANCE``, you can see which version of firmware you have running on your micro:bit. Firmware on your micro:bit should be up-to-date already. You can find the version of firmware in the 'version.txt' file on the micro:bit. Further information on the firmware can be found here: @@ -55,6 +55,10 @@ The pins can be a form of input or output. There are labels for the input/output pins P0, P1, P2, which you can attach external sensors to such as thermometers or moisture detectors. You can read more about large and small pins [here](/device/pins). +### Light level + +The screen can also be used a light level sensor (it's a really cool trick). + ### How do I connect the micro:bit to my computer? Your micro:bit can be connected to your computer via a micro USB cable. @@ -73,7 +77,7 @@ You can attach an external device such as a motor to these and power it using th ### Serial Communication -The BBC micro:bit can send an receive data via [serial communication](/device/serial). The serial data can be transfered via USB or BlE. +The BBC micro:bit can send an receive data via [serial communication](/device/serial). The serial data can be transfered via USB or BLE. ### Bluetooth Low Energy (BLE) Antenna diff --git a/docs/streaming.md b/docs/streaming.md new file mode 100644 index 00000000..c70980fd --- /dev/null +++ b/docs/streaming.md @@ -0,0 +1,32 @@ +# Streaming + +This page describes how to stream data from the micro:bit to the editor or even to the cloud. + +## Before starting... + +Make sure you follow the instructions on [how to setup a serial connection](/device/serial) with the micro:bit. + +## A typical scenario + +A common scenario is to chart some sensor data, such as the acceleration, and analyse it in the editor. +For example, run this code on your micro:bit. + +```blocks +basic.forever(() => { + led.plotBarGraph(input.acceleration(Dimension.X), 0); +}); +``` + +If your serial connection is working, you will start to see a chart representing that acceleration ``x`` value read from the micro:bit. +Each time ``led.plotBarGraph`` is called, the value is also written to the serial output. The log view automatically detects +that there is a data stream and displays a graph. + +## Local download + +The log view will automatically start to collect and organize the data it detects. Simply click on the log view to open the various options +to export the data. The simplest option is to download the data as a **CSV file**. This file can easily be opened in programs like Office Excel. + +## Cloud upload + +In the data export dialog, there is another option to upload the data to the cloud. This allows to upload small amounts of data +without any kind setup. The data can be accessed via web services or directly from Office Excel. \ No newline at end of file From 205a486e58eb5bd00a2b360bf32f7962d570b6ae Mon Sep 17 00:00:00 2001 From: Martin Woolley Date: Fri, 24 Jun 2016 07:28:23 +0100 Subject: [PATCH 20/42] Bump pxt-core to 0.2.179 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b26b229b..5b954f27 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,6 @@ "typescript": "^1.8.7" }, "dependencies": { - "pxt-core": "0.2.187" + "pxt-core": "0.2.179" } } From 727490668c1d8393fd2bdfe9b7c993f368375686 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Thu, 23 Jun 2016 23:52:24 -0700 Subject: [PATCH 21/42] splitting the getting started page --- docs/getting-started.md | 469 +------------------- docs/getting-started/buttons.md | 79 ++++ docs/getting-started/coin-flipper.md | 76 ++++ docs/getting-started/rock-paper-scissors.md | 206 +++++++++ docs/getting-started/screen.md | 96 ++++ docs/getting-started/shake.md | 22 + 6 files changed, 483 insertions(+), 465 deletions(-) create mode 100644 docs/getting-started/buttons.md create mode 100644 docs/getting-started/coin-flipper.md create mode 100644 docs/getting-started/rock-paper-scissors.md create mode 100644 docs/getting-started/screen.md create mode 100644 docs/getting-started/shake.md diff --git a/docs/getting-started.md b/docs/getting-started.md index c7438317..78556e4e 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -9,8 +9,6 @@ to make real programs that work! ## ~ -### Happy face - Use the **Basic** drawer in the editor (to the left) to drag out and arrange three blocks (two `show leds` and one `forever` block) to create this program: @@ -34,470 +32,11 @@ basic.forever(() => { }); ``` -When you run this program (click the **Play** button) you will see a smiley face, then a blank +When this program runs, you will see a smiley face, then a blank screen, then a smiley again -- it never stops! (That's because of the ``forever`` block.) -Click **Compile** to move your program to the BBC micro:bit! +Click **Compile** to move your program to the BBC micro:bit! +Make sure to follow the instructions. -### Happy unhappy face - -Draw an unhappy face instead of the blank screen. Click on the dots -in the second ``show leds`` block until it matches the blocks below. -Now you have an **animation** (cartoon) that shows a happy face, -then an unhappy one, then a happy one again, forever (or until -you turn off your micro:bit)! - -```blocks -basic.forever(() => { - basic.showLeds(` - . . . . . - . # . # . - . . . . . - # . . . # - . # # # . - `) - basic.showLeds(` - . . . . . - . # . # . - . . . . . - . # # # . - # . . . # - `) -}); -``` -Click **Compile** to move your program to the BBC micro:bit! - -### Your turn! - -Pile up more ``show leds`` blocks to create an animation! Create an -animation with at least 5 pictures. What does this animation show? - -```blocks -basic.forever(() => { - basic.showLeds(` - . . . . . - . # . # . - . . . . . - # . . . # - . # # # . - `) - basic.showLeds(` - . . . . . - . # . # . - . . . . . - # # # # # - . . . . . - `) - basic.showLeds(` - . . . . . - . # . # . - . . . . . - . # # # . - # . . . # - `) - basic.showLeds(` - . . . . . - . # . # . - . . . . . - # # # # # - . . . # # - `) - basic.showLeds(` - . . . . . - # . # . . - . . . . . - # . . . # - . # # # . - `) - basic.showLeds(` - . . . . . - . . # . # - . . . . . - # . . . # - . # # # . - `) -}); -``` -Click **Compile** to move your program to the BBC micro:bit! - -#### ~hint - -You can find the ``show leds`` block in the **Basic** part of the editor. - -#### ~ - -### Button A and button B - -This program will show the word **ANTEATER** on the LED -screen when you press button `A`. - -```blocks -input.onButtonPressed(Button.A, () => { - basic.showString("ANTEATER"); -}); -``` - -#### ~hint - -The ``showString`` block can show letters, numbers, and punctuation -on the micro:bit screen. - -#### ~ - -Now try to unscramble these blocks in the editor so that the micro:bit -shows **BANANA** when you press button `B`. - -```shuffle -input.onButtonPressed(Button.B, () => { - basic.showString("BANANA"); -}); -``` -#### ~hint - -You can find the letter `B` by clicking the letter `A` on the -``onButtonPressed`` block. - -#### ~ - -Click **Compile** to move your program to the BBC micro:bit! - -#### Your turn! - -Can you combine these blocks so your program shows your real name -instead of **ANTEATER** when you press `A`, but _your secret agent -name_ instead of **BANANA** when you press `B`? - -### Shake - -You can find when someone is shaking the BBC micro:bit by checking its -**accelerometer** (it finds whether the micro:bit is speeding up or -slowing down). - -Unscramble these blocks in the editor to show a frownie when someone -shakes the micro:bit. (Ouch!) - -```shuffle -input.onGesture(Gesture.Shake, () => { - basic.showLeds(` -. . . . . -. # . # . -. . . . . -. # # # . -# . . . #`); -}); -``` -Click **Compile** to move your program to the BBC micro:bit! - -### Pins - -You can also use the pins as buttons. (The pins are the holes in the -metal stripe at the bottom of the micro:bit board.) For example, hold -the ``GND`` button with one hand and touch the ``0`` pin (called -``P0``) with your other hand to tell the micro:bit you're pressing it. - -Unscramble the blocks in the editor to show a heart when you touch -pin ``P0``. - -```shuffle -input.onPinPressed(TouchPin.P0, () => { - basic.showLeds(` -. # . # . -# . # . # -# . . . # -. # . # . -. . # . .`); -}); -``` -Click **Compile** to move your program to the BBC micro:bit! - -## ~hint - -Try this experiment: find a friend and hold hands. Touch the ``GND`` -pin while your friend presses the ``P0`` pin. You should see the -heart! The electric current is going through your bodies and across -your handshake to make it happen! - -## ~ - -## The amazing coin flipper - -### ~avatar avatar - -Are you trying to choose whether to play soccer or go to the movies -instead, or which toppings to have on your pizza? Build a coin -flipping machine with the BBC micro:bit to choose for you! - -### ~ - -Here are the blocks to make your coin flipper. When you press button -`B`, the coin flipper will show either `H` for heads or `T` for tails -on the LED screen. - -```blocks -input.onButtonPressed(Button.B, () => { - if (Math.randomBoolean()) { - basic.showString("H"); - } else { - basic.showString("T"); - } -}); -``` -### ~hint - -The ``pick random true or false`` block randomly tells the ``if`` -block `true` or `false`. If the ``pick`` block picked `true`, the -``if`` block shows the letter `H`. Otherwise, it shows the letter `T`. - -That's it! - -### ~ - -### Keeping score - -#### ~avatar - -To keep track out of how many guesses you've won, -add these blocks to your coin flipper: - -#### ~ - -```blocks -input.onButtonPressed(Button.A, () => { - game.addScore(1); -}); -input.onButtonPressed(Button.AB, () => { - basic.showNumber(game.score()); -}); -``` - -These blocks mean that if you press button `A`, you will add `1` to -your score, and if you press `A` and `B` together, the micro:bit will -show your score. - -When you're done, your coin flipping program should look like this: - -```blocks -input.onButtonPressed(Button.B, () => { - if (Math.randomBoolean()) { - basic.showString("H"); - } else { - basic.showString("T"); - } -}); -input.onButtonPressed(Button.A, () => { - game.addScore(1); -}); -input.onButtonPressed(Button.AB, () => { - basic.showNumber(game.score()); -}); -``` - -Flip until your thumbs get tired! - -## Let's play Rock Paper Scissors! - -### ~avatar avatar - -Build a Rock Paper Scissors game with the BBC micro:bit! You can play -the game with a friend who has it on a micro:bit. You can also play -it with friends who are just using their hands. (The game is built -like a coin flipper, but with three choices instead of two.) - -### ~ - -## Step 1: Getting started - -We want the micro:bit to choose rock, paper, or scissors when you -shake it. Try creating an ``on shake`` block so when you shake the -micro:bit, it will run part of a program. - -Clear up the blocks and add the blocks below. - -```blocks -input.onGesture(Gesture.Shake, () => { - -}) -``` - -Next, when you shake the micro:bit, it should pick a random number from `0` to `2` -and store it in the variable `item`. - -Add a ``set`` block with a variable. Then add a ``pick random`` block, -and store the random number in the variable, -like this: - -```blocks -input.onGesture(Gesture.Shake, () => { - let item = Math.random(3) -}) - -``` - -### ~hint -No one can predict random numbers. That's what makes them great for Rock Paper Scissors! -### ~ - -Each possible number these blocks can make (`0`, `1`, or `2`) means a different picture. -We will show the right picture for that number on the LED screen. - - -## Step 2: Picking paper - -Put an ``if`` block after the ``let`` block that checks whether -`item` is `0`. Make sure the ``if`` block has an ``else if`` part -and an ``else`` part. - -Next, add a ``show leds`` block that shows a -picture of a piece of paper: - -```blocks -input.onGesture(Gesture.Shake, () => { - let item = Math.random(3) - if (item == 0) { - basic.showLeds(` - # # # # # - # . . . # - # . . . # - # . . . # - # # # # # - `) - } else if (false) { - - } else { - - } -}) -``` - -## Step 3: A random rock - -Now we are going to add a new picture for the micro:bit to show -when another random number comes up. - -Make the ``else if`` part check if the variable `item` is `1`. -Then add a ``show leds`` block with a picture of a rock. - -```blocks -input.onGesture(Gesture.Shake, () => { - let item = Math.random(3) - if (item == 0) { - basic.showLeds(` - # # # # # - # . . . # - # . . . # - # . . . # - # # # # # - `) - } else if (item == 1) { - basic.showLeds(` - . . . . . - . # # # . - . # # # . - . # # # . - . . . . . - `) - } else { - - } -}) -``` - -## Step 4: Suddenly scissors - -Add a ``show leds`` block with a picture of scissors to the ``else`` part: - -```blocks -input.onGesture(Gesture.Shake, () => { - let item = Math.random(3) - if (item == 0) { - basic.showLeds(` - # # # # # - # . . . # - # . . . # - # . . . # - # # # # # - `) - - } else if (item == 1) { - basic.showLeds(` - . . . . . - . # # # . - . # # # . - . # # # . - . . . . . - `) - } else { - basic.showLeds(` - # # . . # - # # . # . - . . # . . - # # . # . - # # . . # - `) - } -}) - -``` - -### ~hint - -You don't need to check if `item` is `2` because `2` is the only number left out of `0`, `1`, and `2`. -That's why you can use an ``else`` instead of an ``else if``. - -### ~ - -Your game is ready! - -Click **Compile** to move your program to the BBC micro:bit! - -Have fun! - -## Step 5: Are you the greatest? - -Here is a way you can make your Rock Paper Scissors game better. -When button ``A`` is pressed, -the micro:bit will add `1` to your score. - -Open the ``Game`` drawer, and then add the block ``change score by 1`` to your program, -like this: - -```blocks -input.onButtonPressed(Button.A, () => { - game.addScore(1) -}) - -``` - -## Step 6: Prove you're the greatest! - -After your micro:bit can add `1` to the score, show how many wins you have. - -```blocks -input.onButtonPressed(Button.A, () => { - game.addScore(1) - basic.showString("WINS:") - basic.showNumber(game.score()) -}) -``` -## Step 7: Staying honest - -Success! Your micro:bit can track wins! -But what about losses? -Use the ``Game`` drawer to subtract `1` from your score when you press button `B`. - -Here are all the blocks you will need: - -```shuffle -input.onButtonPressed(Button.B, () => { - game.addScore(-1) - basic.showString("LOSSES:") - basic.showNumber(game.score()) -}) -``` -Click **Compile** to move your program to the BBC micro:bit! - - -# Want to do more? - -There are [10 great projects](/projects) waiting for you. +## [NEXT: THE SCREEN](/getting-started/screen) \ No newline at end of file diff --git a/docs/getting-started/buttons.md b/docs/getting-started/buttons.md new file mode 100644 index 00000000..492cfd45 --- /dev/null +++ b/docs/getting-started/buttons.md @@ -0,0 +1,79 @@ +# Button A and button B + +### ~avatar avatar + +Buttons are great to build games! + +### ~ + +This program will show the word **ANTEATER** on the LED +screen when you press button `A`. + +```blocks +input.onButtonPressed(Button.A, () => { + basic.showString("ANTEATER"); +}); +``` + +#### ~hint + +The ``showString`` block can show letters, numbers, and punctuation +on the micro:bit screen. + +#### ~ + +Now try to unscramble these blocks in the editor so that the micro:bit +shows **BANANA** when you press button `B`. + +```shuffle +input.onButtonPressed(Button.B, () => { + basic.showString("BANANA"); +}); +``` +#### ~hint + +You can find the letter `B` by clicking the letter `A` on the +``onButtonPressed`` block. + +#### ~ + +Click **Compile** to move your program to the BBC micro:bit! + +#### Your turn! + +Can you combine these blocks so your program shows your real name +instead of **ANTEATER** when you press `A`, but _your secret agent +name_ instead of **BANANA** when you press `B`? + +### Pins + +You can also use the pins as buttons. (The pins are the holes in the +metal stripe at the bottom of the micro:bit board.) For example, hold +the ``GND`` button with one hand and touch the ``0`` pin (called +``P0``) with your other hand to tell the micro:bit you're pressing it. + +Unscramble the blocks in the editor to show a heart when you touch +pin ``P0``. + +```shuffle +input.onPinPressed(TouchPin.P0, () => { + basic.showLeds(` +. # . # . +# . # . # +# . . . # +. # . # . +. . # . .`); +}); +``` +Click **Compile** to move your program to the BBC micro:bit! + +## ~hint + +Try this experiment: find a friend and hold hands. Touch the ``GND`` +pin while your friend presses the ``P0`` pin. You should see the +heart! The electric current is going through your bodies and across +your handshake to make it happen! + +## ~ + +## [NEXT: SHAKE](/getting-started/shake) \ No newline at end of file diff --git a/docs/getting-started/coin-flipper.md b/docs/getting-started/coin-flipper.md new file mode 100644 index 00000000..32bea0ba --- /dev/null +++ b/docs/getting-started/coin-flipper.md @@ -0,0 +1,76 @@ +# The amazing coin flipper + +### ~avatar avatar + +Are you trying to choose whether to play soccer or go to the movies +instead, or which toppings to have on your pizza? Build a coin +flipping machine with the BBC micro:bit to choose for you! + +### ~ + +Here are the blocks to make your coin flipper. When you press button +`B`, the coin flipper will show either `H` for heads or `T` for tails +on the LED screen. + +```blocks +input.onButtonPressed(Button.B, () => { + if (Math.randomBoolean()) { + basic.showString("H"); + } else { + basic.showString("T"); + } +}); +``` +### ~hint + +The ``pick random true or false`` block randomly tells the ``if`` +block `true` or `false`. If the ``pick`` block picked `true`, the +``if`` block shows the letter `H`. Otherwise, it shows the letter `T`. + +That's it! + +### ~ + +### Keeping score + +#### ~avatar + +To keep track out of how many guesses you've won, +add these blocks to your coin flipper: + +#### ~ + +```blocks +input.onButtonPressed(Button.A, () => { + game.addScore(1); +}); +input.onButtonPressed(Button.AB, () => { + basic.showNumber(game.score()); +}); +``` + +These blocks mean that if you press button `A`, you will add `1` to +your score, and if you press `A` and `B` together, the micro:bit will +show your score. + +When you're done, your coin flipping program should look like this: + +```blocks +input.onButtonPressed(Button.B, () => { + if (Math.randomBoolean()) { + basic.showString("H"); + } else { + basic.showString("T"); + } +}); +input.onButtonPressed(Button.A, () => { + game.addScore(1); +}); +input.onButtonPressed(Button.AB, () => { + basic.showNumber(game.score()); +}); +``` + +Flip until your thumbs get tired! + +## [NEXT: ROCK PAPER SCISSORS](/getting-started/rock-paper-scissors) diff --git a/docs/getting-started/rock-paper-scissors.md b/docs/getting-started/rock-paper-scissors.md new file mode 100644 index 00000000..1f7fdcec --- /dev/null +++ b/docs/getting-started/rock-paper-scissors.md @@ -0,0 +1,206 @@ +# Rock Paper Scissors + +### ~avatar avatar + +Build a Rock Paper Scissors game with the BBC micro:bit! You can play +the game with a friend who has it on a micro:bit. You can also play +it with friends who are just using their hands. (The game is built +like a coin flipper, but with three choices instead of two.) + +### ~ + +## Step 1: Getting started + +We want the micro:bit to choose rock, paper, or scissors when you +shake it. Try creating an ``on shake`` block so when you shake the +micro:bit, it will run part of a program. + +Clear up the blocks and add the blocks below. + +```blocks +input.onGesture(Gesture.Shake, () => { + +}) +``` + +Next, when you shake the micro:bit, it should pick a random number from `0` to `2` +and store it in the variable `item`. + +Add a ``set`` block with a variable. Then add a ``pick random`` block, +and store the random number in the variable, +like this: + +```blocks +input.onGesture(Gesture.Shake, () => { + let item = Math.random(3) +}) + +``` + +### ~hint +No one can predict random numbers. That's what makes them great for Rock Paper Scissors! +### ~ + +Each possible number these blocks can make (`0`, `1`, or `2`) means a different picture. +We will show the right picture for that number on the LED screen. + + +## Step 2: Picking paper + +Put an ``if`` block after the ``let`` block that checks whether +`item` is `0`. Make sure the ``if`` block has an ``else if`` part +and an ``else`` part. + +Next, add a ``show leds`` block that shows a +picture of a piece of paper: + +```blocks +input.onGesture(Gesture.Shake, () => { + let item = Math.random(3) + if (item == 0) { + basic.showLeds(` + # # # # # + # . . . # + # . . . # + # . . . # + # # # # # + `) + } else if (false) { + + } else { + + } +}) +``` + +## Step 3: A random rock + +Now we are going to add a new picture for the micro:bit to show +when another random number comes up. + +Make the ``else if`` part check if the variable `item` is `1`. +Then add a ``show leds`` block with a picture of a rock. + +```blocks +input.onGesture(Gesture.Shake, () => { + let item = Math.random(3) + if (item == 0) { + basic.showLeds(` + # # # # # + # . . . # + # . . . # + # . . . # + # # # # # + `) + } else if (item == 1) { + basic.showLeds(` + . . . . . + . # # # . + . # # # . + . # # # . + . . . . . + `) + } else { + + } +}) +``` + +## Step 4: Suddenly scissors + +Add a ``show leds`` block with a picture of scissors to the ``else`` part: + +```blocks +input.onGesture(Gesture.Shake, () => { + let item = Math.random(3) + if (item == 0) { + basic.showLeds(` + # # # # # + # . . . # + # . . . # + # . . . # + # # # # # + `) + + } else if (item == 1) { + basic.showLeds(` + . . . . . + . # # # . + . # # # . + . # # # . + . . . . . + `) + } else { + basic.showLeds(` + # # . . # + # # . # . + . . # . . + # # . # . + # # . . # + `) + } +}) + +``` + +### ~hint + +You don't need to check if `item` is `2` because `2` is the only number left out of `0`, `1`, and `2`. +That's why you can use an ``else`` instead of an ``else if``. + +### ~ + +Your game is ready! + +Click **Compile** to move your program to the BBC micro:bit! + +Have fun! + +## Step 5: Are you the greatest? + +Here is a way you can make your Rock Paper Scissors game better. +When button ``A`` is pressed, +the micro:bit will add `1` to your score. + +Open the ``Game`` drawer, and then add the block ``change score by 1`` to your program, +like this: + +```blocks +input.onButtonPressed(Button.A, () => { + game.addScore(1) +}) + +``` + +## Step 6: Prove you're the greatest! + +After your micro:bit can add `1` to the score, show how many wins you have. + +```blocks +input.onButtonPressed(Button.A, () => { + game.addScore(1) + basic.showString("WINS:") + basic.showNumber(game.score()) +}) +``` +## Step 7: Staying honest + +Success! Your micro:bit can track wins! +But what about losses? +Use the ``Game`` drawer to subtract `1` from your score when you press button `B`. + +Here are all the blocks you will need: + +```shuffle +input.onButtonPressed(Button.B, () => { + game.addScore(-1) + basic.showString("LOSSES:") + basic.showNumber(game.score()) +}) +``` +Click **Compile** to move your program to the BBC micro:bit! + + +# Want to do more? + +There are [10 great projects](/projects) waiting for you. diff --git a/docs/getting-started/screen.md b/docs/getting-started/screen.md new file mode 100644 index 00000000..64e7c64a --- /dev/null +++ b/docs/getting-started/screen.md @@ -0,0 +1,96 @@ +# Screen + +### ~avatar avatar + +There are 25 bright LEDs on the micro:bit screen. Let's use them to create some cool animations! + +### ~ + +### Happy unhappy face + +Draw an unhappy face instead of the blank screen. Click on the dots +in the second ``show leds`` block until it matches the blocks below. +Now you have an **animation** (cartoon) that shows a happy face, +then an unhappy one, then a happy one again, forever (or until +you turn off your micro:bit)! + +```blocks +basic.forever(() => { + basic.showLeds(` + . . . . . + . # . # . + . . . . . + # . . . # + . # # # . + `) + basic.showLeds(` + . . . . . + . # . # . + . . . . . + . # # # . + # . . . # + `) +}); +``` +Click **Compile** to move your program to the BBC micro:bit! + +### Your turn! + +Pile up more ``show leds`` blocks to create an animation! Create an +animation with at least 5 pictures. What does this animation show? + +```blocks +basic.forever(() => { + basic.showLeds(` + . . . . . + . # . # . + . . . . . + # . . . # + . # # # . + `) + basic.showLeds(` + . . . . . + . # . # . + . . . . . + # # # # # + . . . . . + `) + basic.showLeds(` + . . . . . + . # . # . + . . . . . + . # # # . + # . . . # + `) + basic.showLeds(` + . . . . . + . # . # . + . . . . . + # # # # # + . . . # # + `) + basic.showLeds(` + . . . . . + # . # . . + . . . . . + # . . . # + . # # # . + `) + basic.showLeds(` + . . . . . + . . # . # + . . . . . + # . . . # + . # # # . + `) +}); +``` +Click **Compile** to move your program to the BBC micro:bit! + +#### ~hint + +You can find the ``show leds`` block in the **Basic** part of the editor. + +#### ~ + +## [NEXT: BUTTONS](/getting-started/buttons) \ No newline at end of file diff --git a/docs/getting-started/shake.md b/docs/getting-started/shake.md new file mode 100644 index 00000000..5856cbc9 --- /dev/null +++ b/docs/getting-started/shake.md @@ -0,0 +1,22 @@ +# Shake + +You can find when someone is shaking the BBC micro:bit by checking its +**accelerometer** (it finds whether the micro:bit is speeding up or +slowing down). + +Unscramble these blocks in the editor to show a frownie when someone +shakes the micro:bit. (Ouch!) + +```shuffle +input.onGesture(Gesture.Shake, () => { + basic.showLeds(` +. . . . . +. # . # . +. . . . . +. # # # . +# . . . #`); +}); +``` +Click **Compile** to move your program to the BBC micro:bit! + +## [NEXT: COIN FLIPPER GAME](/getting-started/coin-flipper) From 1207a91a7fdc997e7ffe61b68d406181eae5b2ef Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Thu, 23 Jun 2016 23:53:58 -0700 Subject: [PATCH 22/42] 0.2.177 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b26b229b..653f0eb3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pxt-microbit", - "version": "0.2.176", + "version": "0.2.177", "description": "BBC micro:bit target for PXT", "keywords": [ "JavaScript", From 0834402b185ec97dec4182b95e89fd4f414ab215 Mon Sep 17 00:00:00 2001 From: Martin Woolley Date: Fri, 24 Jun 2016 07:59:08 +0100 Subject: [PATCH 23/42] Pairing documentation worj in progress. UART write block added --- docs/reference/bluetooth/bluetooth-pairing.md | 61 ++++++++++++++ libs/microbit-bluetooth/bluetooth.cpp | 80 ++++++++++--------- libs/microbit-bluetooth/enums.d.ts | 16 ++++ libs/microbit-bluetooth/shims.d.ts | 36 ++++----- 4 files changed, 133 insertions(+), 60 deletions(-) create mode 100755 docs/reference/bluetooth/bluetooth-pairing.md diff --git a/docs/reference/bluetooth/bluetooth-pairing.md b/docs/reference/bluetooth/bluetooth-pairing.md new file mode 100755 index 00000000..6c0d0368 --- /dev/null +++ b/docs/reference/bluetooth/bluetooth-pairing.md @@ -0,0 +1,61 @@ +# Bluetooth Pairing + +### ~hint +![](/static/bluetooth/Bluetooth_SIG.png) + +For another device like a smartphone to be able to connect to a micro:bit and uses its Bluetooth 'services' it must first be 'paired'. + +### ~ + +### What is 'pairing'? + +'Pairing' is what you have to do to have your micro:bit trust another device like a smartphone and similarly, have your smartphone trust your micro:bit. Why 'trust'? Well, pairing is all about security. You wouldn't usually want just anyone's smartphone connecting to your micro:bit and making it do things so by pairing *your* smartphone with *your* micro:bit you ensure that only your devices can talk to each other. + +Once you've paired your micro:bit with another device it also means that they are able to exchange information privately, without someone else being able to "see" the data they're exchanging over the air using Bluetooth. This is accomplished by data being [encrypted](https://en.wikipedia.org/wiki/Encryption) and pairing makes it possible for devices who trust each other to encrypt and decrypt data from each other. + +# How do you pair your micro:bit with another device? + +Making your micro:bit pair requires you to follow some simple steps which will be described shortly. What you do with the device you're pairing it to will vary slghtly depending on what that device is. We'll look at how it's done with common smartphones and tablets here too. + +To get your micro:bit ready for pairing do the following: + +1. Hold down buttons A and B on the front of your micro:bit together. The front is the side with two buttons and the LED display. Keep the two buttons held down. Don't let go of them yet! +2. While still holding down buttons A and B, press and then release the reset button on the back of the micro:bit. Keep holding down buttons A and B. +3. You should see "PAIRING MODE!" start to scroll across the micro:bit display. When you see this message start to appear you can release buttons A and B. +4. Eventually you'll see a strange pattern on your micro:bit display. This is like your micro:bit's signature. Other people's micro:bits will probably display a different pattern. + +Your micro:bit is now ready to be paired with the other device. Read the section below which relates to your 'other' device and watch the video too. + +### How do you pair your micro:bit with a Windows smartphone or tablet? + + +### How do you pair your micro:bit with an Android smartphone or tablet? + +Pairing an Android device with a micro:bit is done in the Settings screen. These are the steps to follow. If you have problems watch the video which may help. + +### How do you pair your micro:bit with an Apple iOS smartphone or tablet? + +### Video - How to pair a micro:bit with a Windows smartphone + +https://www.youtube.com/watch?v=AoW3mit7jIg + +### Video - How to pair a micro:bit with an Android smartphone or tablet + +https://www.youtube.com/watch?v=7hLBfdAGkZI + +### Video - How to pair a micro:bit with an Apple iOS smartphone or tablet + +https://www.youtube.com/watch?v=wslwyAMwMhs + + +### How often do I need to pair my micro:bit with my phone? + + + +### See also + +[Bluetooth SIG](https://www.bluetooth.com), [Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) + +```package +microbit-bluetooth +``` \ No newline at end of file diff --git a/libs/microbit-bluetooth/bluetooth.cpp b/libs/microbit-bluetooth/bluetooth.cpp index d9c89d00..23462190 100644 --- a/libs/microbit-bluetooth/bluetooth.cpp +++ b/libs/microbit-bluetooth/bluetooth.cpp @@ -5,6 +5,22 @@ MicroBitUARTService *uart; using namespace pxt; +enum Delimiters { + //% block="new line" + NewLine = 1, + //% block="," + Comma = 2, + //% block="$" + Dollar = 3, + //% block=":" + Colon = 4, + //% block="." + Fullstop = 5, + //% block="#" + Hash = 6, +}; + + /** * Support for additional Bluetooth services. */ @@ -63,8 +79,30 @@ namespace bluetooth { void startButtonService() { new MicroBitButtonService(*uBit.ble); } + + /** + * Starts the Bluetooth UART service + */ + //% help=bluetooth/start-uart-service + //% blockId=bluetooth_start_uart_service block="bluetooth uart service" blockGap=8 + + void startUartService() { + // 61 octet buffer size is 3 x (MTU - 3) + 1 + // MTU on nRF51822 is 23 octets. 3 are used by Attribute Protocol header data leaving 20 octets for payload + // So we allow a RX buffer that can contain 3 x max length messages plus one octet for a terminator character + uart = new MicroBitUARTService(*uBit.ble, 61, 60); + } - /** + /** + * Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device. + */ + //% help=bluetooth/uart-write + //% blockId=bluetooth_uart_write block="bluetooth|uart|write %data" blockGap=8 + void uartWrite(StringData *data) { + uart->send(ManagedString(data)); + } + + /** * Register code to run when the micro:bit is connected to over Bluetooth * @param body Code to run when a Bluetooth connection is established */ @@ -83,40 +121,6 @@ namespace bluetooth { void onBluetoothDisconnected(Action body) { registerWithDal(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_DISCONNECTED, body); } - - /** - * Starts the Bluetooth UART service - */ - //% help=bluetooth/start-uart-service - //% blockId=bluetooth_start_uart_service block="bluetooth|uart|service" blockGap=8 - - void startUartService() { - // 61 octet buffer size is 3 x (MTU - 3) + 1 - // MTU on nRF51822 is 23 octets. 3 are used by Attribute Protocol header data leaving 20 octets for payload - // So we allow a buffer that can contain 3 x max length messages plus one octet for a terminator character - uart = new MicroBitUARTService(*uBit.ble, 61, 60); - } - - - /** - * Reads the Bluetooth UART service buffer, returning when a specified 'end of message' delimiter character is encountered - * @param eom End of Message delimiter character - */ - //% help=bluetooth/uart-read - //% blockId=bluetooth_uart_read block="bluetooth|uart|read %eom" blockGap=8 - StringData* uartRead(char* eom) { - // temp hard coding of : as eom delimiter - char delim[6] = {':', 0}; - return uart->readUntil(delim).leakData(); - } - - /** - * Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device. - */ - //% help=bluetooth/uart-write - //% blockId=bluetooth_uart_write block="bluetooth|uart|write %data" blockGap=8 - void uartWrite(StringData* data) { - uart->send(ManagedString(data)); - } - -} + + +} \ No newline at end of file diff --git a/libs/microbit-bluetooth/enums.d.ts b/libs/microbit-bluetooth/enums.d.ts index c1770c7b..b1a4cfa4 100644 --- a/libs/microbit-bluetooth/enums.d.ts +++ b/libs/microbit-bluetooth/enums.d.ts @@ -1,4 +1,20 @@ // Auto-generated. Do not edit. + + + declare enum Delimiters { + //% block="new line" + NewLine = 1, + //% block="," + Comma = 2, + //% block="$" + Dollar = 3, + //% block=":" + Colon = 4, + //% block="." + Fullstop = 5, + //% block="#" + Hash = 6, + } declare namespace bluetooth { } diff --git a/libs/microbit-bluetooth/shims.d.ts b/libs/microbit-bluetooth/shims.d.ts index ae918647..4dba2871 100644 --- a/libs/microbit-bluetooth/shims.d.ts +++ b/libs/microbit-bluetooth/shims.d.ts @@ -49,6 +49,20 @@ declare namespace bluetooth { //% blockId=bluetooth_start_button_service block="bluetooth button service" blockGap=8 shim=bluetooth::startButtonService function startButtonService(): void; + /** + * Starts the Bluetooth UART service + */ + //% help=bluetooth/start-uart-service + //% blockId=bluetooth_start_uart_service block="bluetooth uart service" blockGap=8 shim=bluetooth::startUartService + function startUartService(): void; + + /** + * Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device. + */ + //% help=bluetooth/uart-write + //% blockId=bluetooth_uart_write block="bluetooth|uart|write %data" blockGap=8 shim=bluetooth::uartWrite + function uartWrite(data: string): void; + /** * Register code to run when the micro:bit is connected to over Bluetooth * @param body Code to run when a Bluetooth connection is established @@ -64,28 +78,6 @@ declare namespace bluetooth { //% help=bluetooth/on-bluetooth-disconnected //% blockId=bluetooth_on_disconnected block="on bluetooth disconnected" shim=bluetooth::onBluetoothDisconnected function onBluetoothDisconnected(body: () => void): void; - - /** - * Starts the Bluetooth UART service - */ - //% help=bluetooth/start-uart-service - //% blockId=bluetooth_start_uart_service block="bluetooth|uart|service" blockGap=8 shim=bluetooth::startUartService - function startUartService(): void; - - /** - * Reads the Bluetooth UART service buffer, returning when a specified 'end of message' delimiter character is encountered - * @param eom End of Message delimiter character - */ - //% help=bluetooth/uart-read - //% blockId=bluetooth_uart_read block="bluetooth|uart|read %eom" blockGap=8 shim=bluetooth::uartRead - function uartRead(eom: char*): string; - - /** - * Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device. - */ - //% help=bluetooth/uart-write - //% blockId=bluetooth_uart_write block="bluetooth|uart|write %data" blockGap=8 shim=bluetooth::uartWrite - function uartWrite(data: string): void; } // Auto-generated. Do not edit. Really. From ecc71a329538046f376b47fea33d7014cce39bc9 Mon Sep 17 00:00:00 2001 From: Martin Woolley Date: Fri, 24 Jun 2016 08:46:05 +0100 Subject: [PATCH 24/42] UART read block with string param unlimited length added --- libs/microbit-bluetooth/bluetooth.cpp | 11 ++++++++++- libs/microbit-bluetooth/bluetooth.ts | 12 ++++++++++++ libs/microbit-bluetooth/shims.d.ts | 9 ++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100755 libs/microbit-bluetooth/bluetooth.ts diff --git a/libs/microbit-bluetooth/bluetooth.cpp b/libs/microbit-bluetooth/bluetooth.cpp index 23462190..49d275bd 100644 --- a/libs/microbit-bluetooth/bluetooth.cpp +++ b/libs/microbit-bluetooth/bluetooth.cpp @@ -97,11 +97,20 @@ namespace bluetooth { * Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device. */ //% help=bluetooth/uart-write - //% blockId=bluetooth_uart_write block="bluetooth|uart|write %data" blockGap=8 + //% blockId=bluetooth_uart_write block="bluetooth uart write %data" blockGap=8 void uartWrite(StringData *data) { uart->send(ManagedString(data)); } + /** + * Reads from the Bluetooth UART service buffer, returning its contents when the specified delimiter character is encountered. + */ + //% help=bluetooth/uart-read + //% blockId=bluetooth_uart_read block="bluetooth uart read %del" blockGap=8 + StringData* uartRead(StringData *del) { + return uart->readUntil(ManagedString(del)).leakData(); + } + /** * Register code to run when the micro:bit is connected to over Bluetooth * @param body Code to run when a Bluetooth connection is established diff --git a/libs/microbit-bluetooth/bluetooth.ts b/libs/microbit-bluetooth/bluetooth.ts new file mode 100755 index 00000000..d7c46790 --- /dev/null +++ b/libs/microbit-bluetooth/bluetooth.ts @@ -0,0 +1,12 @@ +//% blockId="delimiter_conv" block="%del" +export function delimiters(del : Delimiters) : string { + switch(del) { + case Delimiters.NewLine: return "\n"; + case Delimiters.Comma: return ","; + case Delimiters.Dollar: return "$"; + case Delimiters.Colon: return ":"; + case Delimiters.Fullstop: return "."; + case Delimiters.Hash: return "#"; + default: return "\n"; + } +} \ No newline at end of file diff --git a/libs/microbit-bluetooth/shims.d.ts b/libs/microbit-bluetooth/shims.d.ts index 4dba2871..ff96c2b5 100644 --- a/libs/microbit-bluetooth/shims.d.ts +++ b/libs/microbit-bluetooth/shims.d.ts @@ -60,9 +60,16 @@ declare namespace bluetooth { * Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device. */ //% help=bluetooth/uart-write - //% blockId=bluetooth_uart_write block="bluetooth|uart|write %data" blockGap=8 shim=bluetooth::uartWrite + //% blockId=bluetooth_uart_write block="bluetooth uart write %data" blockGap=8 shim=bluetooth::uartWrite function uartWrite(data: string): void; + /** + * Reads from the Bluetooth UART service buffer, returning its contents when the specified delimiter character is encountered. + */ + //% help=bluetooth/uart-read + //% blockId=bluetooth_uart_read block="bluetooth uart read %del" blockGap=8 shim=bluetooth::uartRead + function uartRead(del: string): string; + /** * Register code to run when the micro:bit is connected to over Bluetooth * @param body Code to run when a Bluetooth connection is established From af5bf6e04e4c0ab1dd837ea9e35989910f7900e0 Mon Sep 17 00:00:00 2001 From: Martin Woolley Date: Fri, 24 Jun 2016 09:35:31 +0100 Subject: [PATCH 25/42] Documentation for the uartRead block --- docs/reference/bluetooth/uart-read.md | 53 +++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100755 docs/reference/bluetooth/uart-read.md diff --git a/docs/reference/bluetooth/uart-read.md b/docs/reference/bluetooth/uart-read.md new file mode 100755 index 00000000..a1afcbfd --- /dev/null +++ b/docs/reference/bluetooth/uart-read.md @@ -0,0 +1,53 @@ +# UART Read + +### ~hint +![](/static/bluetooth/Bluetooth_SIG.png) + +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. + +### ~ + +The [Bluetooth UART service](start-uart-service.md) allows another device such as a smartphone to exchange any data it wants to with the micro:bit, in small chunks. + +With the Bluetooth UART service running, this block allows a micro:bit to read data which has been received from a Bluetooth connected device, terminating reading and returning the value obtained as soon as a specified delimiter character is encountered. This means that connected devices can send data to the micro:bit and indicate that the complete message has been sent by appending the message with the delimiter character. + +```sig +bluetooth.uartRead(""); +``` + +### Example: Starting the Bluetooth UART service and then reading data received from another device which is terminated by ":" character and then displaying it + +```blocks +let uart_data: string = ""; +let connected = 0; +basic.showString("UART"); +bluetooth.startUartService(); +bluetooth.onBluetoothConnected(() => { + basic.showString("C"); + connected = 1; + while (connected == 1) { + uart_data = bluetooth.uartRead(":"); + basic.showString(uart_data); + } +}); +bluetooth.onBluetoothDisconnected(() => { + basic.showString("D"); +}); + +``` + +### Video - UART service guessing game + +https://www.youtube.com/watch?v=PgGeWddMAZ0 + +### Advanced + +For more advanced information on the micro:bit Bluetooth UART service including information on using a smartphone, see the [Lancaster University micro:bit runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/uart-service/) + +### See also + +[Bluetooth SIG](https://www.bluetooth.com), [Bluetooth on micro:bit resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html) + +```package +microbit-bluetooth +``` From b9a24a4542a4f68a427dc1d11ce4d4361c63e941 Mon Sep 17 00:00:00 2001 From: Martin Woolley Date: Fri, 24 Jun 2016 11:09:56 +0100 Subject: [PATCH 26/42] Documentation for pairing. Hint section updated to reference this. --- docs/reference/bluetooth/bluetooth-pairing.md | 60 +++++++++++++++---- .../bluetooth/on-bluetooth-connected.md | 2 +- .../bluetooth/on-bluetooth-disconnected.md | 2 +- .../bluetooth/start-accelerometer-service.md | 2 +- .../bluetooth/start-button-service.md | 2 +- .../bluetooth/start-io-pin-service.md | 2 +- docs/reference/bluetooth/start-led-service.md | 2 +- .../bluetooth/start-magnetometer-service.md | 2 +- .../bluetooth/start-temperature-service.md | 2 +- .../reference/bluetooth/start-uart-service.md | 2 +- docs/reference/bluetooth/uart-read.md | 2 +- docs/reference/bluetooth/uart-write.md | 2 +- 12 files changed, 60 insertions(+), 22 deletions(-) diff --git a/docs/reference/bluetooth/bluetooth-pairing.md b/docs/reference/bluetooth/bluetooth-pairing.md index 6c0d0368..d9677e60 100755 --- a/docs/reference/bluetooth/bluetooth-pairing.md +++ b/docs/reference/bluetooth/bluetooth-pairing.md @@ -3,7 +3,7 @@ ### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to be able to connect to a micro:bit and uses its Bluetooth 'services' it must first be 'paired'. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first be [paired with the micro:bit](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the micro:bit and exchange data relating to many of the micro:bit's features. ### ~ @@ -15,7 +15,7 @@ Once you've paired your micro:bit with another device it also means that they ar # How do you pair your micro:bit with another device? -Making your micro:bit pair requires you to follow some simple steps which will be described shortly. What you do with the device you're pairing it to will vary slghtly depending on what that device is. We'll look at how it's done with common smartphones and tablets here too. +Making your micro:bit pair requires you to follow some simple steps which will be described shortly. What you do with the device you're pairing it to will vary slightly depending on what that device is. We'll look at how it's done with common smartphones and tablets here too. To get your micro:bit ready for pairing do the following: @@ -28,29 +28,67 @@ Your micro:bit is now ready to be paired with the other device. Read the section ### How do you pair your micro:bit with a Windows smartphone or tablet? +1. Go into Settings +2. Select Bluetooth +3. Switch your micro:bit into 'pairing mode' using the steps above +4. Wait until 'PAIRING MODE!' has finished scrolling across the micro:bit display. You should see your micro:bit listed on your Windows smartphone with a name something like 'BBC micro:bit [zatig]'. Note that the 5 characters in brackets at the end will vary. +5. On the Windows smartphone, tap the micro:bit named in the device list. This will initiate the pairing process. +6. The micro:bit will display a left pointing arrow and the Windows smartphone will pop up a box into which you will be invited to enter a "pin" (Personal Identity Number). +7. Press button A on the micro:bit and watch carefully as the micro:bit displays a sequence of 6 random numbers. You may find it easier to write them down than to remember them. +8. Enter the 6 digits which the micro:bit displayed into your Windows smartphone in the pop-up box provided and then select "done". +9. If you entered the right number the micro:bit will display a tick / check mark. If you made a mistake it will display a cross or X and you should repeat the process to try again. + +#### Video +https://www.youtube.com/watch?v=AoW3mit7jIg + ### How do you pair your micro:bit with an Android smartphone or tablet? -Pairing an Android device with a micro:bit is done in the Settings screen. These are the steps to follow. If you have problems watch the video which may help. +1. Go into Settings +2. Select Bluetooth +3. Switch your micro:bit into 'pairing mode' using the steps above +4. Wait until 'PAIRING MODE!' has finished scrolling across the micro:bit display. You should see your micro:bit listed on your Android smartphone under the heading "Available devices" with a name something like 'BBC micro:bit [zatig]'. Note that the 5 characters in brackets at the end will vary. +5. On the Android smartphone, tap the micro:bit named in the Available devices list. This will initiate the pairing process. +6. The micro:bit will display a left pointing arrow and the Android smartphone will pop up a box into which you will be invited to enter a "pin" (Personal Identity Number). +7. Press button A on the micro:bit and watch carefully as the micro:bit displays a sequence of 6 random numbers. You may find it easier to write them down than to remember them. +8. Enter the 6 digits which the micro:bit displayed into your Android smartphone in the pop-up box provided and then select "done". +9. If you entered the right number the micro:bit will display a tick / check mark. If you made a mistake it will display a cross or X and you should repeat the process to try again. + +#### Video +https://www.youtube.com/watch?v=7hLBfdAGkZI ### How do you pair your micro:bit with an Apple iOS smartphone or tablet? -### Video - How to pair a micro:bit with a Windows smartphone +The steps to pair with an Apple iOS device are different to those followed for an Android or Windows device. To trigger pairing you need an application which will try to interact with your micro:bit and it's that interaction that triggers the iOS pairing process. There are many you could use but for the purposes of this documentation we'll suggest you install the "nRF Master Control Panel" (nRF MCP) application from Nordic Semiconductor. You'll find it in the Apple app store. It's a really useful Bluetooth application which will help you learn about Bluetooth as well as it having the ability to trigger the pairing process. After installing nRF MCP you should follow these steps to pair with your micro:bit: -https://www.youtube.com/watch?v=AoW3mit7jIg - -### Video - How to pair a micro:bit with an Android smartphone or tablet - -https://www.youtube.com/watch?v=7hLBfdAGkZI - -### Video - How to pair a micro:bit with an Apple iOS smartphone or tablet +1. Switch your micro:bit into 'pairing mode' using the steps above +2. Wait until 'PAIRING MODE!' has finished scrolling across the micro:bit display. +3. Launch the nRF MCP application. Your micro:bit should be listed and have a "Connect" button next to it. +4. Select "Connect" to connect your Apple device to the micro:bit. This will trigger the pairing process. +5. The micro:bit will display a left pointing arrow and the Apple device will pop up a box into which you will be invited to enter a "pin" (Personal Identity Number). +6. Press button A on the micro:bit and watch carefully as the micro:bit displays a sequence of 6 random numbers. You may find it easier to write them down than to remember them. +7. Enter the 6 digits which the micro:bit displayed into your Apple device in the pop-up box provided and then select "Pair". +8. If you entered the right number the micro:bit will display a tick / check mark. If you made a mistake it will display a cross or X and you should repeat the process to try again. +#### Video https://www.youtube.com/watch?v=wslwyAMwMhs ### How often do I need to pair my micro:bit with my phone? +You do *not* need to pair your micro:bit and smartphone or tablet every time you use them together. Pairing establishes 'trust' which will be retained until it is somehow lost. When another device wants to talk to your micro:bit it must connect to it but connecting and pairing are not the same thing. +There are circumstances which will result in pairing data being lost however and when this happens you will need to pair again. + +Currently, flashing new code via a USB cable causes the micro:bit's Bluetooth pairing data to be lost. Consequently, if you do flash new code to your micro:bit using a USB cable you will need to pair again. + +In contrast if you upload new code to your micro:bit over Bluetooth, using for example the Samsung micro:bit application for Android devices, you will not need to pair again. + +If you do find yourself needing to pair again you will first need to remove the pairing from your other device (i.e. smartphone or tablet): + +* On Android go into Settings/Bluetooth, select the 'cog' next to your micro:bit and then select FORGET +* On iOS go into Settings/Bluetooth, select your micro:bit and then select Forget This Device +* On a Windows device go into Settings/Bluetooth. Press and hold the micro:bit entry on the Windows device. A pop-up will appear with the option "delete". Select "delete" to unpair your micro:bit. ### See also diff --git a/docs/reference/bluetooth/on-bluetooth-connected.md b/docs/reference/bluetooth/on-bluetooth-connected.md index 990ca12a..8594d947 100755 --- a/docs/reference/bluetooth/on-bluetooth-connected.md +++ b/docs/reference/bluetooth/on-bluetooth-connected.md @@ -3,7 +3,7 @@ ### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first be [paired with the micro:bit](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the micro:bit and exchange data relating to many of the micro:bit's features. ### ~ diff --git a/docs/reference/bluetooth/on-bluetooth-disconnected.md b/docs/reference/bluetooth/on-bluetooth-disconnected.md index 3bfd3859..942f7efa 100755 --- a/docs/reference/bluetooth/on-bluetooth-disconnected.md +++ b/docs/reference/bluetooth/on-bluetooth-disconnected.md @@ -3,7 +3,7 @@ ### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first be [paired with the micro:bit](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the micro:bit and exchange data relating to many of the micro:bit's features. ### ~ diff --git a/docs/reference/bluetooth/start-accelerometer-service.md b/docs/reference/bluetooth/start-accelerometer-service.md index a96e9bcd..abb9e4b5 100755 --- a/docs/reference/bluetooth/start-accelerometer-service.md +++ b/docs/reference/bluetooth/start-accelerometer-service.md @@ -3,7 +3,7 @@ ### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first be [paired with the micro:bit](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the micro:bit and exchange data relating to many of the micro:bit's features. ### ~ diff --git a/docs/reference/bluetooth/start-button-service.md b/docs/reference/bluetooth/start-button-service.md index 64c9b625..1e8e1313 100755 --- a/docs/reference/bluetooth/start-button-service.md +++ b/docs/reference/bluetooth/start-button-service.md @@ -3,7 +3,7 @@ ### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first be [paired with the micro:bit](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the micro:bit and exchange data relating to many of the micro:bit's features. ### ~ diff --git a/docs/reference/bluetooth/start-io-pin-service.md b/docs/reference/bluetooth/start-io-pin-service.md index 77d349e1..48ffa914 100755 --- a/docs/reference/bluetooth/start-io-pin-service.md +++ b/docs/reference/bluetooth/start-io-pin-service.md @@ -3,7 +3,7 @@ ### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first be [paired with the micro:bit](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the micro:bit and exchange data relating to many of the micro:bit's features. ### ~ diff --git a/docs/reference/bluetooth/start-led-service.md b/docs/reference/bluetooth/start-led-service.md index b05098fd..3dc1c5ea 100755 --- a/docs/reference/bluetooth/start-led-service.md +++ b/docs/reference/bluetooth/start-led-service.md @@ -3,7 +3,7 @@ ### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first be [paired with the micro:bit](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the micro:bit and exchange data relating to many of the micro:bit's features. ### ~ diff --git a/docs/reference/bluetooth/start-magnetometer-service.md b/docs/reference/bluetooth/start-magnetometer-service.md index 8869a713..4dcab9d7 100755 --- a/docs/reference/bluetooth/start-magnetometer-service.md +++ b/docs/reference/bluetooth/start-magnetometer-service.md @@ -3,7 +3,7 @@ ### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first be [paired with the micro:bit](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the micro:bit and exchange data relating to many of the micro:bit's features. ### ~ diff --git a/docs/reference/bluetooth/start-temperature-service.md b/docs/reference/bluetooth/start-temperature-service.md index 4f695da6..0679fbb0 100755 --- a/docs/reference/bluetooth/start-temperature-service.md +++ b/docs/reference/bluetooth/start-temperature-service.md @@ -3,7 +3,7 @@ ### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first be [paired with the micro:bit](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the micro:bit and exchange data relating to many of the micro:bit's features. ### ~ diff --git a/docs/reference/bluetooth/start-uart-service.md b/docs/reference/bluetooth/start-uart-service.md index 6b8d5784..a74875a9 100755 --- a/docs/reference/bluetooth/start-uart-service.md +++ b/docs/reference/bluetooth/start-uart-service.md @@ -3,7 +3,7 @@ ### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first be [paired with the micro:bit](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the micro:bit and exchange data relating to many of the micro:bit's features. ### ~ diff --git a/docs/reference/bluetooth/uart-read.md b/docs/reference/bluetooth/uart-read.md index a1afcbfd..18c7d68c 100755 --- a/docs/reference/bluetooth/uart-read.md +++ b/docs/reference/bluetooth/uart-read.md @@ -3,7 +3,7 @@ ### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first be [paired with the micro:bit](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the micro:bit and exchange data relating to many of the micro:bit's features. ### ~ diff --git a/docs/reference/bluetooth/uart-write.md b/docs/reference/bluetooth/uart-write.md index 0f308b8e..34568c9f 100755 --- a/docs/reference/bluetooth/uart-write.md +++ b/docs/reference/bluetooth/uart-write.md @@ -3,7 +3,7 @@ ### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first connect to the micro:bit. +For another device like a smartphone to use any of the Bluetooth "services" which the micro:bit has, it must first be [paired with the micro:bit](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the micro:bit and exchange data relating to many of the micro:bit's features. ### ~ From 6cfe39dac36e199d712f8f2fb46309afeaeb7f6f Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 08:12:52 -0700 Subject: [PATCH 27/42] patching up bluetooth uart --- libs/microbit-bluetooth/bluetooth.cpp | 30 +++++++++++++++++++-------- libs/microbit-bluetooth/bluetooth.ts | 12 ----------- libs/microbit-bluetooth/shims.d.ts | 22 ++++++++++---------- package.json | 2 +- 4 files changed, 33 insertions(+), 33 deletions(-) delete mode 100755 libs/microbit-bluetooth/bluetooth.ts diff --git a/libs/microbit-bluetooth/bluetooth.cpp b/libs/microbit-bluetooth/bluetooth.cpp index 49d275bd..81585e9d 100644 --- a/libs/microbit-bluetooth/bluetooth.cpp +++ b/libs/microbit-bluetooth/bluetooth.cpp @@ -1,7 +1,6 @@ #include "pxt.h" #include "MESEvents.h" #include "MicroBitUARTService.h" -MicroBitUARTService *uart; using namespace pxt; @@ -26,6 +25,8 @@ enum Delimiters { */ //% color=#0082FB weight=20 namespace bluetooth { + MicroBitUARTService *uart = NULL; + /** * Starts the Bluetooth IO pin service. */ @@ -83,10 +84,10 @@ namespace bluetooth { /** * Starts the Bluetooth UART service */ - //% help=bluetooth/start-uart-service - //% blockId=bluetooth_start_uart_service block="bluetooth uart service" blockGap=8 - + // help=bluetooth/start-uart-service + // blockId=bluetooth_start_uart_service block="bluetooth uart service" blockGap=8 void startUartService() { + if (uart) return; // 61 octet buffer size is 3 x (MTU - 3) + 1 // MTU on nRF51822 is 23 octets. 3 are used by Attribute Protocol header data leaving 20 octets for payload // So we allow a RX buffer that can contain 3 x max length messages plus one octet for a terminator character @@ -99,24 +100,35 @@ namespace bluetooth { //% help=bluetooth/uart-write //% blockId=bluetooth_uart_write block="bluetooth uart write %data" blockGap=8 void uartWrite(StringData *data) { - uart->send(ManagedString(data)); + startUartService(); + uart->send(ManagedString(data)); } /** * Reads from the Bluetooth UART service buffer, returning its contents when the specified delimiter character is encountered. */ //% help=bluetooth/uart-read - //% blockId=bluetooth_uart_read block="bluetooth uart read %del" blockGap=8 + //% blockId=bluetooth_uart_read block="bluetooth uart read %del=bluetooth_uart_delimiter_conv" blockGap=8 StringData* uartRead(StringData *del) { + startUartService(); return uart->readUntil(ManagedString(del)).leakData(); } + /** + * Returns the delimiter corresponding string + */ + //% blockId="bluetooth_uart_delimiter_conv" block="%del" + //% weight=1 + StringData* delimiters(Delimiters del) { + ManagedString c("\n\n,$:.#"[max(0, min(6, (int)del))]); + return c.leakData(); + } /** * Register code to run when the micro:bit is connected to over Bluetooth * @param body Code to run when a Bluetooth connection is established */ - //% help=bluetooth/on-bluetooth-connected - //% blockId=bluetooth_on_connected block="on bluetooth connected" + //% help=bluetooth/on-bluetooth-connected weight=20 + //% blockId=bluetooth_on_connected block="on bluetooth connected" blockGap=8 void onBluetoothConnected(Action body) { registerWithDal(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_CONNECTED, body); } @@ -125,7 +137,7 @@ namespace bluetooth { * Register code to run when a bluetooth connection to the micro:bit is lost * @param body Code to run when a Bluetooth connection is lost */ - //% help=bluetooth/on-bluetooth-disconnected + //% help=bluetooth/on-bluetooth-disconnected weight=19 //% blockId=bluetooth_on_disconnected block="on bluetooth disconnected" void onBluetoothDisconnected(Action body) { registerWithDal(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_DISCONNECTED, body); diff --git a/libs/microbit-bluetooth/bluetooth.ts b/libs/microbit-bluetooth/bluetooth.ts deleted file mode 100755 index d7c46790..00000000 --- a/libs/microbit-bluetooth/bluetooth.ts +++ /dev/null @@ -1,12 +0,0 @@ -//% blockId="delimiter_conv" block="%del" -export function delimiters(del : Delimiters) : string { - switch(del) { - case Delimiters.NewLine: return "\n"; - case Delimiters.Comma: return ","; - case Delimiters.Dollar: return "$"; - case Delimiters.Colon: return ":"; - case Delimiters.Fullstop: return "."; - case Delimiters.Hash: return "#"; - default: return "\n"; - } -} \ No newline at end of file diff --git a/libs/microbit-bluetooth/shims.d.ts b/libs/microbit-bluetooth/shims.d.ts index ff96c2b5..0606d684 100644 --- a/libs/microbit-bluetooth/shims.d.ts +++ b/libs/microbit-bluetooth/shims.d.ts @@ -49,13 +49,6 @@ declare namespace bluetooth { //% blockId=bluetooth_start_button_service block="bluetooth button service" blockGap=8 shim=bluetooth::startButtonService function startButtonService(): void; - /** - * Starts the Bluetooth UART service - */ - //% help=bluetooth/start-uart-service - //% blockId=bluetooth_start_uart_service block="bluetooth uart service" blockGap=8 shim=bluetooth::startUartService - function startUartService(): void; - /** * Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device. */ @@ -67,22 +60,29 @@ declare namespace bluetooth { * Reads from the Bluetooth UART service buffer, returning its contents when the specified delimiter character is encountered. */ //% help=bluetooth/uart-read - //% blockId=bluetooth_uart_read block="bluetooth uart read %del" blockGap=8 shim=bluetooth::uartRead + //% blockId=bluetooth_uart_read block="bluetooth uart read %del=bluetooth_uart_delimiter_conv" blockGap=8 shim=bluetooth::uartRead function uartRead(del: string): string; + /** + * Returns the delimiter corresponding string + */ + //% blockId="bluetooth_uart_delimiter_conv" block="%del" + //% weight=1 shim=bluetooth::delimiters + function delimiters(del: Delimiters): string; + /** * Register code to run when the micro:bit is connected to over Bluetooth * @param body Code to run when a Bluetooth connection is established */ - //% help=bluetooth/on-bluetooth-connected - //% blockId=bluetooth_on_connected block="on bluetooth connected" shim=bluetooth::onBluetoothConnected + //% help=bluetooth/on-bluetooth-connected weight=20 + //% blockId=bluetooth_on_connected block="on bluetooth connected" blockGap=8 shim=bluetooth::onBluetoothConnected function onBluetoothConnected(body: () => void): void; /** * Register code to run when a bluetooth connection to the micro:bit is lost * @param body Code to run when a Bluetooth connection is lost */ - //% help=bluetooth/on-bluetooth-disconnected + //% help=bluetooth/on-bluetooth-disconnected weight=19 //% blockId=bluetooth_on_disconnected block="on bluetooth disconnected" shim=bluetooth::onBluetoothDisconnected function onBluetoothDisconnected(body: () => void): void; } diff --git a/package.json b/package.json index 88b72e6f..eeaa273c 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,6 @@ "typescript": "^1.8.7" }, "dependencies": { - "pxt-core": "0.2.179" + "pxt-core": "*" } } From 5dd37a14941243ce3bf218c35897d8f295816ac5 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 09:02:14 -0700 Subject: [PATCH 28/42] updated bluetooth docs page --- docs/reference/bluetooth.md | 16 +- .../_locales/microbit-bluetooth-strings.json | 264 ++++++++++++++++++ 2 files changed, 274 insertions(+), 6 deletions(-) create mode 100644 libs/microbit-bluetooth/_locales/microbit-bluetooth-strings.json diff --git a/docs/reference/bluetooth.md b/docs/reference/bluetooth.md index ef65f1a1..1961bbf5 100644 --- a/docs/reference/bluetooth.md +++ b/docs/reference/bluetooth.md @@ -1,18 +1,22 @@ # Bluetooth +Support for additional Bluetooth services. + ```cards -bluetooth.onBluetoothConnected(() => { - -}); -bluetooth.onBluetoothDisconnected(() => { - -}); bluetooth.startAccelerometerService(); bluetooth.startButtonService(); bluetooth.startIOPinService(); bluetooth.startLEDService(); bluetooth.startMagnetometerService(); bluetooth.startTemperatureService(); +bluetooth.uartRead(""); +bluetooth.uartWrite(""); +bluetooth.onBluetoothConnected(() => { + +}); +bluetooth.onBluetoothDisconnected(() => { + +}); ``` ```package diff --git a/libs/microbit-bluetooth/_locales/microbit-bluetooth-strings.json b/libs/microbit-bluetooth/_locales/microbit-bluetooth-strings.json new file mode 100644 index 00000000..c745fff9 --- /dev/null +++ b/libs/microbit-bluetooth/_locales/microbit-bluetooth-strings.json @@ -0,0 +1,264 @@ +{ + "Math.randomBoolean": "Generates a `true` or `false` value randomly, just like flipping a coin.", + "Math.randomBoolean|block": "pick random true or false", + "Math|block": "Math", + "String.fromCharCode": "Make a string from the given ASCII character code.", + "String.fromCharCode|block": "text from char code %code", + "String|block": "String", + "basic": "Provides access to basic micro:bit functionality.", + "basic.clearScreen": "Turn off all LEDs", + "basic.clearScreen|block": "clear screen", + "basic.forever": "Repeats the code forever in the background. On each iteration, allows other codes to run.", + "basic.forever|block": "forever", + "basic.pause": "Pause for the specified time in milliseconds", + "basic.pause|block": "pause (ms) %pause", + "basic.pause|param|ms": "how long to pause for, eg: 100, 200, 500, 1000, 2000", + "basic.plotLeds": "Draws an image on the LED screen.", + "basic.plotLeds|param|leds": "pattern of LEDs to turn on/off", + "basic.showAnimation": "Shows a sequence of LED screens as an animation.", + "basic.showAnimation|param|interval": "time in milliseconds between each redraw", + "basic.showAnimation|param|leds": "pattern of LEDs to turn on/off", + "basic.showLeds": "Draws an image on the LED screen.", + "basic.showLeds|block": "show leds", + "basic.showLeds|param|interval": "time in milliseconds to pause after drawing", + "basic.showLeds|param|leds": "the pattern of LED to turn on/off", + "basic.showNumber": "Scroll a number on the screen. If the number fits on the screen (i.e. is a single digit), do not scroll.", + "basic.showNumber|block": "show|number %number", + "basic.showNumber|param|interval": "speed of scroll; eg: 150, 100, 200, -100", + "basic.showString": "Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll.", + "basic.showString|block": "show|string %text", + "basic.showString|param|interval": "how fast to shift characters; eg: 150, 100, 200, -100", + "basic.showString|param|text": "the text to scroll on the screen, eg: \"Hello!\"", + "basic|block": "basic", + "bluetooth": "Support for additional Bluetooth services.", + "bluetooth.onBluetoothConnected": "Register code to run when the micro:bit is connected to over Bluetooth", + "bluetooth.onBluetoothConnected|block": "on bluetooth connected", + "bluetooth.onBluetoothConnected|param|body": "Code to run when a Bluetooth connection is established", + "bluetooth.onBluetoothDisconnected": "Register code to run when a bluetooth connection to the micro:bit is lost", + "bluetooth.onBluetoothDisconnected|block": "on bluetooth disconnected", + "bluetooth.onBluetoothDisconnected|param|body": "Code to run when a Bluetooth connection is lost", + "bluetooth.startAccelerometerService": "Starts the Bluetooth accelerometer service", + "bluetooth.startAccelerometerService|block": "bluetooth accelerometer service", + "bluetooth.startButtonService": "Starts the Bluetooth button service", + "bluetooth.startButtonService|block": "bluetooth button service", + "bluetooth.startIOPinService": "Starts the Bluetooth IO pin service.", + "bluetooth.startIOPinService|block": "bluetooth io pin service", + "bluetooth.startLEDService": "Starts the Bluetooth LED service", + "bluetooth.startLEDService|block": "bluetooth led service", + "bluetooth.startMagnetometerService": "Starts the Bluetooth magnetometer service", + "bluetooth.startMagnetometerService|block": "bluetooth magnetometer service", + "bluetooth.startTemperatureService": "Starts the Bluetooth temperature service", + "bluetooth.startTemperatureService|block": "bluetooth temperature service", + "bluetooth.uartRead": "Reads from the Bluetooth UART service buffer, returning its contents when the specified delimiter character is encountered.", + "bluetooth.uartRead|block": "bluetooth uart read %del=bluetooth_uart_delimiter_conv", + "bluetooth.uartWrite": "Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device.", + "bluetooth.uartWrite|block": "bluetooth uart write %data", + "bluetooth|block": "bluetooth", + "control": "Runtime and event utilities.", + "control.inBackground": "Schedules code that run in the background.", + "control.inBackground|block": "run in background", + "control.reset": "Resets the BBC micro:bit.", + "control.reset|block": "reset", + "control|block": "control", + "game": "A single-LED sprite game engine", + "game.addScore": "Adds points to the current score", + "game.addScore|block": "change score by|%points", + "game.addScore|param|points": "amount of points to change, eg: 1", + "game.gameOver": "Displays a game over animation.", + "game.gameOver|block": "game over", + "game.score": "Gets the current score", + "game.score|block": "score", + "game.setScore": "Sets the current score value", + "game.setScore|param|value": "TODO", + "game.startCountdown": "Starts a game countdown timer", + "game.startCountdown|block": "start countdown|(ms) %duration", + "game.startCountdown|param|ms": "countdown duration in milliseconds, eg: 10000", + "game|block": "game", + "images": "Creation, manipulation and display of LED images.", + "images.createBigImage": "Creates an image with 2 frames.", + "images.createBigImage|block": "create big image", + "images.createImage": "Creates an image that fits on the LED screen.", + "images.createImage|block": "create image", + "images|block": "images", + "input": "Events and data from sensors", + "input.acceleration": "Get the acceleration value in milli-gravitys (when the board is laying flat with the screen up, x=0, y=0 and z=-1024)", + "input.acceleration|block": "acceleration (mg)|%NAME", + "input.acceleration|param|dimension": "TODO", + "input.buttonIsPressed": "Get the button state (pressed or not) for ``A`` and ``B``.", + "input.buttonIsPressed|block": "button|%NAME|is pressed", + "input.calibrate": "Obsolete, compass calibration is automatic.", + "input.compassHeading": "Get the current compass compass heading in degrees.", + "input.compassHeading|block": "compass heading (°)", + "input.lightLevel": "Reads the light level applied to the LED screen in a range from ``0`` (dark) to ``255`` bright.", + "input.lightLevel|block": "light level", + "input.magneticForce": "Get the magnetic force value in ``micro-Teslas`` (``µT``). This function is not supported in the simulator.", + "input.magneticForce|block": "magnetic force (µT)|%NAME", + "input.magneticForce|param|dimension": "TODO", + "input.onButtonPressed": "Do something when a button (``A``, ``B`` or both ``A+B``) is pressed", + "input.onButtonPressed|block": "on button|%NAME|pressed", + "input.onButtonPressed|param|body": "TODO", + "input.onButtonPressed|param|button": "TODO", + "input.onGesture": "Attaches code to run when the screen is facing up.", + "input.onGesture|block": "on |%NAME", + "input.onGesture|param|body": "TODO", + "input.onLogoDown": "Attaches code to run when the logo is oriented downwards and the board is vertical.", + "input.onLogoDown|param|body": "TODO", + "input.onLogoUp": "Attaches code to run when the logo is oriented upwards and the board is vertical.", + "input.onLogoUp|param|body": "TODO", + "input.onPinPressed": "Do something when a pin(``P0``, ``P1`` or both ``P2``) is pressed.", + "input.onPinPressed|block": "on pin|%NAME|pressed", + "input.onPinPressed|param|body": "TODO", + "input.onPinPressed|param|name": "TODO", + "input.onScreenDown": "Attaches code to run when the screen is facing down.", + "input.onScreenDown|param|body": "TODO", + "input.onScreenUp": "Attaches code to run when the screen is facing up.", + "input.onScreenUp|param|body": "TODO", + "input.onShake": "Attaches code to run when the device is shaken.", + "input.onShake|param|body": "TODO", + "input.pinIsPressed": "Get the pin state (pressed or not). Requires to hold the ground to close the circuit.", + "input.pinIsPressed|block": "pin|%NAME|is pressed", + "input.pinIsPressed|param|name": "pin used to detect the touch", + "input.rotation": "The pitch of the device, rotation along the ``x-axis``, in degrees.", + "input.rotation|block": "rotation (°)|%NAME", + "input.rotation|param|kind": "TODO", + "input.runningTime": "Gets the number of milliseconds elapsed since power on.", + "input.runningTime|block": "running time (ms)", + "input.setAccelerometerRange": "Sets the accelerometer sample range in gravities.", + "input.setAccelerometerRange|block": "set accelerometer|range %range", + "input.setAccelerometerRange|param|range": "a value describe the maximum strengh of acceleration measured", + "input.temperature": "Gets the temperature in Celsius degrees (°C).", + "input.temperature|block": "temperature (°C)", + "input|block": "input", + "led": "Control of the LED screen.", + "led.brightness": "Get the screen brightness from 0 (off) to 255 (full bright).", + "led.brightness|block": "brightness", + "led.fadeIn": "Fades in the screen display.", + "led.fadeIn|param|ms": "TODO", + "led.fadeOut": "Fades out the screen brightness.", + "led.fadeOut|param|ms": "TODO", + "led.plot": "Turn on the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left.", + "led.plotAll": "Turns all LEDS on", + "led.plotBarGraph": "Displays a vertical bar graph based on the `value` and `high` value.\nIf `high` is 0, the chart gets adjusted automatically.", + "led.plotBarGraph|block": "plot bar graph of %value |up to %high", + "led.plotBarGraph|param|high": "maximum value. If 0, maximum value adjusted automatically, eg: 0", + "led.plotBarGraph|param|value": "current value to plot", + "led.plot|block": "plot|x %x|y %y", + "led.plot|param|x": "TODO", + "led.plot|param|y": "TODO", + "led.point": "Get the on/off state of the specified LED using x, y coordinates. (0,0) is upper left.", + "led.point|block": "point|x %x|y %y", + "led.point|param|x": "TODO", + "led.point|param|y": "TODO", + "led.screenshot": "Takes a screenshot of the LED screen and returns an image.", + "led.setBrightness": "Set the screen brightness from 0 (off) to 255 (full bright).", + "led.setBrightness|block": "set brightness %value", + "led.setBrightness|param|value": "the brightness value, eg:255, 127, 0", + "led.setDisplayMode": "Sets the display mode between black and white and greyscale for rendering LEDs.", + "led.setDisplayMode|param|mode": "TODO", + "led.stopAnimation": "Cancels the current animation and clears other pending animations.", + "led.stopAnimation|block": "stop animation", + "led.toggle": "Toggles a particular pixel", + "led.toggleAll": "Inverts the current LED display", + "led.toggle|param|x": "TODO", + "led.toggle|param|y": "TODO", + "led.unplot": "Turn off the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left.", + "led.unplot|block": "unplot|x %x|y %y", + "led.unplot|param|x": "TODO", + "led.unplot|param|y": "TODO", + "led|block": "led", + "music": "Generation of music tones through pin ``P0``.", + "music.beat": "Returns the duration of a beat in milli-seconds", + "music.beat|block": "%fraction|beat", + "music.changeTempoBy": "Change the tempo by the specified amount", + "music.changeTempoBy|block": "change tempo by (bpm)|%value", + "music.changeTempoBy|param|bpm": "The change in beats per minute to the tempo, eg: 20", + "music.noteFrequency": "Gets the frequency of a note.", + "music.noteFrequency|block": "%note", + "music.noteFrequency|param|name": "the note name", + "music.playTone": "Plays a tone through pin ``P0`` for the given duration.", + "music.playTone|block": "play|tone %note=device_note|for %duration=device_beat", + "music.playTone|param|frequency": "pitch of the tone to play in Hertz (Hz)", + "music.playTone|param|ms": "tone duration in milliseconds (ms)", + "music.rest": "Rests (plays nothing) for a specified time through pin ``P0``.", + "music.rest|block": "rest(ms)|%duration=device_beat", + "music.rest|param|ms": "rest duration in milliseconds (ms)", + "music.ringTone": "Plays a tone through pin ``P0``.", + "music.ringTone|block": "ring tone (Hz)|%note=device_note", + "music.ringTone|param|frequency": "pitch of the tone to play in Hertz (Hz)", + "music.setTempo": "Sets the tempo to the specified amount", + "music.setTempo|block": "set tempo to (bpm)|%value", + "music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120", + "music.tempo": "Returns the tempo in beats per minute. Tempo is the speed (bpm = beats per minute) at which notes play. The larger the tempo value, the faster the notes will play.", + "music.tempo|block": "tempo (bpm)", + "music|block": "music", + "pins": "Control currents in Pins for analog/digital signals, servos, i2c, ...", + "pins.analogPitch": "Emits a Pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.", + "pins.analogPitch|param|frequency": "TODO", + "pins.analogPitch|param|ms": "TODO", + "pins.analogReadPin": "Read the connector value as analog, that is, as a value comprised between 0 and 1023.", + "pins.analogReadPin|block": "analog read|pin %name", + "pins.analogReadPin|param|name": "pin to write to", + "pins.analogSetPeriod": "Configures the Pulse-width modulation (PWM) of the analog output to the given value in **microseconds** or `1/1000` milliseconds.\nIf this pin is not configured as an analog output (using `analog write pin`), the operation has no effect.", + "pins.analogSetPeriod|block": "analog set period|pin %pin|to (µs)%micros", + "pins.analogSetPeriod|param|micros": "period in micro seconds. eg:20000", + "pins.analogSetPeriod|param|name": "analog pin to set period to", + "pins.analogSetPitchPin": "Sets the pin used when using `pins->analog pitch`.", + "pins.analogSetPitchPin|param|name": "TODO", + "pins.analogWritePin": "Set the connector value as analog. Value must be comprised between 0 and 1023.", + "pins.analogWritePin|block": "analog write|pin %name|to %value", + "pins.analogWritePin|param|name": "pin name to write to", + "pins.analogWritePin|param|value": "value to write to the pin between ``0`` and ``1023``. eg:1023,0", + "pins.digitalReadPin": "Read the specified pin or connector as either 0 or 1", + "pins.digitalReadPin|block": "digital read|pin %name", + "pins.digitalReadPin|param|name": "pin to read from", + "pins.digitalWritePin": "Set a pin or connector value to either 0 or 1.", + "pins.digitalWritePin|block": "digital write|pin %name|to %value", + "pins.digitalWritePin|param|name": "pin to write to", + "pins.digitalWritePin|param|value": "value to set on the pin, 1 eg,0", + "pins.i2cReadNumber": "Read one number from 7-bit I2C address.", + "pins.i2cReadNumber|block": "i2c read number|at address %address|of format %format=i2c_sizeof", + "pins.i2cWriteNumber": "Write one number to a 7-bit I2C address.", + "pins.i2cWriteNumber|block": "i2c write number|at address %address|with value %value|of format %format=i2c_sizeof", + "pins.map": "Re-maps a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc.", + "pins.map|block": "map %value|from low %fromLow|from high %fromHigh|to low %toLow|to high %toHigh", + "pins.map|param|fromHigh": "the upper bound of the value's current range, eg: 1023", + "pins.map|param|fromLow": "the lower bound of the value's current range", + "pins.map|param|toHigh": "the upper bound of the value's target range, eg: 4", + "pins.map|param|toLow": "the lower bound of the value's target range", + "pins.map|param|value": "value to map in ranges", + "pins.onPulsed": "Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either ``high`` or ``low``.", + "pins.onPulsed|block": "on|pin %pin|pulsed %pulse", + "pins.pulseDuration": "Gets the duration of the last pulse in micro-seconds. This function should be called from a ``onPulsed`` handler.", + "pins.pulseDuration|block": "pulse duration (µs)", + "pins.servoSetPulse": "Configures this IO pin as an analog/pwm output, configures the period to be 20 ms, and sets the pulse width, based on the value it is given **microseconds** or `1/1000` milliseconds.", + "pins.servoSetPulse|block": "servo set pulse|pin %value|to (µs) %micros", + "pins.servoSetPulse|param|micros": "pulse duration in micro seconds, eg:1500", + "pins.servoSetPulse|param|name": "pin name", + "pins.servoWritePin": "Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).", + "pins.servoWritePin|block": "servo write|pin %name|to %value", + "pins.servoWritePin|param|name": "pin to write to", + "pins.servoWritePin|param|value": "angle or rotation speed, eg:180,90,0", + "pins.setPull": "Configures the pull of this pin.", + "pins.setPull|block": "set pull|pin %pin|to %pull", + "pins.setPull|param|name": "pin to set the pull mode on", + "pins.setPull|param|pull": "one of the mbed pull configurations: PullUp, PullDown, PullNone ", + "pins|block": "pins", + "serial": "Reading and writing data over a serial connection.", + "serial.readLine": "Reads a line of text from the serial port.", + "serial.readLine|block": "serial read line", + "serial.redirect": "Dynamically configuring the serial instance to use pins other than USBTX and USBRX.", + "serial.redirect|block": "serial redirect to|TX %tx|RX %rx|at baud rate %rate", + "serial.redirect|param|rx": "the new reception pin", + "serial.redirect|param|tx": "the new transmission pins", + "serial.writeLine": "Prints a line of text to the serial", + "serial.writeLine|block": "serial|write line %text", + "serial.writeNumber": "Prints a numeric value to the serial", + "serial.writeNumber|block": "serial|write number %value", + "serial.writeString": "Sends a piece of text through Serial connection.", + "serial.writeString|block": "serial write string %text", + "serial.writeValue": "Writes a ``name: value`` pair line to the serial.", + "serial.writeValue|block": "serial|write value %name|= %value", + "serial.writeValue|param|name": "name of the value stream, eg: x", + "serial.writeValue|param|value": "to write", + "serial|block": "serial" +} \ No newline at end of file From d8d21296857cd9e4b8e7b2686e13e7e646d81909 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 09:02:31 -0700 Subject: [PATCH 29/42] removed strings page --- .../_locales/microbit-bluetooth-strings.json | 264 ------------------ 1 file changed, 264 deletions(-) delete mode 100644 libs/microbit-bluetooth/_locales/microbit-bluetooth-strings.json diff --git a/libs/microbit-bluetooth/_locales/microbit-bluetooth-strings.json b/libs/microbit-bluetooth/_locales/microbit-bluetooth-strings.json deleted file mode 100644 index c745fff9..00000000 --- a/libs/microbit-bluetooth/_locales/microbit-bluetooth-strings.json +++ /dev/null @@ -1,264 +0,0 @@ -{ - "Math.randomBoolean": "Generates a `true` or `false` value randomly, just like flipping a coin.", - "Math.randomBoolean|block": "pick random true or false", - "Math|block": "Math", - "String.fromCharCode": "Make a string from the given ASCII character code.", - "String.fromCharCode|block": "text from char code %code", - "String|block": "String", - "basic": "Provides access to basic micro:bit functionality.", - "basic.clearScreen": "Turn off all LEDs", - "basic.clearScreen|block": "clear screen", - "basic.forever": "Repeats the code forever in the background. On each iteration, allows other codes to run.", - "basic.forever|block": "forever", - "basic.pause": "Pause for the specified time in milliseconds", - "basic.pause|block": "pause (ms) %pause", - "basic.pause|param|ms": "how long to pause for, eg: 100, 200, 500, 1000, 2000", - "basic.plotLeds": "Draws an image on the LED screen.", - "basic.plotLeds|param|leds": "pattern of LEDs to turn on/off", - "basic.showAnimation": "Shows a sequence of LED screens as an animation.", - "basic.showAnimation|param|interval": "time in milliseconds between each redraw", - "basic.showAnimation|param|leds": "pattern of LEDs to turn on/off", - "basic.showLeds": "Draws an image on the LED screen.", - "basic.showLeds|block": "show leds", - "basic.showLeds|param|interval": "time in milliseconds to pause after drawing", - "basic.showLeds|param|leds": "the pattern of LED to turn on/off", - "basic.showNumber": "Scroll a number on the screen. If the number fits on the screen (i.e. is a single digit), do not scroll.", - "basic.showNumber|block": "show|number %number", - "basic.showNumber|param|interval": "speed of scroll; eg: 150, 100, 200, -100", - "basic.showString": "Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll.", - "basic.showString|block": "show|string %text", - "basic.showString|param|interval": "how fast to shift characters; eg: 150, 100, 200, -100", - "basic.showString|param|text": "the text to scroll on the screen, eg: \"Hello!\"", - "basic|block": "basic", - "bluetooth": "Support for additional Bluetooth services.", - "bluetooth.onBluetoothConnected": "Register code to run when the micro:bit is connected to over Bluetooth", - "bluetooth.onBluetoothConnected|block": "on bluetooth connected", - "bluetooth.onBluetoothConnected|param|body": "Code to run when a Bluetooth connection is established", - "bluetooth.onBluetoothDisconnected": "Register code to run when a bluetooth connection to the micro:bit is lost", - "bluetooth.onBluetoothDisconnected|block": "on bluetooth disconnected", - "bluetooth.onBluetoothDisconnected|param|body": "Code to run when a Bluetooth connection is lost", - "bluetooth.startAccelerometerService": "Starts the Bluetooth accelerometer service", - "bluetooth.startAccelerometerService|block": "bluetooth accelerometer service", - "bluetooth.startButtonService": "Starts the Bluetooth button service", - "bluetooth.startButtonService|block": "bluetooth button service", - "bluetooth.startIOPinService": "Starts the Bluetooth IO pin service.", - "bluetooth.startIOPinService|block": "bluetooth io pin service", - "bluetooth.startLEDService": "Starts the Bluetooth LED service", - "bluetooth.startLEDService|block": "bluetooth led service", - "bluetooth.startMagnetometerService": "Starts the Bluetooth magnetometer service", - "bluetooth.startMagnetometerService|block": "bluetooth magnetometer service", - "bluetooth.startTemperatureService": "Starts the Bluetooth temperature service", - "bluetooth.startTemperatureService|block": "bluetooth temperature service", - "bluetooth.uartRead": "Reads from the Bluetooth UART service buffer, returning its contents when the specified delimiter character is encountered.", - "bluetooth.uartRead|block": "bluetooth uart read %del=bluetooth_uart_delimiter_conv", - "bluetooth.uartWrite": "Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device.", - "bluetooth.uartWrite|block": "bluetooth uart write %data", - "bluetooth|block": "bluetooth", - "control": "Runtime and event utilities.", - "control.inBackground": "Schedules code that run in the background.", - "control.inBackground|block": "run in background", - "control.reset": "Resets the BBC micro:bit.", - "control.reset|block": "reset", - "control|block": "control", - "game": "A single-LED sprite game engine", - "game.addScore": "Adds points to the current score", - "game.addScore|block": "change score by|%points", - "game.addScore|param|points": "amount of points to change, eg: 1", - "game.gameOver": "Displays a game over animation.", - "game.gameOver|block": "game over", - "game.score": "Gets the current score", - "game.score|block": "score", - "game.setScore": "Sets the current score value", - "game.setScore|param|value": "TODO", - "game.startCountdown": "Starts a game countdown timer", - "game.startCountdown|block": "start countdown|(ms) %duration", - "game.startCountdown|param|ms": "countdown duration in milliseconds, eg: 10000", - "game|block": "game", - "images": "Creation, manipulation and display of LED images.", - "images.createBigImage": "Creates an image with 2 frames.", - "images.createBigImage|block": "create big image", - "images.createImage": "Creates an image that fits on the LED screen.", - "images.createImage|block": "create image", - "images|block": "images", - "input": "Events and data from sensors", - "input.acceleration": "Get the acceleration value in milli-gravitys (when the board is laying flat with the screen up, x=0, y=0 and z=-1024)", - "input.acceleration|block": "acceleration (mg)|%NAME", - "input.acceleration|param|dimension": "TODO", - "input.buttonIsPressed": "Get the button state (pressed or not) for ``A`` and ``B``.", - "input.buttonIsPressed|block": "button|%NAME|is pressed", - "input.calibrate": "Obsolete, compass calibration is automatic.", - "input.compassHeading": "Get the current compass compass heading in degrees.", - "input.compassHeading|block": "compass heading (°)", - "input.lightLevel": "Reads the light level applied to the LED screen in a range from ``0`` (dark) to ``255`` bright.", - "input.lightLevel|block": "light level", - "input.magneticForce": "Get the magnetic force value in ``micro-Teslas`` (``µT``). This function is not supported in the simulator.", - "input.magneticForce|block": "magnetic force (µT)|%NAME", - "input.magneticForce|param|dimension": "TODO", - "input.onButtonPressed": "Do something when a button (``A``, ``B`` or both ``A+B``) is pressed", - "input.onButtonPressed|block": "on button|%NAME|pressed", - "input.onButtonPressed|param|body": "TODO", - "input.onButtonPressed|param|button": "TODO", - "input.onGesture": "Attaches code to run when the screen is facing up.", - "input.onGesture|block": "on |%NAME", - "input.onGesture|param|body": "TODO", - "input.onLogoDown": "Attaches code to run when the logo is oriented downwards and the board is vertical.", - "input.onLogoDown|param|body": "TODO", - "input.onLogoUp": "Attaches code to run when the logo is oriented upwards and the board is vertical.", - "input.onLogoUp|param|body": "TODO", - "input.onPinPressed": "Do something when a pin(``P0``, ``P1`` or both ``P2``) is pressed.", - "input.onPinPressed|block": "on pin|%NAME|pressed", - "input.onPinPressed|param|body": "TODO", - "input.onPinPressed|param|name": "TODO", - "input.onScreenDown": "Attaches code to run when the screen is facing down.", - "input.onScreenDown|param|body": "TODO", - "input.onScreenUp": "Attaches code to run when the screen is facing up.", - "input.onScreenUp|param|body": "TODO", - "input.onShake": "Attaches code to run when the device is shaken.", - "input.onShake|param|body": "TODO", - "input.pinIsPressed": "Get the pin state (pressed or not). Requires to hold the ground to close the circuit.", - "input.pinIsPressed|block": "pin|%NAME|is pressed", - "input.pinIsPressed|param|name": "pin used to detect the touch", - "input.rotation": "The pitch of the device, rotation along the ``x-axis``, in degrees.", - "input.rotation|block": "rotation (°)|%NAME", - "input.rotation|param|kind": "TODO", - "input.runningTime": "Gets the number of milliseconds elapsed since power on.", - "input.runningTime|block": "running time (ms)", - "input.setAccelerometerRange": "Sets the accelerometer sample range in gravities.", - "input.setAccelerometerRange|block": "set accelerometer|range %range", - "input.setAccelerometerRange|param|range": "a value describe the maximum strengh of acceleration measured", - "input.temperature": "Gets the temperature in Celsius degrees (°C).", - "input.temperature|block": "temperature (°C)", - "input|block": "input", - "led": "Control of the LED screen.", - "led.brightness": "Get the screen brightness from 0 (off) to 255 (full bright).", - "led.brightness|block": "brightness", - "led.fadeIn": "Fades in the screen display.", - "led.fadeIn|param|ms": "TODO", - "led.fadeOut": "Fades out the screen brightness.", - "led.fadeOut|param|ms": "TODO", - "led.plot": "Turn on the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left.", - "led.plotAll": "Turns all LEDS on", - "led.plotBarGraph": "Displays a vertical bar graph based on the `value` and `high` value.\nIf `high` is 0, the chart gets adjusted automatically.", - "led.plotBarGraph|block": "plot bar graph of %value |up to %high", - "led.plotBarGraph|param|high": "maximum value. If 0, maximum value adjusted automatically, eg: 0", - "led.plotBarGraph|param|value": "current value to plot", - "led.plot|block": "plot|x %x|y %y", - "led.plot|param|x": "TODO", - "led.plot|param|y": "TODO", - "led.point": "Get the on/off state of the specified LED using x, y coordinates. (0,0) is upper left.", - "led.point|block": "point|x %x|y %y", - "led.point|param|x": "TODO", - "led.point|param|y": "TODO", - "led.screenshot": "Takes a screenshot of the LED screen and returns an image.", - "led.setBrightness": "Set the screen brightness from 0 (off) to 255 (full bright).", - "led.setBrightness|block": "set brightness %value", - "led.setBrightness|param|value": "the brightness value, eg:255, 127, 0", - "led.setDisplayMode": "Sets the display mode between black and white and greyscale for rendering LEDs.", - "led.setDisplayMode|param|mode": "TODO", - "led.stopAnimation": "Cancels the current animation and clears other pending animations.", - "led.stopAnimation|block": "stop animation", - "led.toggle": "Toggles a particular pixel", - "led.toggleAll": "Inverts the current LED display", - "led.toggle|param|x": "TODO", - "led.toggle|param|y": "TODO", - "led.unplot": "Turn off the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left.", - "led.unplot|block": "unplot|x %x|y %y", - "led.unplot|param|x": "TODO", - "led.unplot|param|y": "TODO", - "led|block": "led", - "music": "Generation of music tones through pin ``P0``.", - "music.beat": "Returns the duration of a beat in milli-seconds", - "music.beat|block": "%fraction|beat", - "music.changeTempoBy": "Change the tempo by the specified amount", - "music.changeTempoBy|block": "change tempo by (bpm)|%value", - "music.changeTempoBy|param|bpm": "The change in beats per minute to the tempo, eg: 20", - "music.noteFrequency": "Gets the frequency of a note.", - "music.noteFrequency|block": "%note", - "music.noteFrequency|param|name": "the note name", - "music.playTone": "Plays a tone through pin ``P0`` for the given duration.", - "music.playTone|block": "play|tone %note=device_note|for %duration=device_beat", - "music.playTone|param|frequency": "pitch of the tone to play in Hertz (Hz)", - "music.playTone|param|ms": "tone duration in milliseconds (ms)", - "music.rest": "Rests (plays nothing) for a specified time through pin ``P0``.", - "music.rest|block": "rest(ms)|%duration=device_beat", - "music.rest|param|ms": "rest duration in milliseconds (ms)", - "music.ringTone": "Plays a tone through pin ``P0``.", - "music.ringTone|block": "ring tone (Hz)|%note=device_note", - "music.ringTone|param|frequency": "pitch of the tone to play in Hertz (Hz)", - "music.setTempo": "Sets the tempo to the specified amount", - "music.setTempo|block": "set tempo to (bpm)|%value", - "music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120", - "music.tempo": "Returns the tempo in beats per minute. Tempo is the speed (bpm = beats per minute) at which notes play. The larger the tempo value, the faster the notes will play.", - "music.tempo|block": "tempo (bpm)", - "music|block": "music", - "pins": "Control currents in Pins for analog/digital signals, servos, i2c, ...", - "pins.analogPitch": "Emits a Pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.", - "pins.analogPitch|param|frequency": "TODO", - "pins.analogPitch|param|ms": "TODO", - "pins.analogReadPin": "Read the connector value as analog, that is, as a value comprised between 0 and 1023.", - "pins.analogReadPin|block": "analog read|pin %name", - "pins.analogReadPin|param|name": "pin to write to", - "pins.analogSetPeriod": "Configures the Pulse-width modulation (PWM) of the analog output to the given value in **microseconds** or `1/1000` milliseconds.\nIf this pin is not configured as an analog output (using `analog write pin`), the operation has no effect.", - "pins.analogSetPeriod|block": "analog set period|pin %pin|to (µs)%micros", - "pins.analogSetPeriod|param|micros": "period in micro seconds. eg:20000", - "pins.analogSetPeriod|param|name": "analog pin to set period to", - "pins.analogSetPitchPin": "Sets the pin used when using `pins->analog pitch`.", - "pins.analogSetPitchPin|param|name": "TODO", - "pins.analogWritePin": "Set the connector value as analog. Value must be comprised between 0 and 1023.", - "pins.analogWritePin|block": "analog write|pin %name|to %value", - "pins.analogWritePin|param|name": "pin name to write to", - "pins.analogWritePin|param|value": "value to write to the pin between ``0`` and ``1023``. eg:1023,0", - "pins.digitalReadPin": "Read the specified pin or connector as either 0 or 1", - "pins.digitalReadPin|block": "digital read|pin %name", - "pins.digitalReadPin|param|name": "pin to read from", - "pins.digitalWritePin": "Set a pin or connector value to either 0 or 1.", - "pins.digitalWritePin|block": "digital write|pin %name|to %value", - "pins.digitalWritePin|param|name": "pin to write to", - "pins.digitalWritePin|param|value": "value to set on the pin, 1 eg,0", - "pins.i2cReadNumber": "Read one number from 7-bit I2C address.", - "pins.i2cReadNumber|block": "i2c read number|at address %address|of format %format=i2c_sizeof", - "pins.i2cWriteNumber": "Write one number to a 7-bit I2C address.", - "pins.i2cWriteNumber|block": "i2c write number|at address %address|with value %value|of format %format=i2c_sizeof", - "pins.map": "Re-maps a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc.", - "pins.map|block": "map %value|from low %fromLow|from high %fromHigh|to low %toLow|to high %toHigh", - "pins.map|param|fromHigh": "the upper bound of the value's current range, eg: 1023", - "pins.map|param|fromLow": "the lower bound of the value's current range", - "pins.map|param|toHigh": "the upper bound of the value's target range, eg: 4", - "pins.map|param|toLow": "the lower bound of the value's target range", - "pins.map|param|value": "value to map in ranges", - "pins.onPulsed": "Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either ``high`` or ``low``.", - "pins.onPulsed|block": "on|pin %pin|pulsed %pulse", - "pins.pulseDuration": "Gets the duration of the last pulse in micro-seconds. This function should be called from a ``onPulsed`` handler.", - "pins.pulseDuration|block": "pulse duration (µs)", - "pins.servoSetPulse": "Configures this IO pin as an analog/pwm output, configures the period to be 20 ms, and sets the pulse width, based on the value it is given **microseconds** or `1/1000` milliseconds.", - "pins.servoSetPulse|block": "servo set pulse|pin %value|to (µs) %micros", - "pins.servoSetPulse|param|micros": "pulse duration in micro seconds, eg:1500", - "pins.servoSetPulse|param|name": "pin name", - "pins.servoWritePin": "Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).", - "pins.servoWritePin|block": "servo write|pin %name|to %value", - "pins.servoWritePin|param|name": "pin to write to", - "pins.servoWritePin|param|value": "angle or rotation speed, eg:180,90,0", - "pins.setPull": "Configures the pull of this pin.", - "pins.setPull|block": "set pull|pin %pin|to %pull", - "pins.setPull|param|name": "pin to set the pull mode on", - "pins.setPull|param|pull": "one of the mbed pull configurations: PullUp, PullDown, PullNone ", - "pins|block": "pins", - "serial": "Reading and writing data over a serial connection.", - "serial.readLine": "Reads a line of text from the serial port.", - "serial.readLine|block": "serial read line", - "serial.redirect": "Dynamically configuring the serial instance to use pins other than USBTX and USBRX.", - "serial.redirect|block": "serial redirect to|TX %tx|RX %rx|at baud rate %rate", - "serial.redirect|param|rx": "the new reception pin", - "serial.redirect|param|tx": "the new transmission pins", - "serial.writeLine": "Prints a line of text to the serial", - "serial.writeLine|block": "serial|write line %text", - "serial.writeNumber": "Prints a numeric value to the serial", - "serial.writeNumber|block": "serial|write number %value", - "serial.writeString": "Sends a piece of text through Serial connection.", - "serial.writeString|block": "serial write string %text", - "serial.writeValue": "Writes a ``name: value`` pair line to the serial.", - "serial.writeValue|block": "serial|write value %name|= %value", - "serial.writeValue|param|name": "name of the value stream, eg: x", - "serial.writeValue|param|value": "to write", - "serial|block": "serial" -} \ No newline at end of file From ce5da6bf806f1156253c761e174b914bccc591e9 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 09:14:07 -0700 Subject: [PATCH 30/42] updated projects link --- docs/getting-started/rock-paper-scissors.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/getting-started/rock-paper-scissors.md b/docs/getting-started/rock-paper-scissors.md index 1f7fdcec..701d0d6d 100644 --- a/docs/getting-started/rock-paper-scissors.md +++ b/docs/getting-started/rock-paper-scissors.md @@ -200,7 +200,4 @@ input.onButtonPressed(Button.B, () => { ``` Click **Compile** to move your program to the BBC micro:bit! - -# Want to do more? - -There are [10 great projects](/projects) waiting for you. +## [NEXT: PROJECTS!](/projects) From dfbea2719b5e1732e3514fc6fd535a2706dcc450 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 09:41:51 -0700 Subject: [PATCH 31/42] updated project landing page --- docs/projects.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/projects.md b/docs/projects.md index 68c023c6..b41155ed 100644 --- a/docs/projects.md +++ b/docs/projects.md @@ -1,11 +1,7 @@ -# Ten Projects - -### ~avatar avatar +# Projects Here are some cool projects that you can build with your micro:bit! -### ~ - ```codecard [{ From 80d3f67e6c1d202954f867bcd09222577537826d Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 09:48:42 -0700 Subject: [PATCH 32/42] Bump pxt-core to 0.2.188 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eeaa273c..11c16e82 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,6 @@ "typescript": "^1.8.7" }, "dependencies": { - "pxt-core": "*" + "pxt-core": "0.2.188" } } From 7cc93507d9245ffc8fa8783dddcce7b584df284c Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 09:48:44 -0700 Subject: [PATCH 33/42] 0.2.178 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 11c16e82..e13d5df4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pxt-microbit", - "version": "0.2.177", + "version": "0.2.178", "description": "BBC micro:bit target for PXT", "keywords": [ "JavaScript", From 45b480c6ddf38b8f7255a95c56fddcd52bfa33d2 Mon Sep 17 00:00:00 2001 From: Ron Hale-Evans Date: Fri, 24 Jun 2016 10:25:47 -0700 Subject: [PATCH 34/42] Rewrote in simple language. Deleted an irrelevant example. --- docs/reference/control/in-background.md | 35 ++++++++++++------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/reference/control/in-background.md b/docs/reference/control/in-background.md index 24aa8a9b..0e0de180 100644 --- a/docs/reference/control/in-background.md +++ b/docs/reference/control/in-background.md @@ -1,15 +1,25 @@ -# In Background +# Run In Background -Run code in the background as a separate process or thread; for more information on this advanced construct, see [the micro:bit - a reactive system](/device/reactive). +Run part of a program while the rest of it is doing something else. ```sig control.inBackground(() => { }) ``` +### ~hint + +For more information, read +[The micro:bit - a reactive system](/device/reactive). +It is pretty advanced! + +### ~ + ### Example -The example below shows how a background process can be used to display the current value of the global variable `num`, while code (like the `on button pressed` handler) can change the value of the variable. +This program shows how running in the background can say what is +stored in a variable like `num`, while another part (``on button pressed``) +changes what is stored there. ```blocks let num = 0 @@ -24,7 +34,8 @@ input.onButtonPressed(Button.A, () => { }) ``` -The code below using the `forever` loop is equivalent to the code above +This program does the same thing, but in a more usual way, +with a ``forever`` loop. ```blocks let num = 0 @@ -36,20 +47,8 @@ input.onButtonPressed(Button.A, () => { }) ``` -### Contention for the LED display - -If you have multiple processes that each show something on the LED screen, you may get unexpected results. Try, for example: - -```blocks -basic.forever(() => { - basic.showNumber(6789, 150) -}) -input.onButtonPressed(Button.A, () => { - basic.showNumber(2, 150) -}) -``` - ### See also -[while](/blocks/loops/while), [forever](/reference/basic/forever), [on button pressed](/reference/input/on-button-pressed) +[while](/blocks/loops/while), [forever](/reference/basic/forever), +[on button pressed](/reference/input/on-button-pressed) From 545f715eeb8e55b42d24a2ff7f77fa8acc865d56 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 11:03:39 -0700 Subject: [PATCH 35/42] fixing uarl docs --- docs/reference/bluetooth/uart-read.md | 3 +-- docs/reference/bluetooth/uart-write.md | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/reference/bluetooth/uart-read.md b/docs/reference/bluetooth/uart-read.md index 18c7d68c..374507c7 100755 --- a/docs/reference/bluetooth/uart-read.md +++ b/docs/reference/bluetooth/uart-read.md @@ -18,10 +18,9 @@ bluetooth.uartRead(""); ### Example: Starting the Bluetooth UART service and then reading data received from another device which is terminated by ":" character and then displaying it ```blocks -let uart_data: string = ""; +let uart_data = ""; let connected = 0; basic.showString("UART"); -bluetooth.startUartService(); bluetooth.onBluetoothConnected(() => { basic.showString("C"); connected = 1; diff --git a/docs/reference/bluetooth/uart-write.md b/docs/reference/bluetooth/uart-write.md index 34568c9f..58c3d676 100755 --- a/docs/reference/bluetooth/uart-write.md +++ b/docs/reference/bluetooth/uart-write.md @@ -27,7 +27,6 @@ bluetooth.onBluetoothDisconnected(() => { basic.showString("D"); connected = 0; }); -bluetooth.startUartService(); input.onButtonPressed(Button.A, () => { if (connected == 1) { bluetooth.uartWrite("HELLO"); From 3b05b8f2f64cd52a6fe71511787e8cb257e92317 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 11:31:20 -0700 Subject: [PATCH 36/42] Bump pxt-core to 0.2.189 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e13d5df4..e0683db6 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,6 @@ "typescript": "^1.8.7" }, "dependencies": { - "pxt-core": "0.2.188" + "pxt-core": "0.2.189" } } From 9cf7f08ae24a30675140010d94c8c8a1db706f12 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 11:31:22 -0700 Subject: [PATCH 37/42] 0.2.179 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e0683db6..30924129 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pxt-microbit", - "version": "0.2.178", + "version": "0.2.179", "description": "BBC micro:bit target for PXT", "keywords": [ "JavaScript", From 92b46d5c7bab5a242643c1b0821f0c89103b01fd Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 13:27:34 -0700 Subject: [PATCH 38/42] using button instead of large links --- docs/getting-started.md | 4 +++- docs/getting-started/buttons.md | 4 +++- docs/getting-started/coin-flipper.md | 4 +++- docs/getting-started/rock-paper-scissors.md | 4 +++- docs/getting-started/screen.md | 4 +++- docs/getting-started/shake.md | 4 +++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 78556e4e..1fe3577a 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -39,4 +39,6 @@ screen, then a smiley again -- it never stops! (That's because of the Click **Compile** to move your program to the BBC micro:bit! Make sure to follow the instructions. -## [NEXT: THE SCREEN](/getting-started/screen) \ No newline at end of file +### ~button /getting-started/screen +NEXT: THE SCREEN +### ~ \ No newline at end of file diff --git a/docs/getting-started/buttons.md b/docs/getting-started/buttons.md index 492cfd45..0f2d79dd 100644 --- a/docs/getting-started/buttons.md +++ b/docs/getting-started/buttons.md @@ -76,4 +76,6 @@ your handshake to make it happen! ## ~ -## [NEXT: SHAKE](/getting-started/shake) \ No newline at end of file +### ~button /getting-started/shake +NEXT: SHAKE +### ~ \ No newline at end of file diff --git a/docs/getting-started/coin-flipper.md b/docs/getting-started/coin-flipper.md index 32bea0ba..93d27c0f 100644 --- a/docs/getting-started/coin-flipper.md +++ b/docs/getting-started/coin-flipper.md @@ -73,4 +73,6 @@ input.onButtonPressed(Button.AB, () => { Flip until your thumbs get tired! -## [NEXT: ROCK PAPER SCISSORS](/getting-started/rock-paper-scissors) +### ~button /getting-started/rock-paper-scissors +NEXT: ROCK PAPER SCISSORS +### ~ diff --git a/docs/getting-started/rock-paper-scissors.md b/docs/getting-started/rock-paper-scissors.md index 701d0d6d..ac9f6e79 100644 --- a/docs/getting-started/rock-paper-scissors.md +++ b/docs/getting-started/rock-paper-scissors.md @@ -200,4 +200,6 @@ input.onButtonPressed(Button.B, () => { ``` Click **Compile** to move your program to the BBC micro:bit! -## [NEXT: PROJECTS!](/projects) +### ~button /projects +NEXT: PROJECTS! +### ~ diff --git a/docs/getting-started/screen.md b/docs/getting-started/screen.md index 64e7c64a..30cf1339 100644 --- a/docs/getting-started/screen.md +++ b/docs/getting-started/screen.md @@ -93,4 +93,6 @@ You can find the ``show leds`` block in the **Basic** part of the editor. #### ~ -## [NEXT: BUTTONS](/getting-started/buttons) \ No newline at end of file +### ~button /getting-started/buttons +NEXT: BUTTONS +### ~ \ No newline at end of file diff --git a/docs/getting-started/shake.md b/docs/getting-started/shake.md index 5856cbc9..ced4b764 100644 --- a/docs/getting-started/shake.md +++ b/docs/getting-started/shake.md @@ -19,4 +19,6 @@ input.onGesture(Gesture.Shake, () => { ``` Click **Compile** to move your program to the BBC micro:bit! -## [NEXT: COIN FLIPPER GAME](/getting-started/coin-flipper) +### ~button /getting-started/coin-flipper +NEXT: COIN FLIPPER GAME +### ~ From ed6d34399234d4c093306ecb3f20cd0fbe235b2c Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 13:54:45 -0700 Subject: [PATCH 39/42] Bump pxt-core to 0.2.190 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 30924129..861ea779 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,6 @@ "typescript": "^1.8.7" }, "dependencies": { - "pxt-core": "0.2.189" + "pxt-core": "0.2.190" } } From 58f79ea6171bb0ac705760f1caecb8d92711ebc8 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 24 Jun 2016 13:54:47 -0700 Subject: [PATCH 40/42] 0.2.180 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 861ea779..08d69d99 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pxt-microbit", - "version": "0.2.179", + "version": "0.2.180", "description": "BBC micro:bit target for PXT", "keywords": [ "JavaScript", From b72ff9fe4f93674e8e2b4e22488455e02752f836 Mon Sep 17 00:00:00 2001 From: Ron Hale-Evans Date: Fri, 24 Jun 2016 15:42:21 -0700 Subject: [PATCH 41/42] New page for accelerometer range. --- docs/reference/input/acceleration.md | 4 +- .../input/set-accelerometer-range.md | 37 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 docs/reference/input/set-accelerometer-range.md diff --git a/docs/reference/input/acceleration.md b/docs/reference/input/acceleration.md index f4b4e122..f59ffa62 100644 --- a/docs/reference/input/acceleration.md +++ b/docs/reference/input/acceleration.md @@ -38,5 +38,7 @@ basic.forever(() => { ### See also -[compass-heading](/reference/input/compass-heading), [lightlevel](/reference/input/light-level) +[set accelerometer range](/reference/input/set-accelerometer-range), +[compass heading](/reference/input/compass-heading), +[light level](/reference/input/light-level) diff --git a/docs/reference/input/set-accelerometer-range.md b/docs/reference/input/set-accelerometer-range.md new file mode 100644 index 00000000..68589749 --- /dev/null +++ b/docs/reference/input/set-accelerometer-range.md @@ -0,0 +1,37 @@ +# Set Accelerometer Range + +Set up the part of the micro:bit that measures +[acceleration](/reference/input/acceleration) (how much the microbit +is speeding up or slowing down), in case you need to measure high +or low acceleration. + +### Parameters + +* the biggest number of gravities of acceleration you will be + measuring (either 1G, 2G, 4G, or 8G). Any bigger numbers will be + ignored by your micro:bit, both when you are picking a number of + gravities, and when you are measuring acceleration. + +### Example + +This program says the highest acceleration that your micro:bit +will measure is 4G. Then it measures acceleration from side to side +until you stop the program. + +```blocks +input.setAccelerometerRange(AcceleratorRange.FourG); +basic.forever(() => { + basic.showNumber(input.acceleration(Dimension.X)); +}); +``` + +#### ~hint + +This program does not work in the simulator, only in a micro:bit. + +#### ~ + +### See Also + +[compass heading](/reference/input/compass-heading), +[light level](/reference/input/light-level) From e6baf8c35ebf885cc6510cee6166e0756ac9f26f Mon Sep 17 00:00:00 2001 From: Tom Ball Date: Fri, 24 Jun 2016 19:37:05 -0400 Subject: [PATCH 42/42] bring streaming into menu --- docs/streaming.md | 4 ++-- pxtarget.json | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/streaming.md b/docs/streaming.md index c70980fd..f2ce8334 100644 --- a/docs/streaming.md +++ b/docs/streaming.md @@ -26,7 +26,7 @@ that there is a data stream and displays a graph. The log view will automatically start to collect and organize the data it detects. Simply click on the log view to open the various options to export the data. The simplest option is to download the data as a **CSV file**. This file can easily be opened in programs like Office Excel. -## Cloud upload +## Cloud upload via Azure -In the data export dialog, there is another option to upload the data to the cloud. This allows to upload small amounts of data +In the data export dialog, there is another option to upload the data to the Azure cloud. This allows to upload small amounts of data without any kind setup. The data can be accessed via web services or directly from Office Excel. \ No newline at end of file diff --git a/pxtarget.json b/pxtarget.json index 93138988..d156eec5 100644 --- a/pxtarget.json +++ b/pxtarget.json @@ -112,6 +112,10 @@ { "name": "JavaScript", "path": "/javascript" + }, + { + "name": "Streaming Data", + "path": "/streaming" } ], "sideDoc": "getting-started"