diff --git a/.github/lock.yml b/.github/lock.yml index a1d7e6e1..974f87a3 100644 --- a/.github/lock.yml +++ b/.github/lock.yml @@ -30,7 +30,13 @@ lockLabel: false # Comment to post before locking. Set to `false` to disable -lockComment: false +lockComment: > + + This thread has been automatically locked since there has not been + + any recent activity after it was closed. Please open a new issue for + + related bugs. diff --git a/.github/workflows/compress-images-on-pull-request.yml b/.github/workflows/compress-images-on-pull-request.yml new file mode 100644 index 00000000..4f747770 --- /dev/null +++ b/.github/workflows/compress-images-on-pull-request.yml @@ -0,0 +1,12 @@ +name: Compress images +on: pull_request +jobs: + build: + name: calibreapp/image-actions + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: calibreapp/image-actions + uses: calibreapp/image-actions@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pxt-buildpr.yml b/.github/workflows/pxt-buildpr.yml deleted file mode 100644 index 2d2450d6..00000000 --- a/.github/workflows/pxt-buildpr.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: pxt-buildpr - -on: [pull_request] - -jobs: - build: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [8.x] - - steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: npm install - run: | - sudo apt-get install xvfb - sudo npm install -g pxt - npm install - - name: pxt ci - run: | - pxt ci - env: - CHROME_BIN: chromium-browser - DISPLAY: :99.0 - CI: true diff --git a/.github/workflows/pxt-buildtarget.yml b/.github/workflows/pxt-buildtarget.yml deleted file mode 100644 index 9d40aed0..00000000 --- a/.github/workflows/pxt-buildtarget.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: pxt-buildtarget - -on: - push: - branches: - - master - create: - -jobs: - build: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [8.x] - - steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: npm install - run: | - sudo apt-get install xvfb - sudo npm install -g pxt - npm install - - name: pxt ci - run: | - pxt ci - env: - CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }} - PXT_ACCESS_TOKEN: ${{ secrets.PXT_ACCESS_TOKEN }} - PXT_RELEASE_REPO: ${{ secrets.PXT_RELEASE_REPO }} - NPM_ACCESS_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} - CHROME_BIN: chromium-browser - DISPLAY: :99.0 - CI: true diff --git a/.github/workflows/testghpkgs.yml b/.github/workflows/testghpkgs.yml new file mode 100644 index 00000000..d4926702 --- /dev/null +++ b/.github/workflows/testghpkgs.yml @@ -0,0 +1,50 @@ +name: pxt-testghpkgs + +on: + schedule: + - cron: '0 0 * * 6' + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [8.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm install + run: | + sudo npm install -g pxt + npm install + - name: pxt buildtarget + run: pxt buildtarget + - name: cache build output + uses: actions/cache@v1 + env: + cache-name: cache-testghpkgs + with: + path: temp/ghpkgs + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + - name: pxt testghpkgs + run: pxt testghpkgs + env: + PXT_FORCE_GITHUB_PROXY: 1 + PXT_ACCESS_TOKEN: ${{ secrets.PXT_ACCESS_TOKEN }} + GITHUB_TOKEN: ${{ secrets.TRAVIS_GITHUB_ACCESS_TOKEN }} + - name: upload build log + uses: actions/upload-artifact@v2 + if: ${{ always() }} + with: + name: logs + path: temp/ghpkgs/*.txt diff --git a/.gitignore b/.gitignore index 89b121a8..4e6323eb 100644 --- a/.gitignore +++ b/.gitignore @@ -27,10 +27,6 @@ crowdinstats.csv *.db *.suo *.log - -.DS_Store -.idea -*.iml .vscode/.BROWSE.VC.DB-shm .vscode/.BROWSE.VC.DB-wal package-lock.json diff --git a/README.md b/README.md index 152beb0e..be1b63f1 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,149 @@ -# Calliope target for Microsoft MakeCode +# micro:bit target for PXT -This editor is hosted at https://makecode.calliope.cc. -* Got a question? Try the forum at https://forum.calliope.cc/ -### BUILD COMMENTS +pxt-calliope is a [Microsoft Programming Experience Toolkit (PXT)](https://github.com/Microsoft/pxt) target that allows you to program a [BBC micro:bit](https://microbit.org/). -- build libs/core/dal.d.ts new requires some meddling, as the `#define` parser does not parse `#ifdef` and thus -has some conflicts with double defines constants -![](http://calliope.cc/content/1-ueber-mini/mini_board.png) +* [Try it live](https://makecode.calliope.cc/) -## Local server +## Issue tracking -The local server allows to run the editor and the documentation from your computer. +Please add an issue if you discover an (unreported) bug. -### Setup +## Developing new extensions -The following commands are a 1-time setup after synching the repo on your machine. +Authoring and testing of new extensions can be done directly from the web editor. See [our documentation](https://makecode.com/blog/github-packages) on how to get started. If you want to run the editor locally, keep reading. -* See requirements for [pxt](https://github.com/Microsoft/pxt) -* [clone this repo](https://help.github.com/articles/cloning-a-repository/) to your computer and go in the project folder +## Local server setup + +The local server lets you to run the editor and serve the documentation from your own computer. It is meant for a single developer used and not designed to serve the editor to a large amount of users. + +1. Install [Node.js](https://nodejs.org/) 8.9.4 or higher. +2. Clone this repository. ``` git clone https://github.com/microsoft/pxt-calliope cd pxt-calliope ``` -* install the PXT command line (add ``sudo`` for Mac/Linux shells). +3. Install the PXT command line (add `sudo` for Mac/Linux shells). ``` npm install -g pxt ``` -* install the dependencies +4. Install the pxt-calliope dependencies. ``` npm install ``` +Go to the **Running** section. + +### Developer Setup + +This is the typical setup used by the MakeCode team to work on the microbit. + +1. Install [Node.js](https://nodejs.org/) 8.9.4 or higher. +2. Install [Docker](https://www.docker.com/get-started) if you plan to build ``.cpp`` files. +3. Clone the pxt repository. +``` +git clone https://github.com/microsoft/pxt +cd pxt +``` +4. Install the dependencies of pxt and build it +``` +npm install +npm run build +cd .. +``` +5. Clone the pxt-common-packages repository +``` +git clone https://github.com/microsoft/pxt-common-packages +cd pxt-common-packages +npm install +cd .. +``` +6. Clone this repository. +``` +git clone https://github.com/microsoft/pxt-calliope +cd pxt-calliope +``` +7. Install the PXT command line (add `sudo` for Mac/Linux shells). +``` +npm install -g pxt +``` +8. Install the pxt-calliope dependencies. +``` +npm install +``` +8. Link pxt-calliope back to base pxt repo (add `sudo` for Mac/Linux shells). +This step is only required if you intend to make changes to pxt and/or +pxt-common-packages repos. If all you want is serve a local Makecode, you can skip +this step. +``` +pxt link ../pxt +pxt link ../pxt-common-packages +``` +Note the above command assumes the folder structure of +``` + makecode + | + ---------------------------------- + | | | + pxt pxt-common-packages pxt-calliope + ``` + ### Running -Run this command to open a local web server (add ``sudo`` for Mac/Linux shells). +Run this command from inside pxt-calliope to open a local web server ``` pxt serve ``` If the local server opens in the wrong browser, make sure to copy the URL containing the local token. Otherwise, the editor will not be able to load the projects. -If you need modify the `.cpp` files, turn on yotta compilation with the ``-yt`` flag (add ``sudo`` for Mac/Linux shells). On Windows, you must be running -from the ``Run Yotta`` command prompt. +If you need to modify the `.cpp` files (and have installed yotta), enable yotta compilation using the `--localbuild` flag: ``` -pxt serve -yt +pxt serve --local ``` -## Updates - -To update your PXT version and make sure you're running the latest tools, run (add ``sudo`` for Mac/Linux shells) +If you want to speed up the build, you can use the ``rebundle`` option, which skips building and simply refreshes the target information ``` -pxt update +pxt serve --rebundle ``` -More instructions at https://github.com/Microsoft/pxt#running-a-target-from-localhost +### Cleaning -## Testing +Sometimes, your built folder might be in a bad state, clean it and try again. +``` +pxt clean +``` -The build automatically runs the following: +### Updates -* make sure the built-in packages compile -* `pxt run` in `libs/lang-test*` - this will run the test in command line runner; - there is a number of asserts in both of these -* `pxt testdir` in `tests` - this makes sure all the files compile and generates .hex files +Make sure to pull changes from all repos regularly. More instructions are at https://github.com/Microsoft/pxt#running-a-target-from-localhost -To test something on the device: +## Update playlists in markdown -* do a `pxt deploy` in `libs/lang-test*` - they should show `1` or `2` on the screen (and not unhappy face) -* run `pxt testdir` in `tests` and deploy some of the hex files from `tests/built` +Get a Google API key and store it in the ``GOOGLE_API_KEY`` environment variables (turn on data from the app). -The `lang-test0` source comes from the `pxt-core` package. It's also tested with `pxt run` there. +``` +pxt downloadplaylists +``` + +## Repos + +The pxt-calliope target depends on several other repos. The main ones are: +- https://github.com/Microsoft/pxt, the PXT framework +- https://github.com/Microsoft/pxt-common-packages, common APIs accross various MakeCode editors +- https://github.com/lancaster-university/microbit, basic wrapper around the DAL +- https://github.com/lancaster-university/microbit-dal + +## History + +See the [MakeCode blog](https://makecode.com/blog). ## Code of Conduct This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +## Trademarks + +MICROSOFT, the Microsoft Logo, and MAKECODE are registered trademarks of Microsoft Corporation. They can only be used for the purposes described in and in accordance with Microsoft’s Trademark and Brand guidelines published at https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general.aspx. If the use is not covered in Microsoft’s published guidelines or you are not sure, please consult your legal counsel or MakeCode team (makecode@microsoft.com). diff --git a/calliope.code-workspace b/calliope.code-workspace deleted file mode 100644 index c925e61c..00000000 --- a/calliope.code-workspace +++ /dev/null @@ -1,13 +0,0 @@ -{ - "folders": [ - { - "path": "../pxt" - }, - { - "path": "../pxt-common-packages" - }, - { - "path": "." - } - ] -} \ No newline at end of file diff --git a/clients/macuploader/Graphics/appicon.sketch b/clients/macuploader/Graphics/appicon.sketch new file mode 100644 index 00000000..480cb417 Binary files /dev/null and b/clients/macuploader/Graphics/appicon.sketch differ diff --git a/clients/macuploader/Graphics/export.png b/clients/macuploader/Graphics/export.png index 7bc58c2e..b5083be0 100644 Binary files a/clients/macuploader/Graphics/export.png and b/clients/macuploader/Graphics/export.png differ diff --git a/clients/macuploader/Graphics/menubar.sketch b/clients/macuploader/Graphics/menubar.sketch new file mode 100644 index 00000000..55ed3814 Binary files /dev/null and b/clients/macuploader/Graphics/menubar.sketch differ diff --git a/docs/blocks/logic/boolean.md b/docs/blocks/logic/boolean.md new file mode 100644 index 00000000..350626f4 --- /dev/null +++ b/docs/blocks/logic/boolean.md @@ -0,0 +1,30 @@ +# @extends + +## #examples + +## Example: ``AND`` operator + +This example turns on LED `3 , 3`, if LEDs `1 , 1` and `2 , 2` are both on: + +```blocks +if (led.point(1,1) && led.point(2,2)) { + led.plot(3,3) +} +``` + +## Example: Comparisons of numbers and strings + +When you compare two Numbers, you get a Boolean value, such as the comparison `x < 5` in the code below: + +```blocks +input.onButtonPressed(Button.A, () => { + let x = randint(0, 5) + if(x < 5) { + basic.showString("low"); + } else { + basic.showString("high"); + } +}) +``` + +See the documentation on [Numbers](/types/number) for more information on comparing two Numbers. diff --git a/docs/blocks/logic/if.md b/docs/blocks/logic/if.md new file mode 100644 index 00000000..c3d0d837 --- /dev/null +++ b/docs/blocks/logic/if.md @@ -0,0 +1,15 @@ +# @extends + +## #examples + +## Example: adjusting screen brightness + +If the [light level](/reference/input/light-level) is `< 100`, this code sets the brightness to `255` when the button A is pressed: + +```blocks +input.onButtonPressed(Button.A, () => { + if(input.lightLevel()<100){ + led.setBrightness(255); + } +}) +``` diff --git a/docs/blocks/loops.md b/docs/blocks/loops.md new file mode 100644 index 00000000..03d67b62 --- /dev/null +++ b/docs/blocks/loops.md @@ -0,0 +1,3 @@ +# @extends + +## #specific diff --git a/docs/blocks/loops/for-of.md b/docs/blocks/loops/for-of.md new file mode 100644 index 00000000..a0cc44c0 --- /dev/null +++ b/docs/blocks/loops/for-of.md @@ -0,0 +1,20 @@ +# @extends + +## #examples + +## Example: Find the highest number + +Find the highest number in a list of numbers. Display the highest number on the screen. + +```blocks +let list: number[] = [] +let highest = 0 +highest = 0 +list = [5, 8, 6, 2, 4, 3, 7, 1] +for (let value of list) { + if (value > highest) { + highest = value + } +} +basic.showNumber(highest) +``` \ No newline at end of file diff --git a/docs/blocks/loops/for.md b/docs/blocks/loops/for.md new file mode 100644 index 00000000..1f4faf2b --- /dev/null +++ b/docs/blocks/loops/for.md @@ -0,0 +1,15 @@ +# @extends + +## #examples + +## Example: Count to 4 + +This program will show the numbers 0, 1, 2, 3, and 4 one after another on the LED screen. + +```blocks +input.onButtonPressed(Button.A, () => { + for(let i = 0; i < 5; ++i) { + basic.showNumber(i) + } +}) +``` diff --git a/docs/blocks/loops/repeat.md b/docs/blocks/loops/repeat.md new file mode 100644 index 00000000..8c2fcb3d --- /dev/null +++ b/docs/blocks/loops/repeat.md @@ -0,0 +1,16 @@ +# @extends + +## #examples + +## Example: Blinking heart + +Flash the ``heart`` icon on the screen `4` times. + +```blocks +for (let i = 0; i < 4; i++) { + basic.showIcon(IconNames.Heart) + basic.pause(300) + basic.clearScreen() + basic.pause(300) +} +``` diff --git a/docs/blocks/loops/while.md b/docs/blocks/loops/while.md new file mode 100644 index 00000000..f6f3e569 --- /dev/null +++ b/docs/blocks/loops/while.md @@ -0,0 +1,17 @@ +# @extends + +## #examples + +## Example: diagonal line + +The following example uses a while loop to make a diagonal line on the LED screen (points `0, 0`, `1, 1`, `2, 2`, `3, 3`, `4, 4`). + +```blocks +input.onButtonPressed(Button.A, () => { + let index = 4; + while(index >= 0) { + led.plot(index, index); + index--; + } +}) +``` diff --git a/docs/blocks/math/random-boolean.md b/docs/blocks/math/random-boolean.md new file mode 100644 index 00000000..e32b6d59 --- /dev/null +++ b/docs/blocks/math/random-boolean.md @@ -0,0 +1,29 @@ +# random Boolean + +Returns a pseudo-random boolean value that is either `true` or `false`. + +```sig +Math.randomBoolean() +``` + +## Returns + +* a pseudo-random [boolean](types/boolean) that is either `true` or `false`. + +## Example + +Make your @boardname@ do a coin toss when it's dropped softly. Have the LEDs show 'heads' or 'tails' as the result of the toss. + +```blocks +input.onGesture(Gesture.FreeFall, () => { + if (Math.randomBoolean()) { + basic.showIcon(IconNames.Happy) + } else { + basic.showIcon(IconNames.Sword) + } +}) +``` + +## See Also + +[random](/reference/math/random) \ No newline at end of file diff --git a/docs/blocks/on-start.md b/docs/blocks/on-start.md new file mode 100644 index 00000000..8c56977c --- /dev/null +++ b/docs/blocks/on-start.md @@ -0,0 +1,12 @@ +# @extends + +## #exstart + +In this example, ``on start`` sets a dimmer brightness on the screen and the button handler shows a string. + +```blocks +input.onButtonPressed(Button.A, () => { + basic.showString("Hello!") +}) +led.setBrightness(50) +``` diff --git a/docs/blocks/variables/assign.md b/docs/blocks/variables/assign.md new file mode 100644 index 00000000..0d3a503a --- /dev/null +++ b/docs/blocks/variables/assign.md @@ -0,0 +1,36 @@ +# Assignment Operator + +Use an equals sign to make a [variable](/blocks/variables/var) store the [number](/types/number) +or [string](/types/string) you say. + +When you use the equals sign to store something in a variable, the equals sign is called +an *assignment operator*, and what you store is called a *value*. + +## Storing numbers in variables + +This program makes the variable `item` equal `5` and then shows it on the [LED screen](/device/screen). + +````blocks +let item = 5 +basic.showNumber(item) +```` + +## Storing strings in variables + +This program makes the variable `name` equal `Joe` and then shows it on the [LED screen](/device/screen). + +````blocks +let name = "Joe" +basic.showString(name); +```` + +## Notes + +You can use the assignment operator with variables of +every [type](/types). A *type* is which kind of thing +a variable can store, like a number or string. + +## See also + +[variable](/blocks/variables/var), [types](/types) + diff --git a/docs/blocks/variables/change.md b/docs/blocks/variables/change.md new file mode 100644 index 00000000..e30c9386 --- /dev/null +++ b/docs/blocks/variables/change.md @@ -0,0 +1,13 @@ +# @extends + +## #examples + +## Example: show the value of a variable + +Use the assignment operator to set the value of a [variable](/blocks/variables/var). Change the value of a variable from 0 to 1 using the change item block. Then display the new value of the variable on the LED screen. Like this: + +```blocks +let x = 0; +x += 1; +basic.showNumber(x); +``` diff --git a/docs/blocks/variables/var.md b/docs/blocks/variables/var.md new file mode 100644 index 00000000..d149e444 --- /dev/null +++ b/docs/blocks/variables/var.md @@ -0,0 +1,87 @@ +# Local Variables + +How to define and use local variables. + +## @parent language + +A variable is a place where you can store and retrieve data. Variables have a name, a [type](/types), and value: + +* *name* is how you'll refer to the variable +* *type* refers to the kind of data a variable can store +* *value* refers to what's stored in the variable + +## Var statement + +Use the Block Editor variable statement to create a variable +and the [assignment operator](/blocks/variables/assign) +to store something in the variable. + +For example, this code stores the number `2` in the `x` variable: + +```blocks +let x = 2; +``` +Here's how to define a variable in the Block Editor: + +1. Click `variables`. + +2. Change the default variable name if you like. + +3. Drag a block type on the right-side of the [assignment operator](/blocks/variables/assign) and click the down arrow to change the variable name. + +A variable is created for the number returned by the [brightness](/reference/led/brightness) function. + +```blocks +let b = led.brightness(); +``` + +## Using variables + +Once you've defined a variable, just use the variable's name whenever you need what's stored in the variable. For example, the following code shows the value stored in `counter` on the LED screen: + +```blocks +let counter = 1; +basic.showNumber(counter); +``` + +To change the contents of a variable use the assignment operator. The following code sets `counter` to 1 and then increments `counter` by 10: + +```blocks +let counter = 1; +counter = counter + 10; +basic.showNumber(counter); +``` + +## Why use variables? + +If you want to remember and modify data, you'll need a variable. +A counter is a great example: + +```blocks +let counter = 0; +input.onButtonPressed(Button.A, () => { + counter = counter + 1; + basic.showNumber(counter); +}); +``` + +## Local variables + +Local variables exist only within the function or block of code where they're defined. For example: + +```blocks +// x does NOT exist here. +if (led.brightness() > 128) { + // x exists here + let x = 0; +} +``` + +### Notes + +* You can use the default variable names if you'd like, however, it's best to use descriptive variable names. To change a variable name in the editor, select the down arrow next to the variable and then click "new variable". + +## See also + +[types](/types), [assignment operator](/blocks/variables/assign) + diff --git a/docs/coding-cards.md b/docs/coding-cards.md new file mode 100644 index 00000000..7846e4f6 --- /dev/null +++ b/docs/coding-cards.md @@ -0,0 +1,74 @@ +# Coding Cards + +## Math + +```codecard +[ +{ + "name": "Make a Digital Balance", + "description": "Use the accelerometer to find the balance point", + "url": "https://drive.google.com/open?id=1Tl80unLA5_Zwkymh1flSbwuZbCIqSOxQ", + "imageUrl": "/static/coding-cards/balance-card.jpg" +}, +{ + "name": "Make a Digital Dice", + "description": "Create a shakeable dice that uses the accelerometer", + "url": "https://drive.google.com/open?id=1iW75z-7maJ3qixwv9Yuj6rA5U387qVpg", + "imageUrl": "/static/coding-cards/dice-card.jpg" +}, +{ + "name": "Make a Trundle Wheel", + "description": "Build trundle wheel that measures a distance travelled", + "url": "https://drive.google.com/open?id=1hzpBN5aqzYMvm7s_W6RQr9u4eFx1f6LK", + "imageUrl": "/static/coding-cards/trundlewheel-card.jpg" +} +] +``` + +## Games + +```codecard +[ +{ + "name": "Nervous", + "description": "Carefully move the ring but don't touch the wire!", + "url": "https://drive.google.com/open?id=1BJCkrdMoojU-ojQcOluawecw5W6kcdnZ", + "imageUrl": "/static/coding-cards/games-nervous.jpg" +}, +{ + "name": "Reaction", + "description": "Which player has the fastest reaction time?", + "url": "https://drive.google.com/open?id=1kfZKLflUrPoeveboo1LpubgaJSsFkDgY", + "imageUrl": "/static/coding-cards/games-reaction.jpg" +}, +{ + "name": "Shake the Bottle", + "description": "Shake the bottle until the fizz inside pops the lid", + "url": "https://drive.google.com/open?id=1lTZbrVP5UDG7IZeY1Kod8gw4VNcldzzZ", + "imageUrl": "/static/coding-cards/games-shake.jpg" +}, +{ + "name": "Sprite Based Games", + "description": "Try this game to see how to make sprite based games", + "url": "https://drive.google.com/open?id=1p1fm9SlFVr8NQ9ctQvhZ7H-okfxXhabW", + "imageUrl": "/static/coding-cards/games-sprite.jpg" +}, +{ + "name": "Zen", + "description": "Strike a pose but keep very still, wiggle too much and your out!", + "url": "https://drive.google.com/open?id=14JBWsx-K489GjSgvMX4kslxaHKYfdBtj", + "imageUrl": "/static/coding-cards/games-zen.jpg" +} +] +``` + +## See Also + +[Make a Digital Balance](https://drive.google.com/open?id=1Tl80unLA5_Zwkymh1flSbwuZbCIqSOxQ), +[Make a Digital Dice](https://drive.google.com/open?id=1iW75z-7maJ3qixwv9Yuj6rA5U387qVpg), +[Make a Trundle Wheel](https://drive.google.com/open?id=1hzpBN5aqzYMvm7s_W6RQr9u4eFx1f6LK), +[Nervous](https://drive.google.com/open?id=1BJCkrdMoojU-ojQcOluawecw5W6kcdnZ), +[Reaction](https://drive.google.com/open?id=1kfZKLflUrPoeveboo1LpubgaJSsFkDgY), +[Shake the Bottle](https://drive.google.com/open?id=1lTZbrVP5UDG7IZeY1Kod8gw4VNcldzzZ), +[Sprite Based Games](https://drive.google.com/open?id=1p1fm9SlFVr8NQ9ctQvhZ7H-okfxXhabW), +[Zen](https://drive.google.com/open?id=14JBWsx-K489GjSgvMX4kslxaHKYfdBtj) diff --git a/docs/courses/blocks-to-javascript/SUMMARY.md b/docs/courses/blocks-to-javascript/SUMMARY.md new file mode 100644 index 00000000..3a6dd25e --- /dev/null +++ b/docs/courses/blocks-to-javascript/SUMMARY.md @@ -0,0 +1,8 @@ +# [Blocks to JavaScript](/courses/blocks-to-javascript) + +* [Blocks to JavaScript](/courses/blocks-to-javascript) + * [Hello JavaScript](/courses/blocks-to-javascript/hello-javascript) + * [Starter Blocks](/courses/blocks-to-javascript/starter-blocks) + * [Writing Code](/courses/blocks-to-javascript/writing-code) + * [Conditional Loops](/courses/blocks-to-javascript/conditional-loops) + * [Writing Functions](/courses/blocks-to-javascript/writing-functions) diff --git a/docs/courses/logic-lab.md b/docs/courses/logic-lab.md new file mode 100644 index 00000000..3d90ab0b --- /dev/null +++ b/docs/courses/logic-lab.md @@ -0,0 +1,15 @@ +# Logic Lab + +![Logic lab header image](/static/courses/logic-lab/logic-lab-header.jpg) + +A basic aspect of knowledge and understanding is whether something is true or not. Considering conditions around you and making a conclusion about something being true or false means that you are using logic. Computers and, in fact, all of digital electronics rely on this idea of logic to process information and give results in terms of conditions being true or false. Logic is used almost everywhere in the programs you write in places where you want decide to do one task or another. + +## Logic topics + +These topic sections teach you about applying logic to conditions and using Boolean algebra to express them. Also, you will see how logical operators work and how they combine to form more complex logic structures. + +* [Logic and Expressions](/courses/logic-lab/expressions) +* [Boolean Elements](/courses/logic-lab/elements) +* [Logic Explorer](/courses/logic-lab/explorer) +* [Logic Gates](/courses/logic-lab/logic-gates) +* [Programmable Logic](/courses/logic-lab/programmable) diff --git a/docs/courses/logic-lab/SUMMARY.md b/docs/courses/logic-lab/SUMMARY.md new file mode 100644 index 00000000..95b9eb45 --- /dev/null +++ b/docs/courses/logic-lab/SUMMARY.md @@ -0,0 +1,8 @@ +# [Logic Lab](/courses/logic-lab) + +* [Logic Lab](/courses/logic-lab) + * [Logic and Expressions](/courses/logic-lab/expressions) + * [Boolean Elements](/courses/logic-lab/elements) + * [Logic Explorer](/courses/logic-lab/explorer) + * [Logic Gates](/courses/logic-lab/logic-gates) + * [Programmable Logic](/courses/logic-lab/programmable) diff --git a/docs/courses/logic-lab/elements.md b/docs/courses/logic-lab/elements.md new file mode 100644 index 00000000..9f7780d0 --- /dev/null +++ b/docs/courses/logic-lab/elements.md @@ -0,0 +1,207 @@ +# Boolean elements + +Whether creating equations in Boolean algebra or using them in your programs, you'll form both simple and complex logical expressions that use basic operations to combine the logical conditions. + +## Notation + +Boolean (logical) equations are expressed in a way similar to mathmatical equations. Variables in Boolean expressions though, have only two possible values, ``true`` or ``false``. For an equation using a logical expression, the equivalant sides of the equal sign ,``=``, will be only ``true`` or ``false`` too. + +The following list shows the basic notation elements for Boolean expressions. + +* ``~A``: the inverse (**NOT**) of ``A``, when ``A`` is ``true``, ``~A`` is ``false`` +* ``A + B``: the value of ``A`` **OR** ``B`` +* ``A · B``: the value of ``A`` **AND** ``B`` +* ``A ⊕ B``: the value of the exclusive OR (**XOR**) of ``A`` with ``B`` +* ``Q``: equivalent result (OUTPUT) value of a logical expression + +A resulting value, ``Q``, from a logical expression in is shown like: + +``Q`` = ``A + B`` + +An equation to show logically equivalent expressions (where both sides have the same resulting value) can look like this: + +``~(A + B)`` = ``~A · ~B`` + +## Logical operators + +All Boolean expressions result from a combination of conditions and operators. These operators join individual conditons together and evaluate into a single ``true`` or ``false`` condition. The following are the basic logical operators. Their use in both Boolean algebra and in code is shown along with their truth table. + +### Identity + +Identity means that a result value is the same as the condition itself. + +``Q = A`` + +```block +let A = false +let Q = A +``` + +#### Example - Blink LEDs on press + +```blocks +let A = false +basic.forever(function () { + A = input.buttonIsPressed(Button.A) + if (A) { + basic.showIcon(IconNames.Chessboard) + } else { + basic.clearScreen() + } + basic.pause(100) +}) +``` + +#### Truth table + +A | A +-|- +F | F +T | T + +### NOT (Negation) + +The NOT operator is called negation or the inverse. It takes a single logical value and makes it have the opposite value, ``true`` goes to ``false`` and ``false`` goes to ``true``. + +``Q = ~A`` + +```block +let A = false +let Q = !(A) +``` + +#### Example - Blink LEDs on not pressed + +```blocks +let A = false +basic.forever(function () { + A = input.buttonIsPressed(Button.A) + if (!(A)) { + basic.showIcon(IconNames.Chessboard) + } else { + basic.clearScreen() + } + basic.pause(100) +}) +``` + +#### Truth table + +A | ~A +-|- +F | T +T | F + +### OR (Disjunction) + +The OR operator results in ``true`` when one or more conditions are ``true``. + +``Q = A + B`` + +```block +let A = false +let B = false +let Q = A || B +``` + +#### Example - Blink on any press + +```blocks +let A = false +let B = false +basic.forever(function () { + A = input.buttonIsPressed(Button.A) + B = input.buttonIsPressed(Button.B) + if (A || B) { + basic.showIcon(IconNames.Chessboard) + } else { + basic.clearScreen() + } + basic.pause(100) +}) +``` + +#### Truth table + +A | B | A + B +-|-|- +F | F | F +T | F | T +F | T | T +T | T | T + +### AND (Conjunction) + +The AND operator requires that all conditions are ``true`` for the result to be ``true``. + +``Q = A · B`` + +```block +let A = false +let B = false +let Q = A && B +``` + +#### Example - Blink on double press only + +```blocks +let A = false +let B = false +basic.forever(function () { + A = input.buttonIsPressed(Button.A) + B = input.buttonIsPressed(Button.B) + if (A && B) { + basic.showIcon(IconNames.Chessboard) + } else { + basic.clearScreen() + } + basic.pause(100) +}) +``` + +#### Truth table + +A | B | A · B +-|-|- +F | F | F +T | F | F +F | T | F +T | T | T + +### XOR (Exclusive OR) #xor + +Exclusive OR (XOR) means that only one or the other condition is true. Both conditions can't be true at the same time. XOR is common in Boolean algebra but it has no operator in JavaScript. Its operation can be made from combining a few simple expressions. + +``Q = A ⊕ B`` + +```block +let A = false +let B = false +let Q = (A || B) && !(A && B) +``` + +#### Example - Blink on one press or the other + +```blocks +let A = false +let B = false +basic.forever(function () { + A = input.buttonIsPressed(Button.A) + B = input.buttonIsPressed(Button.B) + if ((A || B) && !(A && B)) { + basic.showIcon(IconNames.Chessboard) + } else { + basic.clearScreen() + } + basic.pause(100) +}) +``` + +#### Truth table + +A | B | A ⊕ B +-|-|- +F | F | F +T | F | T +F | T | T +T | T | F diff --git a/docs/courses/logic-lab/explorer.md b/docs/courses/logic-lab/explorer.md new file mode 100644 index 00000000..fad60650 --- /dev/null +++ b/docs/courses/logic-lab/explorer.md @@ -0,0 +1,162 @@ +# Logic explorer + +As a way to see how the basic logical operators work, we'll make a program to test them with all their possible input values. + +## Inputs and output + +Make an array called ``||variables:inputs||`` with two values, ``false`` and ``true``, as logical inputs. Add another variable ``||variables:Q||`` to receive the resulting value of a logical expression as output. + +```blocks +let inputs = [false, true] +let Q = false +``` + +## Single input loop + +To start with, we'll make a single input test for the variable ``||variables:A||``. The output, in variable ``||variables:Q||``, for the logical operator test will display an icon on the LEDs. A ``true`` value shows a ``t-shirt`` and ``false`` will show a ``small diamond``. + +1. Get a ``||loops:for element||`` loop and put it in the ``||loops:on start||``. Rename the ``||variables:index||`` variable to ``||variables:A||`` and switch the ``||variables:list||`` variable to ``||variables:inputs||``. +2. Pull a ``||variables:set Q to||`` block into the ``||loops:for element||`` loop and set the value to ``||logic:false||``. +3. Go find the ``||logic:if then else||`` and put in below the ``||variables:set Q to||``. Pick up a ``||variables:Q||`` in ``||variables:VARIABLE||`` and drop it onto the ``||logic:false||`` to replace it. +4. Move a ``||basic:show icon||`` inside the ``||logic:if then||`` section and change the image to a ``t-shirt``. This is our image for a ``true`` output. +5. Move a ``||basic:show icon||`` inside the ``||logic:else||`` section and change the image to a ``small diamond``. This is our image for a ``false`` output. +6. Just below the ``||logic:if then else||``, put in a ``||loops:pause||``, a ``||basic:clear screen||``, and another ``||basic:pause||`` block. Set the time for each ``||basic:pause||`` to ``500``. + +```blocks +let inputs = [false, true] +let Q = false +for (let A of inputs) { + Q = false + if (Q) { + basic.showIcon(IconNames.TShirt) + } else { + basic.showIcon(IconNames.SmallDiamond) + } + basic.pause(500) + basic.clearScreen() + basic.pause(500) +} +``` + +## Identity test + +The identity test is simple. It just makes the output have the same logical value as the input. Set the ``||variables:Q||`` output variable to the ``||variables:A||`` variable. + +```block +let A = false +let Q = A +``` + +### Identity truth table + +For the Identity test, these output values will show for the inputs: + +A | Q = A +-|- +**false** | ``[basic.showIcon(IconNames.SmallDiamond)]`` +**true** | ``[basic.showIcon(IconNames.TShirt)]`` + +## NOT test + +Negation, or inversion, makes the output have the opposite value of the input. So, the output value is NOT the same as the input. Since there are only two possible values, the output is the other value that is NOT the input. + +Replace the ``||logic:false||`` in the ``||variables:Q||`` equation with a ``||logic:not||`` operator. Pull the ``||variables:A||`` variable down from the ``||loops:for element||`` loop and drop it inside the ``||logic:not||`` operator. + +```block +let A = false +let Q = !A +``` + +### NOT truth table + +For the NOT test, these output values will show for the inputs: + +A | ~A +-|- +**false** | ``[basic.showIcon(IconNames.TShirt)]`` +**true** | ``[basic.showIcon(IconNames.SmallDiamond)]`` + +## Two input loop + +For the rest of the operator tests, we need to have another input variable. This variable comes from a second ``||loops:for element||`` loop. With one input variable there was just two possible input values. Adding a second input variable increases the number of possible input combinations by two times. Now there will be 4 different input possibilities. This will result in the truth tables having 4 rows for the operator tests. + +Go get another ``||loops:for element||`` loop and put it in so that it surrounds all the inside the first loop. Rename the ``||variables:index||`` variable to ``||variables:B||`` and switch the ``||variables:list||`` variable to ``||variables:inputs||``. + +```blocks +let inputs = [false, true] +let Q = false +for (let A of inputs) { + for (let B of inputs) { + Q = !A + if (Q) { + basic.showIcon(IconNames.TShirt) + } else { + basic.showIcon(IconNames.SmallDiamond) + } + basic.pause(500) + basic.clearScreen() + basic.pause(500) + } +} +``` + +## OR test + +Now, grab an ``||logic:or||`` operator and replace the ``||logic:not||`` in the ``||variables:Q||`` equation with it. Pull the ``||variables:A||`` variable down from the outside ``||loops:for element||`` loop and drop it in on the left side the ``||logic:or||`` operator. Drag down the ``||variables:B||`` variable down from the inside ``||loops:for element||`` loop and drop it in on the right side the ``||logic:or||`` operator. + +```block +let A = false +let B = false +let Q = A || B +``` +### OR truth table + +For the OR test, these output values will show for the inputs: + +A | B | A + B +-|-|- +**false** | **false** | ``[basic.showIcon(IconNames.SmallDiamond)]`` +**false** | **true** | ``[basic.showIcon(IconNames.TShirt)]`` +**true** | **false** | ``[basic.showIcon(IconNames.TShirt)]`` +**true** | **true** | ``[basic.showIcon(IconNames.TShirt)]`` + +## AND test + +Now, switch the ``||logic:or||`` operator type in the ``||variables:Q||`` equation to the ``||logic:and||`` operator type: + +```block +let A = false +let B = false +let Q = A && B +``` + +### AND truth table + +For the AND test, these output values will show for the inputs: + +A | B | A · B +-|-|- +**false** | **false** | ``[basic.showIcon(IconNames.SmallDiamond)]`` +**false** | **true** | ``[basic.showIcon(IconNames.SmallDiamond)]`` +**true** | **false** | ``[basic.showIcon(IconNames.SmallDiamond)]`` +**true** | **true** | ``[basic.showIcon(IconNames.TShirt)]`` + +## XOR test + +To test XOR, we'll use the XOR expression from [Boolean elements](/courses/logic-lab/elements#xor). Drag and place the ``||logic:LOGIC||`` blocks to make the ``||variables:Q||`` equation to look like this: + +```block +let A = false +let B = false +let Q = (A || B) && !(A && B) +``` +### XOR truth table + +For the XOR test, these output values will show for the inputs: + +A | B | A ⊕ B +-|-|- +**false** | **false** | ``[basic.showIcon(IconNames.SmallDiamond)]`` +**false** | **true** | ``[basic.showIcon(IconNames.TShirt)]`` +**true** | **false** | ``[basic.showIcon(IconNames.TShirt)]`` +**true** | **true** | ``[basic.showIcon(IconNames.SmallDiamond)]`` \ No newline at end of file diff --git a/docs/courses/logic-lab/expressions.md b/docs/courses/logic-lab/expressions.md new file mode 100644 index 00000000..c4d7ba8e --- /dev/null +++ b/docs/courses/logic-lab/expressions.md @@ -0,0 +1,142 @@ +# Logic and expressions + +The use and study of _logic_ involves finding a new fact by analyzing whether some other facts together can prove to be true. Some facts, or conditions, when looked at together may prove another fact to be true, or maybe false. + +If the temperature outside is below freezing and you don't have a coat, you will feel cold. If you're not sick, then you will feel well. If you can swim or ride in a boat in water, you will stay afloat. These are statements of fact that result from some condition being true. + +## Truth statements + +By taking some facts and putting them into a logical form, we can make an arithmetic that helps us analyze them and make a conclusion. Using the examples just mentioned, let's turn them into some logical word equations: + +* ``Outside temperature is freezing`` **AND** ``I have no coat`` **=** ``I feel cold`` +* **NOT** ``sick`` **=** ``I feel well`` +* ``I can swim`` **OR** ``I'm in a boat`` **=** ``I'm floating`` + +You see the AND, NOT, and OR in the example word equations? These are our logical _operators_. Every day we make decisions when we think about one or more facts together using these operators. Sometimes, it's necessary for all facts to be true in order for the conclusion to be true. This is the case when the AND operator is used. When analyzing facts with the OR operator, only on fact needs to be true for the conclusion to be true also. + +Making a decision may require more than just one or two facts. When this happens, another operator is needed to combine the facts together to make a conclusion. In the last example word equation, you actually might not be floating if just those two condtions are true. To correctly prove that you're actually floating, you need to state that you're in water too. + +* **(**``I can swim`` **OR** ``I'm in a boat``**) AND** ``I'm in water`` **=** ``I'm floating`` + +To prove that you're floating, the two facts that you can swim or you are in a boat must be made into a single fact that is combined with the other fact that you are also in water. Otherwise, if you're able to swim but still on land, or in a boat that is on the beach, you're not not floating. + +## Boolean algebra + +As a way to reduce the conditions, or facts as we've called them, into a form that is more compact, an algebra was invented. George Boole made a type of arithmetic (Boolean algebra) that uses symbols for the conditions, the operators, and the result. The conditions are considered as variables that have the value of either ``true`` or ``false``. the operators like AND, OR, and NOT are single character symbols. If we want to change the statement "I'm happy when it's sunny or when I'm eating a donut" into a Boolean equation, we could start by making the conditions into variables. + +* Variable ``A`` = ``"It's sunny"`` +* Variable ``B`` = ``"I've eaten a donut"`` + +The result then, is a variable called ``Q`` that is true when you're happy and is a value of an operation of ``A`` with ``B``. This operation is OR which is represented by the ``+`` symbol. + +``Q`` = ``A + B`` + +The result of ``Q`` is ``true`` when either it's sunny or you've had a donut. If other things make you happy, like being on vacation, you could add that to the equation. + +* Variable ``C`` = ``"I'm on vacation"`` + +``Q`` = ``A + B + C`` + +It could be that you're easy to please and you just have to feel well to be happy. So, you're happy when your NOT sick. We'll use the ``~`` to mean NOT in our equation. + +* Variable ``A`` = ``"I'm sick"`` + +``Q`` = ``~A`` + +In the situation where all conditions must be true for the result to be true, the conditions use the AND operation. For the sun to shine on you, the sky must be clear and it has to be daytime. We put these two facts together with the AND symbol ``·``. + +* Variable ``A`` = ``"The sky is clear"`` +* Variable ``B`` = ``"It's daytime"`` +* Result ``Q`` = ``"The sun is shining"`` + +``Q`` = ``A · B`` + +## Expressions + +Sometimes different operations on the same conditions can make equivalent results. If we take the opposite case of the last example where the sun is not shining, the variables for that are: + +* Variable ``A`` = ``"The sky is clear"`` +* Variable ``B`` = ``"It's daytime"`` +* Result ``Q`` = ``"The sun is shining"`` +* Result ``~Q`` = ``"The sun is NOT shining"`` + +To make the opposite of ``"the sun is shining"`` we negate, use the NOT symbol, on both sides of the equation. + +``~Q`` = ``~(A · B)`` + +Now, let's think of the sun NOT shining due to negative conditions. If the sky isn't clear OR it's not daytime, then the sun isn't shining. So, the NOT symbol is put in before the variables for each condition so that ``"the sun is NOT shining"`` has another equation like this: + +``~Q`` = ``~A + ~B`` + +We see that the side with the ``A`` and ``B`` variables in both equations are equivalent to each other since they both equate to ``~Q``: + +``~(A · B)`` = ``~A + ~B`` + +The logic equation now doesn't include the result variable ``Q`` but instead there are two _expressions_ that are logically equivalent on each side. + +### ~ hint + +#### De Morgan's Thereom + +That last equation, ``~(A · B)`` = ``~A + ~B``, demonstrates an inportant property in Boolean algebra. It's called De Morgan's Thereom which says that the inverse (NOT) of a conjunction (AND) is logically equivalent to the disjunction (OR) of two inverses (NOT). Also, the inverse (NOT) of a disjunction (OR) is logically equivalent to the conjunction (AND) of two inverses (NOT). + +This easier understood by seeing the Boolean equations for both cases: + +``~(A · B)`` = ``~A + ~B`` + +>-- AND -- + +``~(A + B)`` = ``~A · ~B`` + +### ~ + +## Truth tables + +A truth table is a way to see all possible condtions for the variables in a logical expression and to chart the results. Using the truth statement about when it's freezing outside and you have no coat, here's the truth table showing the possible conditions and their results: + +It's freezing | I have no coat | I feel cold +-|-|- +false | false | false +false | true | false +true | false | false +true | true | true +
+ +Because you feel cold only when both conditions are true, the statement becomes an AND expression in Boolean algebra. + +* Variable ``A`` = ``"it's freezing"`` +* Variable ``B`` = ``"I don't have a coat"`` + +``A · B`` = ``Q`` + +A truth table for the variables in the expression have the same values as the table for the truth statement (``true`` and ``false`` are abbreviated to just ``T`` and ``F``). + +A | B | Q +-|-|- +F | F | F +F | T | F +T | F | F +T | F | T +
+ +What would happen if we changed the condition of ``"I have no coat"`` to ``"I have a coat"``? How does that affect truth table about how cold you feel? + +It's freezing | I have a coat | I feel cold +-|-|- +false | false | false +false | true | false +true | false | true +true | true | false +
+ +A | B | Q +-|-|- +F | F | F +F | T | F +T | F | T +T | F | F +
+ +To write a Boolean equation for when you feel cold, we find the condtions in the table where ``Q`` is ``true``. Here we see that you will feel cold only in one row, when condition ``A`` is ``true`` and condtion ``B`` is ``false``. The Boolean equation for these conditions is this: + +``A · ~B`` = ``Q`` diff --git a/docs/courses/logic-lab/logic-gates.md b/docs/courses/logic-lab/logic-gates.md new file mode 100644 index 00000000..fc37475d --- /dev/null +++ b/docs/courses/logic-lab/logic-gates.md @@ -0,0 +1,87 @@ +# Logic Gates + +![OR gate symbol](/static/courses/logic-lab/logic-gates/full-adder.png) + +In the real world digital devices aren't the abstract logical expressions of Boolean algebra, but they are implementations of these expressions in hardware. The logical expressions are translated into device structures called _logic gates_. A logic gate is both a symbolic representation of a logical operation and, when used in digital electronics, it can is an actual circuit in hardware. A single logic gate is usually made of several transistors an shares space with many others in an integrated circuit. + +Each of the basic operators we learned about in the [expressions](/courses/logic-lab/expressions) section have a gate symbol. The symbol takes the place of the operator and the variables are the inputs to the gate. The resulting value from the expression equation is the output of the gate. The output of a gate can be a final result or it can be connected as an input to yet another gate. + +## Gate symbols + +Logic gates are symbols that can directly replace an expression in Boolean arithmetic. Each one has a different shape to show its particular function. The inputs (Boolean variables) enter at the left of the symbol and the output leaves from the right. When combined together, several gates can make a complex logical evaluation system that has many inputs and outputs. Digital computers are designed by connecting thousands, or millions, of these gates to together. + +### NOT gate + +The NOT gate is a forward arrow with a small circle at the output. The circle part of the symbol is what says that the output is negating the input. + +![NOT gate symbol](/static/courses/logic-lab/logic-gates/not-gate.png) + +### OR gate + +Th OR gate has a curved input side and a sharp pointed output. + +![OR gate symbol](/static/courses/logic-lab/logic-gates/or-gate.png) + +### AND gate + +The AND gate has a flat input side and round output side. + +![AND gate symbol](/static/courses/logic-lab/logic-gates/and-gate.png) + +### Exclusive OR (XOR) gate + +The exclusive or gate symbol is just like the OR gate but it has an additonal curved line crossing the inputs. + +![XOR gate symbol](/static/courses/logic-lab/logic-gates/xor-gate.png) + +## Combined logic + +When you connect multiple gates together you have a combined logic system or _combinatorial logic_. To design a combined logic system we can use a truth tables to match logical outputs for out various input conditions. Boolean expressions are written from the conditions in the table. Then, we can directly convert the expression into a diagram of logic gates. + +You might remember that back in [Boolean elements](/courses/logic-lab/elements#xor) we saw that there was no operator to use in code for XOR. It was was made up using a combination of AND, OR, and NOT operators: + +```block +let A = false +let B = false +let Q = (A || B) && !(A && B) +``` + +Let's map the input and output conditions in a truth table for a combined logic system for XOR. We'll find all the conditions that cause a ``true`` result and create a Boolean expression for them. + +A | B | A ⊕ B +-|-|- +F | F | F +F| T | T +T| F | T +T | T | F +
+ +There are two conditions where the result column has ``true`` values. The first conditon is when ``A`` is ``false`` and ``B`` is ``true`` which is expressed as ``~A · B``. The second conditon is when ``A`` is ``true`` and ``B`` is ``false`` which is expressed as ``A · ~B``. Our XOR expression is ``true`` when one of these conditions are ``true`` which is written like: + +``A ⊕ B`` = ``(~A · B) + (A · ~B)`` + +In code this expression is formed with these logic blocks: + +```block +let A = false +let B = false +let Q = (!A && B) || (A && !B) +``` + +Coverting the equation to logic gates makes the following diagram. Notice how each gate "connects" the variables together just like the logic blocks in the code above. + +![Combinatorial XOR first version](/static/courses/logic-lab/logic-gates/combinatorial1-xor.png) + +However, if we take the other two unused conditions from the truth table that make the XOR operation ``false``, can make the negative equation for XOR, called a NXOR: + +``~(A ⊕ B)`` = ``(~A · ~B) + (A · B)`` + +To get back to ``A ⊕ B`` we have to negate this negative equation. Then, with the help of [De Morgan's Thereom](/courses/logic-lab/expressions#de-morgan-s-thereom), we get a different equation for XOR but it's still logically equivalent to the original one. + +``A ⊕ B`` = ``(A + B) · ~(A · B)`` + +When this equation is converted to logic gates, there's one fewer gate than in the first diagram. + +![Combinatorial XOR second version](/static/courses/logic-lab/logic-gates/combinatorial2-xor.png) + +This diagram has less complexity than the first one. Reduction in the number of gates to accomplish the same logical result is one of the primary goals for digital logic design. For electronic devices, this allows more gates to use the limited amount of space on an integrated circuit. diff --git a/docs/courses/logic-lab/programmable.md b/docs/courses/logic-lab/programmable.md new file mode 100644 index 00000000..217e420c --- /dev/null +++ b/docs/courses/logic-lab/programmable.md @@ -0,0 +1,231 @@ +# Programmable logic + +Logic gates are formed by connecting transistors together on a semiconductor material to make an integrated circuit. The wafers, or chips, of semiconductor contain lots of logic gates that make up different types of devices which work together to read, store, calculate, and transmit digital information. + +Most integrated circuits contain a specific arrangement logic gates at the time they are manufactured. Because of their physical and chemical properties, some semiconductors can let you change connections between the gates after the device is manufactured. By applying special voltages at programming pins, a custom arrangement of gates can be "programmed" into the integrated circuit. These types of semiconductors are part of a category of electronics called _Programmable Logic Devices (PLD)_. There are many different kinds. Some of them you program only once and others you can erase the original gate arrangement and program in new ones multiple times. + +We can use the @boardname@ to create our own PLD. The digital pins are the inputs for the logic circuits. The logic gates we program are logical expressions in code that combine the digital inputs we read from the pins. The result of the expression is written to a digital output pin. + +## Board PLD + +The physical idea of using your board as a PLD looks like this: + +![Board with to logic inputs and one output](/static/courses/logic-lab/pld/mbit-pld.png) + +The logic inputs for `A` and `B` are connected to digital input pins. The resulting output `Q` is connected to a digital output pin. We can make a general representation of your board as a PLD by selecting some digital pins to use as inputs and outputs for our programmable logic. + +![Generic PLD representation](/static/courses/logic-lab/pld/generic-pld.png) + +By "connecting" the pins together with code, we can program virtual logic gates and make the board act like a PLD. With multiple pins and some more code, we can even create a combined logic circuit. + +![Gates inside the PLD diagram](/static/courses/logic-lab/pld/not-and-or.png) + + + +## Programmable NOT gate + +The **NOT** gate takes the logic value of the input and inverts it at the output. This is a single input gate using just the **P0** pin for input. + +![NOT gate with pin assignments](/static/courses/logic-lab/pld/not-gate-pins.png) + +The **NOT** gate is wired using alligator test clips as shown in the following diagram. The output clip is connected to pin **P2**. + +![NOT gate wiring diagram](/static/courses/logic-lab/pld/not-gate-pld.png) + +The script to program the **NOT** gate is simply a logical inverse of ``||pins:digital read pin||`` written to an output pin with ``||pins:digital write pin||``. + +```block +if (pins.digitalReadPin(DigitalPin.P0) > 0) { + pins.digitalWritePin(DigitalPin.P2, 0) +} else { + pins.digitalWritePin(DigitalPin.P2, 1) +} +``` + +## Programmable OR gate + +The **OR** gate takes two inputs and makes the output ``true`` if any input is ``true``. The **P0** and **P1** pins are the inputs. + +![OR gate with pin assignments](/static/courses/logic-lab/pld/or-gate-pins.png) + +The **OR** gate is wired using alligator test clips as shown in this diagram. The output clip is connected to pin **P2**. + +![OR gate wiring diagram](/static/courses/logic-lab/pld/or-gate-pld.png) + +The script to program an **OR** gate is two ``||pins:digital read pin||`` blocks, evaluated with an ``||logic:or||``, and the result is written to an output pin with ``||pins:digital write pin||``. + +```block +if ((pins.digitalReadPin(DigitalPin.P0) > 0) || pins.digitalReadPin(DigitalPin.P1) > 0) { + pins.digitalWritePin(DigitalPin.P2, 1) +} else { + pins.digitalWritePin(DigitalPin.P2, 0) +} +``` + +## Programmable AND gate + +The **AND** gate takes two inputs and makes the output ``true`` if both inputs are ``true``. The **P0** and **P1** pins are the inputs. + +![AND gate with pin assignments](/static/courses/logic-lab/pld/and-gate-pins.png) + +The **AND** gate is wired using alligator test clips as shown in the next diagram. The output pin is connected to pin **A2**. + +![AND gate wiring diagram](/static/courses/logic-lab/pld/and-gate-pld.png) + +The script for an **AND** gate is two ``||pins:digital read pin||`` blocks, evaluated with an ``||logic:and||``, and the result is written to an output pin with ``||pins:digital write pin||``. + +```block +if ((pins.digitalReadPin(DigitalPin.P0) > 0) && pins.digitalReadPin(DigitalPin.P1) > 0) { + pins.digitalWritePin(DigitalPin.P2, 1) +} else { + pins.digitalWritePin(DigitalPin.P2, 0) +} +``` + +## Combined logic + +You can program your board to have multiple logic gates that operate on the two inputs. Just combine the three logic gate scripts from above into one ``||loops:forever||`` loop. If you have an expansion connector for your @boardname@, you could program multiple outputs for your logic system. You could also use one extra input pin as an observer pin to test the outputs of your combined logic. The different outputs feedback to the observer pin so it will see what their logic levels are. Here's a schematic for a multiple gate system. + +![micro:bit NOT, AND, OR gate PLD](/static/courses/logic-lab/pld/not-and-or-pld.png) + +The combined logic for our multiple gate PLD is programmed like this: + +```blocks +let A = false +let B = false +basic.forever(function () { + A = pins.digitalReadPin(DigitalPin.P0) > 0 + B = pins.digitalReadPin(DigitalPin.P1) > 0 + + if (A) { + pins.digitalWritePin(DigitalPin.P2, 0) + } else { + pins.digitalWritePin(DigitalPin.P2, 1) + } + if (A || B) { + pins.digitalWritePin(DigitalPin.P3, 1) + } else { + pins.digitalWritePin(DigitalPin.P3, 0) + } + if (A && B) { + pins.digitalWritePin(DigitalPin.C4, 1) + } else { + pins.digitalWritePin(DigitalPin.C4, 0) + } + basic.pause(100) +}) +``` + +### Logic observer + +As easy way to see what the outputs of our PLD are, you can use the **P6** pin as a logic observer input and display the letter ``T`` for a ``true`` output value and the letter ``F`` for ``false``. + +```blocks +basic.forever(function () { +if (pins.digitalReadPin(DigitalPin.C6) > 0) { + basic.showString("T") + } else { + basic.showString("F") + } + basic.pause(100) +}) +``` + +### Input tests + +You can test different input combinations by connecting the other ends of alligator clip leads on pins **P0** and **P1** to either **GND** or **3V**. The **GND** pin will make a ``false`` input value and **3V** will make a ``true`` input value. + +If you have an expansion connector for your @boardname@, you can use the combined logic script and the logic observer code to check each ouptput. Move the other end alligator clip lead connected to the observer pin **P6** to each of the outputs **P2**, **P3**, and **P4** to see the result of the logic operation programmed for those pins. + +If you just have the @boardname@ by itself, you can test each logic function using only the scripts for each logic gate. Just put the script inside a ``||loops:forever||`` and place a ``||basic:show string||`` block with the logic letter after each ``||pins:digital write pin||``. + +This is the code for the **NOT** gate: + +```blocks +basic.forever(function() { + if (pins.digitalReadPin(DigitalPin.P0) > 0) { + pins.digitalWritePin(DigitalPin.P2, 0) + basic.showString("F") + } else { + pins.digitalWritePin(DigitalPin.P2, 1) + basic.showString("T") + } + basic.pause(100) +}) +``` + +#### NOT truth table + +As an example, here's the truth table with pin voltages for the **NOT** operation: + +P0 | P2 | Display +-|-|- +GND | 3V | ``[basic.showString("T")]`` +3V | GND | ``[basic.showString("F")]`` +
+ +Do test connections for the inputs and check the results for the **OR** and **AND** outputs. + +#### OR truth table + +P0 | P1 | P3 | Display +-|-|-|- +GND | GND | ? | ? +GND | 3V | ? | ? +3V | GND | ? | ? +3V | 3V | ? | ? + +#### AND truth table + +P0 | P1 | P4 | Display +-|-|-|- +GND | GND | ? | ? +GND | 3V | ? | ? +3V | GND | ? | ? +3V | 3V | ? | ? + +### XOR device + +As we learned earlier, the **XOR** gate operation is made up from several other gates. The result `Q` was made from this expression in code: + +```block +let A = false +let B = false +let Q = (!A && B) || (A && !B) +``` + +We'll make an **XOR** gate by programming a combined logic device for it. This time let's say that the whole @boardname@ is a programmed **XOR** gate. + +![XOR symbol with board image](/static/courses/logic-lab/pld/xor-mbit.png) + +Let's use the same wiring diagram as we did for the **OR** gate using **P0** and **P1** as input pins with **P2** as the output pin. + +![XOR gate wiring diagram](/static/courses/logic-lab/pld/xor-gate-pld.png) + +Our logic gate script is a bit different this time. To simplify forming the expression for **XOR**, we'll assign variables to the input and output values. + +```blocks +let A = false +let B = false +basic.forever(function () { + A = pins.digitalReadPin(DigitalPin.P0) > 0 + B = pins.digitalReadPin(DigitalPin.P1) > 0 + if (!(A) && B || A && !(B)) { + pins.digitalWritePin(DigitalPin.P2, 1) + basic.showString("T") + } else { + pins.digitalWritePin(DigitalPin.P2, 0) + basic.showString("F") + } + basic.pause(100) +}) +``` + +Connect the inputs for **P0** and **P1** according to the **XOR** truth table and see if the outputs in the table match your results. + +P0 | P1 | P2 | Display +-|-|-|- +GND | GND | GND | ``[basic.showString("F")]`` +GND | 3V | 3V | ``[basic.showString("T")]`` +3V | GND | 3V | ``[basic.showString("T")]`` +3V | 3V | GND | ``[basic.showString("F")]`` diff --git a/docs/device/bluetooth/hf2.md b/docs/device/bluetooth/hf2.md new file mode 100644 index 00000000..b7a217be --- /dev/null +++ b/docs/device/bluetooth/hf2.md @@ -0,0 +1,19 @@ +# Bluetooth HF2 + +The Bluetooth HF2 service implements a subset of [HF2](https://github.com/Microsoft/uf2/blob/master/hf2.md), namely the serial message logging. + +## Service + +### HF2 service + + * UUID: ``b112f5e6-2679-30da-a26e-0273b6043849`` + +### TX Characteristic + +* Optional +* UUDI: ``b112f5e6-2679-30da-a26e-0273b604384a`` +* NOTIFY only + +This characteristic mostly emits HF2 serial messages. The first byte contains the type of message and length in the lower 6 bits. The message contains up to 19 bytes. + +This service is supported by the MakeCode editor to receive messages. \ No newline at end of file diff --git a/docs/device/crocodile-clips.md b/docs/device/crocodile-clips.md new file mode 100644 index 00000000..8664df59 --- /dev/null +++ b/docs/device/crocodile-clips.md @@ -0,0 +1,48 @@ +# Crocodile clips + +The large holes at the bottom of the board are designed to attach alligator/crocodile clips +to create electrical circuit with other components. + +# ~hint + +**No crocodile clips!?!?!** Use [wires or aluminium foil](/device/foil-circuits)! + +# ~ + + +## Connecting crocodile clips + +The hole for ``P0`` and ``GND`` allow to grab the board on the side which makes for a great grip. + +![](/static/mb/device/croc-clips/crocclipsclamped.jpg) + +Pass one jaw in the hole and grab the side of the board with the other jaw. + +![](/static/mb/device/croc-clips/sideclamp.jpg) + +For the center holes, ``P1`` and ``P2``, you can also grab the bottom of the board but they are a bit harder to grip. + +You can also grip the board between the jaws. In which case, you will want to make sure to avoid overlapping the jaws +with the other pins as it will create short-circuit in the board. + +![](/static/mb/device/croc-clips/badclamp.jpg) + +Adding a little tape helps keeping the crocodile clips in place. + +![](/static/mb/device/croc-clips/frontclamp.jpg) + +## Example: on pin pressed with random numbers + +This example displays a random number every time the crocodile clip holds `GND` then connects and disconnects the `P0` pin. +Each time the crocodile clip is firmly connected and disconnected from pin `P0`, +the @boardname@ will return a random Number between 0 and the parameter limit. + +```blocks +input.onPinPressed(TouchPin.P0, () => { + basic.showNumber(randint(0, 10)) +}) +``` + +## See also + +[micro:bit pins](/device/pins) diff --git a/docs/device/data-analysis.md b/docs/device/data-analysis.md new file mode 100644 index 00000000..6a6c9354 --- /dev/null +++ b/docs/device/data-analysis.md @@ -0,0 +1,16 @@ +# Data Analysis + +In addition to learning programming, the @boardname@ is a fantastic tool for observing and measuring things that happen in the natural world. The sciences rely on methods of observation, information gathering, and analysis. Using the @boardname@ with MakeCode, you can use the sensors and inputs to measure and capture physical events that occur. Measurement data can then be sent for recording by other devices like another @boardname@ or a personal computer. + +![Data graph logo](/static/mb/device/data-analysis/data-analysis.jpg) + +The Data Viewer in the MakeCode editor allows you to stream and log data from your programs. It will do this when you write data values using the **[serial](/reference/serial)** write functions. When you try your code in the simulator or connect with USB, each value you write is saved and collected as a log for you to analyze later if you want. + +These topics describe how to analyze your data using MakeCode with the @boardname@: + +* [Plotting with LEDs](./data-analysis/led-plotting) +* [Viewing your data](./data-analysis/viewing) +* [Writing data](./data-analysis/writing) +* [Generating data](./data-analysis/generating) +* [Analyze](./data-analysis/analyze) +* [Remote data collection](./data-analysis/remote) diff --git a/docs/device/data-analysis/analyze.md b/docs/device/data-analysis/analyze.md new file mode 100644 index 00000000..16b1b431 --- /dev/null +++ b/docs/device/data-analysis/analyze.md @@ -0,0 +1,110 @@ +# Analyze + +When it recognizes that data in the console has a format it can show in a chart, the Data Viewer will display it along with any new values that arrive. It also creates multiple charts if it notices more than one value stream in the incoming data. + +If you want to keep the data and work with it later, you can download it and save it to your computer or mobile device. + +## Charting value streams + +As an example, let's generate some data for two values. The first value `x` makes a line on the chart. The second value is the square of the first value `x**2`shifted by `5`. This second value will show a chart of a parabola. + +```blocks +for (let x = 0; x <= 10; x++) { + serial.writeValue("x", x) + serial.writeValue("y", (x - 5)**2) + basic.pause(1000) +} +``` + +![Charts of line and parabola](/static/mb/device/data-analysis/line-parabola.jpg) + +Since we used ``||serial:serial write value||`` for each value, there are two charts, one for the `x` stream and the other for the `y` stream. Also, the values shown in the console window are formatted as name value pairs: + +``` +x:0 +y:25 +x:1 +y:16 +... +``` + +## Charting by data lines + +Instead of writing multiple values separately, we can combine them in an array and write them together at once. Using the last example, let's combine each line and parabola value into an array. + +```blocks +for (let x = 0; x <= 10; x++) { + serial.writeNumbers([x, (x - 5) ** 2]) + basic.pause(1000) +} +``` + +![One chart of both line and parabola](/static/mb/device/data-analysis/line-parabola2.jpg) + +This time both values are shown on the same chart. We used ``||serial:serial write numbers||`` to send both values at the same time. Instead of being written as name value pairs, the values are combined into one line of comma separated values (CSV). The Data Viewer recognizes the values as one stream and puts multiple data lines on the same chart. The console shows the data in CSV format: + +``` +0,25 +1,16 +2,9 +3,4 +... +``` + +## Raw data + +The data in the console window appears exactly like it's written by your program. The data your program writes is called "raw" data. The Data Viewer reads the data and "cooks" it by deciding how to display it in a way that's useful to you. + +You can select and copy the raw data from the console and paste it into another program if you want to work with it outside of the MakeCode editor. Also, there is a copy button next to the console window that let's you easily copy the raw data with one click. + +![Copy button for console data](/static/mb/device/data-analysis/copy-button.gif) + +## Downloading your data + +You can download your data to save it to view in another program. Click the **Download** button above the chart view. + +![Download button highlighted](/static/mb/device/data-analysis/download-button.jpg) + +The data is formatted again and saved in file with a name like: + +``microbit-data-13-20-2018-14-18-15-0700.csv`` + +The filename contains the date and time when the data was downloaded. If you open the file in an editor you can see how the Data Viewer reformatted it from how it was in the console. + +### Download format + +The download file will contain your data as lines of CSV. The downloaded data from the first example will look something like this: + +``` +sep= +time (source1) x time (source1) y +0 0 0 25 +1.018 1 1.026 16 +2.049 2 2.045 9 +3.062 3 3.059 4 +4.064 4 4.074 1 +5.078 5 5.078 0 +6.115 6 6.112 1 +7.097 7 7.112 4 +8.131 8 8.128 9 +9.145 9 9.145 16 +10.148 10 10.16 25 +``` + +The first line says what character is used as the value separator. Characters other than a comma can be used as separators. The Data Viewer choose to use a `TAB` character. The next line contains the headings for the values. These are the names of each value when name value pairs are written to the console. Also, a time value (timestamp) is included for each value. The timestamp is the amount of time since the start of the program when the value was written. + +The remaining lines contain the data values and their timestamps. Each line has one occurrence of each value. So, for the example data above, each new `x` and `y` value is put together on the same line. + +### Loading into a spreadsheet + +Each line of data is placed into a row in the spreadsheet. The separators tell the spreadsheet which column the values go into. + +![CSV data in spreadsheet](/static/mb/device/data-analysis/spreadsheet-data.jpg) + +### Analyze in the spreadsheet + +Spreadsheets are powerful tools for analyzing and looking at relationships in your data. Most spreadsheet programs can do advanced charting too. Here's a chart of our example data. You'll notice that it looks similar to the chart displayed by the MakeCode editor. + +![Spreadsheet with chart](/static/mb/device/data-analysis/spreadsheet-chart.jpg) + +The spreadsheet knows how to take the headings from the download file and use them as labels for the individual data lines. diff --git a/docs/device/data-analysis/generating.md b/docs/device/data-analysis/generating.md new file mode 100644 index 00000000..058c7f1a --- /dev/null +++ b/docs/device/data-analysis/generating.md @@ -0,0 +1,111 @@ +# Generating data + +## Sensor values + +Most of the data you want to record probably comes from values measured by the sensors. The sensor values are read using ``||input:Input||`` blocks. They return to your program the current value measured by the sensor. + +```block +serial.writeValue("accelX", input.acceleration(Dimension.X)) +``` + +```block +serial.writeValue("heading", input.compassHeading()) +``` + +```block +serial.writeValue("light", input.lightLevel()) +``` + +```block +serial.writeValue("forceX", input.magneticForce(Dimension.X)) +``` + +## Pin data + +External sensors and devices connected to the board are read using the ``||pins:Pins||`` blocks. Here are some examples of reading the pins and reporting measurements from devices: + +### Soil moisture + +```block +let moisture = pins.analogReadPin(AnalogPin.P0) +serial.writeValue("moisture", moisture) +``` + +### Closed door detector + +```block +pins.onPulsed(DigitalPin.P0, PulseValue.Low, () => { + serial.writeValue("DoorClosed", 1) +}) +``` + +### I2C humidity sensor + +```block +let humidity = pins.i2cReadNumber(61, NumberFormat.Int8LE) +serial.writeValue("humidity", humidity) +``` + +## Human events + +Sometimes we want to track human interactions with a device. These events might be button presses, gestures, or pin touches. + +### Example: Button tracker + +Run this example in the editor and switch to the Data Viewer. Watch it plot your button presses like pulse events in the chart. + +```blocks +let buttonValue = 0 +basic.forever(() => { + if (input.buttonIsPressed(Button.A)) { + buttonValue = 1 + } else { + buttonValue = 0; + } + serial.writeValue("ButtonA", buttonValue) + basic.pause(200) +}) +``` + +Writing an additional value creates another stream that will appear in a separate chart. Adding and event for another button press, we can plot pulses on a second chart. + +```blocks +let buttonValue = 0 +basic.forever(() => { + if (input.buttonIsPressed(Button.A)) { + buttonValue = 1 + } else { + buttonValue = 0; + } + serial.writeValue("ButtonA", buttonValue) + if (input.buttonIsPressed(Button.B)) { + buttonValue = 1 + } else { + buttonValue = 0; + } + serial.writeValue("ButtonB", buttonValue) + basic.pause(200) +}) +``` + +## Time and timestamps + +A timestamp marks when you read a value or detect that an event happens. These are commonly written along with other data values as an additional data item. The data viewer will create timestamps for values it sees when you write them. If you are downloading and saving data from the Data Viewer, it creates the timestamps for you and you don't need to add them. + +If you need your own time values, you can make them from the **running time** of the board. + +```block +input.onGesture(Gesture.Shake, () => { + serial.writeValue("shaken", input.runningTime()) +}) +``` + +Also, you can write your own custom CSV with your own timestamp: + +```blocks +serial.writeLine("timestamp,temp,light") +basic.forever(() => { + serial.writeNumbers([input.runningTime(), input.temperature(), input.lightLevel()]) + basic.pause(30000) +}) +``` diff --git a/docs/device/data-analysis/led-plotting.md b/docs/device/data-analysis/led-plotting.md new file mode 100644 index 00000000..6fb0f629 --- /dev/null +++ b/docs/device/data-analysis/led-plotting.md @@ -0,0 +1,97 @@ +# Plotting data with LEDs + +To quickly see and record your data values, use the ``||led:plot bar graph||`` block. It will plot a value on the LED screen and write a number to console at the same time. + +```blocks +basic.forever(() => { + let i = 0 + while (i < 25) { + led.plotBarGraph(i, 25) + i += 2 + basic.pause(1000) + } +}) +``` + +Here's a plot of values from `1` to `25`: + +```sim +basic.forever(() => { + let i = 0 + while (i < 25) { + led.plotBarGraph(i, 25) + i += 2 + basic.pause(1000) + } +}) +``` + +## Plot range + +A number of LEDs will light up to show how much the value is related to the _high_ number in the second argument. The high number sets the _range_ of values to show. If the high number is set to `16` and you want to plot the value of `8`, then that value is half of the range. + +```block +led.plotBarGraph(8, 16) +``` +So, about half of the LEDs will light up to represent that number. + +```sim +basic.forever(() => { + basic.clearScreen() + basic.showString("8 up to 16") + basic.clearScreen() + basic.pause(500) + led.plotBarGraph(8, 16) + basic.pause(2000) +}) +``` + +## Autoranging + +If you don't know what the largest number to plot will be, then you can set the high number to `0`. This lets the largest value plotted be the range value. This is called _autoranging_. To see how it works, make an array of numbers and plot them. Put a large value in the middle of the array with smaller values before and after it. Watch as the same values are plotted with fewer lights after the largest number is plotted. + +```blocks +let values = [4,8,12,16,50,4,8,12,16] +for (let i = 0; i < values.length; i++) { + led.plotBarGraph(values[i], 0) + basic.pause(1000) +} +``` + +## Recording plotted values + +The ``||led:plot bar graph||`` also sends the number value it's plotting to the console. You can see the output in the Data Viewer. It charts the values and they appear as individual numbers in console. + +```blocks +input.onButtonPressed(Button.B, () => { + for (let i = 0; i < 25; i++) { + if (i % 2 > 0) { + led.plotBarGraph(0, 0) + } else { + led.plotBarGraph(i, 24) + } + basic.pause(500) + } +}) +``` + +The chart for the the plotted values from the example above: + +![Plot LEDs chart result](/static/mb/device/data-analysis/plot-bar-graph.jpg) + +The values appear in the console as just one number per line: + +``` +0 +2 +0 +4 +0 +6 +... +``` + +## See also + +[plot bar graph](/reference/led/plot-bar-graph) + diff --git a/docs/device/data-analysis/remote.md b/docs/device/data-analysis/remote.md new file mode 100644 index 00000000..4dd3ad28 --- /dev/null +++ b/docs/device/data-analysis/remote.md @@ -0,0 +1,161 @@ +# Remote data collection + +If you have more than one @boardname@ you can setup one of them to receive data sent by radio from other @boardname@s. Remote @boardname@s can take measurements and send them to a board that's connected by USB to a computer. The @boardname@ connected to the computer is the data recorder and writes the received data to the serial port. + +![Remote micro:bit sending](/static/mb/device/data-analysis/radio-zap.jpg) + +## Receiver @boardname@ + +Connect the @boardname@ to a computer with a USB cable. The data received over radio is sent to the computer with this connection using writes to the serial port. If you have the [Windows 10 MakeCode](https://www.microsoft.com/store/apps/9PJC7SV48LCX) app, you can view the received data with the [Data Viewer](./viewing) in the editor. Otherwise, you need a _serial terminal_ app or some other program that can read from the computer's serial port. + +The receiving @boardname@ sets a radio group number on which to listen for incoming messages. + +```block +radio.setGroup(99) +``` + +The receiver then waits to receive a packet (radio message) from the sender which contains the data to record. This happens inside an ``||radio:on received number||`` block. If the sending @boardname@ is measuring temperature at a remote location (somewhere else in the room maybe), the receiver will write the value received as a temperature measurement to the serial port. + +```blocks +radio.setGroup(99) +radio.onReceivedNumber(function (receivedNumber) { + basic.showNumber(receivedNumber) + serial.writeValue("TempCelsius", receivedNumber) +}) +``` + +## Remote sender @boardname@ + +A remote @boardname@ reads its measurement values and sends them to the same radio group as the receiver. + +```block +radio.setGroup(99) +``` +A typical measurement program might read a sensor value continuously. Depending on how much the values change, the measurement program could contain the read operation in a loop with a delay interval. In the example here, the delay is one minute between each read of a temperature value. The value is sent on the current radio group with ``||radio:radio send number||``. + +```blocks +let temperature = 0 +radio.setGroup(99) +basic.forever(() => { + temperature = input.temperature() + basic.showNumber(temperature) + radio.sendNumber(temperature) + basic.pause(60000) +}) +``` + +## Sending multiple values + +The remote @boardname@ in the previous example sent a single value which was temperature. The receiver understands that the incoming value is a temperature measurement. If you want the remote to also send the current amount of light measured, the receiver won't know that this other value isn't a temperature reading. + +The sender code is modified to use a value packet instead of just a number message. Here's the sender program sending both temperature and light values with ``||radio:radio send value||``. + +```blocks +let temperature = 0 +let lightLevel = 0 +radio.setGroup(99) +basic.forever(() => { + temperature = input.temperature() + radio.sendValue("temperature", temperature) + lightLevel = input.lightLevel() + radio.sendValue("light", lightLevel) + basic.pause(60000) +}) +``` + +Here's the program for the receiver to record both temperature and light: + +```blocks +radio.setGroup(99) +radio.onReceivedValue(function (name: string, value: number) { + basic.showString(name + ":") + basic.showNumber(value) + serial.writeValue(name, value) +}) +``` + +The receiver program uses just one ``||radio:on received number||`` event to record the values. The ``name`` and the ``value`` are parameters for the event block so both temperature and light values are received here. + +## Multiple remote stations + +For more complex data recording situations, you might need to measure sensor values from multiple locations at the same time. This means that there is more than one remote @boardname@ (station) measuring data. + +### Separate radio groups + +You could add another receiver @boardname@ and set it to a different radio group. This way you can copy the same programs to each sender and receiver and just change the radio group number for the matched boards. This solution, though, means you need an extra receiver board and another computer to record the data from the second station. + +### Station identifiers + +A different solution from using more than one radio group is to still have just one receiver on one group but make the different stations send identifiers with their values. + +This is done with ``||radio:radio set transmit serial number||`` which tells the radio to add the board's serial number to the packet it sends. The serial number is included with the ``name`` and ``value`` so the receiver can know what station it comes from. + +```block +radio.setTransmitSerialNumber(true) +``` + +The sender's program with the identifier added: + +```blocks +let temperature = 0 +radio.setGroup(99) +radio.setTransmitSerialNumber(true) +basic.forever(() => { + temperature = input.temperature() + basic.showNumber(temperature) + radio.sendValue("temperature", temperature) + basic.pause(60000) +}) +``` + +The program on the receiver board can use the serial number to make a name value pair that the [Data Viewer](./writing#name-value-pairs) can recognize: + +```blocks +let id = 0; +radio.setGroup(99) +radio.onReceivedValue(function (name: string, value: number) { + id = radio.receivedPacket(RadioPacketProperty.SerialNumber) + basic.showString(name + ":") + basic.showNumber(value) + serial.writeValue(id + "_" + name, value) +}) +``` + +The serial number, ``id``, is used as a _prefix_ for the ``name`` to identify which station the ``value`` came from. + +### Extended data recording + +If you're recording data to save on a computer for analysis or other uses outside of the MakeCode editor, you can use the ``||radio:radio write received packet to serial||`` block to format it for you. This function will format the data from the received packet into a [JSON](https://en.wikipedia.org/wiki/JSON) string and write it to the serial port, all in one operation. It's used just like this: + +```blocks +radio.onReceivedNumber(function (receivedNumber) { + radio.writeReceivedPacketToSerial(); +}); +``` + +The output to the serial port is a line of text with these name value pairs: + +* **t** - time: the time when the packet was sent +* **s** - serial: the serial number of the board that sent the packet (if enabled) +* **n** - name: the name for the data value from the string part of the packet +* **v** - value: the data from the number part of the packet + +It's sent in this format to the serial port: + +```json +{"t":3504,"s":1951284846,"n":"temperature","v":19} +{"t":3823,"s":1951284846,"n":"temperature","v":20} +{"t":4143,"s":1951284846,"n":"temperature","v":20} +{"t":4463,"s":1951284846,"n":"temperature","v":18} +{"t":4781,"s":1951284846,"n":"temperature","v":21} +{"t":5102,"s":1951284846,"n":"temperature","v":17} +``` + +## See also + +[radio](/reference/radio), [serial write value](/reference/serial/write-value), +[write received packet to serial](/reference/radio/write-received-packet-to-serial) + +```package +radio +``` diff --git a/docs/device/data-analysis/viewing.md b/docs/device/data-analysis/viewing.md new file mode 100644 index 00000000..b34aeed1 --- /dev/null +++ b/docs/device/data-analysis/viewing.md @@ -0,0 +1,50 @@ +# Viewing your data + +## Recording data + +When your code is writing data, and the editor is recording it, the **Show data** button is displayed in the simulator under the board and simulation controls. + +![Show data button](/static/mb/device/data-analysis/show-data.jpg) + +## Data view window + +If you press the **Show data** button, the editor will switch from the **Blocks** or **JavaScript** view to display a charting window and a text console. + +![Data chart and console](/static/mb/device/data-analysis/data-view.jpg) + +The console window under the graph will show the data in the format it was written. The chart is the visual representation of the values appearing on the console. + +## Time scroll + +The chart will display new data as it arrives. The chart will scroll with time to continue to display new values. + +![Data chart time scroll](/static/mb/device/data-analysis/time-scroll.gif) + +## Data view controls + +The chart window shows the data view controls on top of the chart. + +![Data view controls](/static/mb/device/data-analysis/data-view-controls.jpg) + +Here's what the controls do: + +**Return**: The return button switches the view back to previous code window (either Blocks or JavaScript). + +![Return button](/static/mb/device/data-analysis/return-button.jpg) + + +**Source**: Tells you where the data is coming from. If the code writing the data is running in the simulator, then the source is **Simulator**. If your code is running on the @boardname@ and connected by USB, the source is **@boardname@**. + +![Source label](/static/mb/device/data-analysis/source-label.jpg) + +**Pause**: The pause button will stop the display of new values and stop scrolling. When you resume, the chart starts again with the current value written. + +![Pause button](/static/mb/device/data-analysis/pause-button.jpg) + +**Resume**: The resume button will start displaying new values after the **Pause** button was pressed. + +![Resume button](/static/mb/device/data-analysis/resume-button.jpg) + +**Download**: The download button collects the data your code has written and downloads it to your computer as a file called something like _data-11-2018-23-00-0700.csv_. The numbers in the filename are the date and time when the file is created. The file may automatically open in an editor or spreadsheet if one of those programs is associated with _csv_ files. + +![Download button](/static/mb/device/data-analysis/download-button.jpg) diff --git a/docs/device/data-analysis/writing.md b/docs/device/data-analysis/writing.md new file mode 100644 index 00000000..2f0a444a --- /dev/null +++ b/docs/device/data-analysis/writing.md @@ -0,0 +1,187 @@ +# Writing data + +While you're using MakeCode, all data written by the [serial](/reference/serial) functions is recorded by the MakeCode editor. This happens when you try your code in the simulator and also when the @boardname@ is connected to a computer running the MakeCode app with USB. + +## Data formats + +The Data Viewer recognizes the format of your output and decides how to display it. If your data is a _stream_ of values it will plot them in the chart window and show them as text in the console. If your data is just text information, it appears only in the console window. + +You can write data in these format types: + +* Text ([string](/types/string)): `"Hello there!"` +* [Numbers](/types/number): `"354"` +* [Number arrays](/types/array): `"11,3,45,76"` +* Name value pairs: `"accelY:956"` + +## Text output + +Text is formed by simply using string data. The text data is not recorded in the console until a complete "line" of text is written. A line is just a string with some special characters (ones you don't actually see printed) at the end. You can write several strings, say: + +```block +serial.writeString("Hello "); +serial.writeString("from ") +serial.writeString("micro:bit") +``` + +This text, though, won't appear in the editor console until it becomes a complete line. If you follow the string writes with a line in your code, then the line will show up: + +```block +serial.writeString("Hello ") +serial.writeString("from ") +serial.writeString("micro:bit") +serial.writeLine("") +``` + +Text output is used mostly for messages since number formats have meaning when used for data analysis. + +The blank ``||serial:serial write line||`` adds the special line ending characters and turns the previous strings into a complete line of text. The whole line could simply be written out with just one function: + +```block +serial.writeLine("Hello from micro:bit") +``` + +When you're writing only text, it appears only in the console view and not in the chart window. This example writes four messages of text: + +```block +for (let i = 0; i < 4; i++) { + serial.writeLine("Hello from micro:bit " + i) +} +``` + +The four messages appear in the console window: + +![Console output](/static/mb/device/data-analysis/console-output.jpg) + +## Writing numbers + +In order for the Data Viewer to recognize a number as value and show in the chart, it has to be in a line by itself. So, numbers written individually won't be charted: + +```block +serial.writeNumber(1) +serial.writeNumber(2) +serial.writeNumber(3) +``` + +The numbers don't show up as single values because they appear in the output as a string: `"123"`. Also, the string doesn't form a complete line so it doesn't show up in the console window either. You could add a blank line to the numbers already written. If you did this, you would have just one value charted which is `123`: + +```block +serial.writeNumber(1) +serial.writeNumber(2) +serial.writeNumber(3) +serial.writeLine("") +``` + +Here's a way to chart the numbers individually: + +```block +for (let i = 0; i < 4; i++) { + serial.writeNumber(i) + serial.writeLine("") +} +``` + +It's much better though to use a value stream by writing the numbers as [name value pairs](#name-value-pairs). + +## Number arrays + +Numbers in arrays are displayed on separate data lines on the same chart. You can use ``||serial:serial write numbers||`` to write several values at once. The numbers are written to the output as _comma separated values_ (CSV). The array of numbers: + +```block +let values = [0,1,2,3,4]; +``` + +is written to the output in the form of a CSV string as: `"0,1,2,3,4"`. + +The Data Viewer recognizes this as an array of numbers and charts them on separate data lines: + +```block +let values = [0, 1, 2, 3, 4] +basic.forever(() => { + serial.writeNumbers(values) +}) +``` + +Data lines are shown for each value in the array: + +![Data lines on chart](/static/mb/device/data-analysis/data-lines.jpg) + +Give this example a try and watch the chart make a diamond pattern from two triangle waves: + +```blocks +let diamond: number[] = [] +basic.forever(() => { + for (let i = 0; i <= 10 - 1; i++) { + if (i < 5) { + diamond[0] = i + diamond[1] = 5 - i + } else { + diamond[0] = 10 - i + diamond[1] = i - 5 + } + serial.writeNumbers(diamond) + basic.pause(500) + } +}) +``` + +It will look like this: + +![Data pattern on chart](/static/mb/device/data-analysis/diamond-chart.jpg) + +## Name value pairs + +A very common way to report and record data is to use a _name value pair_ (NVP). A value is given a name so you know what it's for or where it came from. The name value pair is written with the format of _name:value_. There is a name, a colon character, and the value all together on one line. The line is written to the output and the Data Viewer recognizes it as a value and charts it as part of a value stream. The value stream is based on the name so any new values received with the same name are displayed on the chart that's showing values for that name. If more than one type of name value pair is found, the Data Viewer makes another value stream and shows those values on a different chart. + +If you want to report the values for both temperature and light, you can make separate name value pairs for them. The name value pairs are written using ``||serial:serial write value||``. This function writes the values to the output as lines in a format like this: + +``` +temp:17 +light:118 +temp:18 +light:117 +``` + +```blocks +basic.forever(() => { + serial.writeValue("temp", input.temperature()) + serial.writeValue("light", input.lightLevel()) + basic.pause(5000) +}) +``` + +Two charts display each value stream: + +![Two charts for each value type](/static/mb/device/data-analysis/two-value-chart.jpg) + +The console output shows the different name value pairs too: + +![Two values in console output](/static/mb/device/data-analysis/two-value-console.jpg) + +### Writing subvalues + +Similar to number arrays, different name value pairs are shown on one chart by using _subvalues_. You make a subvalue by combining a first-level name and a second-level name with a `'.'`: + +``"firstLevel.secondLevel"`` + +The first-level name is value name for the chart. The second-level name is the name for the actual value displayed. + +If you want to show all three values of acceleration on a single chart, then use each axis as a second-level (subvalue) name, ``"acceleration.x"``. + +```block +serial.writeValue("acceleration.x", input.acceleration(Dimension.X)) +``` + +To show the values for each axis together: + +```blocks +basic.forever(() => { + serial.writeValue("acceleration.x", input.acceleration(Dimension.X)) + serial.writeValue("acceleration.y", input.acceleration(Dimension.Y)) + serial.writeValue("acceleration.z", input.acceleration(Dimension.Z)) + basic.pause(500) +}) +``` + +Each subvalue ``'x'``, ``'y'``, and ``'z'`` is displayed on the chart named ``"acceleration"`` in the Data Viewer. + +![Three subvalues of acceleration in one chart](/static/mb/device/data-analysis/combined-values.jpg) diff --git a/docs/device/error-codes.md b/docs/device/error-codes.md new file mode 100644 index 00000000..c102e7db --- /dev/null +++ b/docs/device/error-codes.md @@ -0,0 +1,86 @@ +# Error codes + +Your @boardname@ may encounter a situation that prevents it from running your code. When this happens, a frowny face will appear on your @boardname@ screen (see picture) followed by an error number. These are called _panic_ codes. + +```sim +basic.forever(function() { + basic.showLeds(` + # . . . # + # # . # # + . . . . . + . # # # . + # . . . # + `) + basic.pause(1000) + basic.clearScreen() + basic.showString("020") +}) +``` + +## Board system errors + +The @boardname@ system errors range between **01** - **99**. For a full list of these codes, what they mean and what you can do to resolve them, visit the [micro:bit guide to error codes](https://support.microbit.org/en/support/solutions/articles/19000016969). + +* **10** (`MICROBIT_I2C_LOCKUP`): the @boardname@'s I2C bus is not working +* **20** (`MICROBIT_OOM`): there is no free memory on the @boardname@ +* **30** (`MICROBIT_HEAP_ERROR`): a problem in the heap space +* **40** (`MICROBIT_NULL_DEREFERENCE `): there was a NULL dereference, the @boardname@ tried to manage a invalid object pointer +* **42** (`MICROBIT_SYSTEM_ERROR`): there's an error condition in the @boardname@ system software +* **43** (`MICROBIT_NO_RADIO`): the @boardname@ can't enable the radio +* **50** (`MICROBIT_HARDWARE_UNAVAILABLE_ACC`): an error occurred with the micro:bit's accelerometer component +* **51** (`MICROBIT_HARDWARE_UNAVAILABLE_MAG`): an error occurred with the micro:bit's magnetometer component +* **90** (`MICROBIT_HARDWARE_CONFIGURATION_ERROR`): actual board hardware doesn't match the configuration description +* **98** (`MICROBIT_ASSERTION_FAILED`): assertion failed, the condition in an [assert](/reference/control/assert) was false + +## Memory errors + +Memory error codes range from **800** - **909**. + +### ~alert + +#### Report errors! + +If you ever see an error within the range of **800** - **909**, please report an issue at [GitHub](https://github.com/microsoft/pxt-microbit/issues) or on the [support](https://support.microbit.org/) page. + +### ~ + +### Garbage collector errors + +Error codes generated from the garbage collector. + +* **840**: Allocation pointer is null or invalid +* **841**: Garbage collection work queue error +* **843**: VTable entry is not free +* **844**: GC allocation failed for requested number of bytes +* **846**: Invalid allocation thread +* **848**: Allocation pointer beyond allocation header +* **849**: Allocation pointer is null + +### Program access errors + +* **901** (`PANIC_INVALID_BINARY_HEADER`): the type header for the object is not valid +* **902** (`PANIC_OUT_OF_BOUNDS`): the object data portion is greater than the length defined for it +* **903** (`PANIC_REF_DELETED`): an object reference was deleted and the object is no longer valid +* **904** (`PANIC_SIZE`): the object size doesn't match the size defined for the type +* **905** (`PANIC_INVALID_VTABLE`): an object vtable is invalid or not initialized +* **906** (`PANIC_INTERNAL_ERROR`): an internal resource error +* **907** (`PANIC_NO_SUCH_CONFIG`): the specified device resource is not present +* **909** (`PANIC_INVALID_ARGUMENT`): the argument value is out of range or the type or format is invalid + +## JavaScript runtime codes + +### Invalid cast codes + +When the static type of ``x`` is a class ``C``, the dynamic type of ``x`` isn’t ``C``, and you try to access a field on ``x`` or call a method on ``x``, you will get one of the following codes, depending on dynamic type of ``x``. + +* **980** (`PANIC_CAST_FROM_UNDEFINED`): when value of ``x`` is ``undefined`` +* **981** (`PANIC_CAST_FROM_BOOLEAN`): when value of ``x`` is ``true`` or ``false`` +* **982** (`PANIC_CAST_FROM_NUMBER`): when ``x`` is a ``number`` +* **983** (`PANIC_CAST_FROM_STRING`): when ``x`` is a ``string`` +* **984** (`PANIC_CAST_FROM_OBJECT`): when ``x`` is object of some type +* **985** (`PANIC_CAST_FROM_FUNCTION`): when ``x`` is a function +* **989** (`PANIC_CAST_FROM_NULL`): when ``x`` is ``null`` + +## See also + +[panic](/reference/control/panic), [assert](/reference/control/assert) diff --git a/docs/device/firmware.md b/docs/device/firmware.md new file mode 100644 index 00000000..4df44a35 --- /dev/null +++ b/docs/device/firmware.md @@ -0,0 +1,11 @@ +# Firmware + +Occasionally, changes and improvements to the system software (firmware) on the @boardname@ are needed. Updates to the firmware are made by the [micro:bit Education Foundation](http://microbit.org/about). + +## Do I need an update? + +Changes to the firmware don't happen very often. You probably don't need to update it for your @boardname@ if everything is working alright. Sometimes there's a problem with a certain part of the board not working right or it has trouble connecting to your computer or other device. In those cases, a firmware update may include a fix for the problem. + +## Getting a firmware update + +Instructions for updating the firmware are shown on the **[firmware upgrade](https://microbit.org/guide/firmware/)** support page at microbit.org. diff --git a/docs/device/foil-circuits.md b/docs/device/foil-circuits.md new file mode 100644 index 00000000..46b4ba3a --- /dev/null +++ b/docs/device/foil-circuits.md @@ -0,0 +1,52 @@ +# foil circuits + +The large holes at the bottom of the board are designed to attach alligator/crocodile clips +to create electrical circuit with other components. + +If you do not have crocodile clips at hand, you can use wires or even Aluminium foil to achieve the same result. +We will show you how to connect the @boardname@ to headphones using Aluminium foil and tape. + +https://youtu.be/mhXYyPuvpz0 + +## Materials + +* @boardname@ and battery pack (you can also power it via USB) +* a small piece of cardboard +* Aluminium foil +* tape + +## Assembly instructions + +Tape the @boardname@ and battery pack to the card board. Make sure to remove the batteries while you are building your circuit. + +![](/static/mb/device/croc-clips/microbitattached.jpg) + +Cut the thinnest strip of foil possible and roll it into a cable. You can also try to fold, whatever works for you. +Build two of those wires. + +![](/static/mb/device/croc-clips/foilcut.jpg) + +Place the foil wire on the ``GND`` pin and attach with a piece of tape. Press hard to get the best connection between +the foil and the pin board. Make sure the foil is not overlapping with the other pins! + +![](/static/mb/device/croc-clips/groundconnected.jpg) + +Place the second wire on the ``P0`` pin the same way. Make sure the wire does not overlap with the other pins! + +![](/static/mb/device/croc-clips/microbitconnect.jpg) + +Tape the headphone jack connector to the cardboard and roll the wire coming from ``GND`` around the metal base. +Make sure the wire does not touch the other metal rings on the jack. + +![](/static/mb/device/croc-clips/jackground.jpg) + +Tape the second wire on the head of the jack connector. + +![](/static/mb/device/croc-clips/jackconnect.jpg) + +![](/static/mb/device/croc-clips/foilcircuit.jpg) + + +## See also + +[@boardname@ pins](/device/pins) diff --git a/docs/device/mes-events.md b/docs/device/mes-events.md new file mode 100644 index 00000000..ae3457c6 --- /dev/null +++ b/docs/device/mes-events.md @@ -0,0 +1,145 @@ +# MES events + +Events and event values are generated in the Message Event Service (MES). Using MES events allows orderly interactions between the @boardname@ and external devices. These events are sent to and received from other wireless devices paired with the @boardname@ (phone, game pad, etc.). + +The event source IDs represent a device feature category. The event values are actions for, or notifications about a device feature. + +### ~hint + +**MES system sources** + +The MES events are defined in this source file of the **[microbit-dal](https://github.com/lancaster-university/microbit-dal)**: + +* [MESEvents.h](https://github.com/lancaster-university/microbit-dal/blob/master/inc/bluetooth/MESEvents.h) + +Also, you can see how the message bus works in the DAL core files: + +* [MemberFunctionCallback.cpp](https://github.com/lancaster-university/microbit-dal/blob/master/source/core/MemberFunctionCallback.cpp) +* [MicroBitListener.cpp](https://github.com/lancaster-university/microbit-dal/blob/master/source/core/MicroBitListener.cpp) + +### ~ + +## Raised events + +Events are generated, or _raised_, for by the @boardname@ for a paired device. These are raised using the [raise event](/reference/control/raise-event) function. + +```typescript-ignore +control.raiseEvent( + control.eventSourceId(EventBusSource.MES_REMOTE_CONTROL_ID), + control.eventValueId(EventBusValue.MES_REMOTE_CONTROL_EVT_VOLUMEUP) +); +``` + +### Remote control + +Events for using the @boardname@ as a remote control for audio play. + +#### MES_REMOTE_CONTROL_ID + +* `MES_REMOTE_CONTROL_EVT_PLAY`: Play the current track +* `MES_REMOTE_CONTROL_EVT_PAUSE`: Pause the current play in progress +* `MES_REMOTE_CONTROL_EVT_STOP`: Stop playing and reset to the beginning of the current track +* `MES_REMOTE_CONTROL_EVT_NEXTTRACK`: Skip to the next track +* `MES_REMOTE_CONTROL_EVT_PREVTRACK`: Skip to the previous track +* `MES_REMOTE_CONTROL_EVT_FORWARD`: Move forward in the current track +* `MES_REMOTE_CONTROL_EVT_REWIND`: Move backward in the current track +* `MES_REMOTE_CONTROL_EVT_VOLUMEUP`: Increase the play volume (audio) +* `MES_REMOTE_CONTROL_EVT_VOLUMEDOWN`: Decrease the play volume (audio) + +### Camera + +Control camera actions on a paired device. + +#### MES_CAMERA_ID + +* `MES_CAMERA_EVT_LAUNCH_PHOTO_MODE`: Turn on or set the camera to _photo_ mode. +* `MES_CAMERA_EVT_LAUNCH_VIDEO_MODE`: Turn on or set the camera to _video_ mode. +* `MES_CAMERA_EVT_TAKE_PHOTO`: Capture the picture in the camera view. +* `MES_CAMERA_EVT_START_VIDEO_CAPTURE`: Begin capturing video (start record) +* `MES_CAMERA_EVT_STOP_VIDEO_CAPTURE`: End capturing video (stop record) +* `MES_CAMERA_EVT_STOP_PHOTO_MODE`: Stop photo mode and return to the default mode +* `MES_CAMERA_EVT_STOP_VIDEO_MODE`: Stop video mode and return to the default mode +* `MES_CAMERA_EVT_TOGGLE_FRONT_REAR`: Switch from the front camera to rear camera or rear to front + +### Alerts + +Trigger standard alert notifications on a device. + +#### MES_ALERTS_ID + +* `MES_ALERT_EVT_DISPLAY_TOAST` +* `MES_ALERT_EVT_VIBRATE` +* `MES_ALERT_EVT_PLAY_SOUND` +* `MES_ALERT_EVT_PLAY_RINGTONE` +* `MES_ALERT_EVT_FIND_MY_PHONE` +* `MES_ALERT_EVT_ALARM1` +* `MES_ALERT_EVT_ALARM2` +* `MES_ALERT_EVT_ALARM3` +* `MES_ALERT_EVT_ALARM4` +* `MES_ALERT_EVT_ALARM5` +* `MES_ALERT_EVT_ALARM6` + +## Received events + +Events are received by the @boardname@ from a paired device. You capture these in an [on event](/reference/control/on-event) function. + +```typescript-ignore +control.onEvent(EventBusSource.MES_DEVICE_INFO_ID, EventBusValue.MES_DEVICE_INCOMING_CALL, () => { + +}) +``` + +### Carrier signal strength + +Signal strength to the subscribed carrier service. + +#### MES_SIGNAL_STRENGTH_ID + +* `MES_SIGNAL_STRENGTH_EVT_NO_BAR`: No service available or very low signal strength +* `MES_SIGNAL_STRENGTH_EVT_ONE_BAR`: Low signal strength +* `MES_SIGNAL_STRENGTH_EVT_TWO_BAR`: Medium signal strength +* `MES_SIGNAL_STRENGTH_EVT_THREE_BAR`: High signal strength +* `MES_SIGNAL_STRENGTH_EVT_FOUR_BAR`: Full signal strength + +### Device information + +Information about the current status of the device + +#### MES_DEVICE_INFO_ID + +* `MES_DEVICE_ORIENTATION_LANDSCAPE`: Display orientation is now in landscape +* `MES_DEVICE_ORIENTATION_PORTRAIT`: Display orientation is now in portrait +* `MES_DEVICE_GESTURE_NONE`: No gesture detected for device activation +* `MES_DEVICE_GESTURE_DEVICE_SHAKEN`: The device was shaken +* `MES_DEVICE_DISPLAY_OFF`: Device display is now turned off +* `MES_DEVICE_DISPLAY_ON`: Device display is now turned on +* `MES_DEVICE_INCOMING_CALL`: Currently receiving an incoming call +* `MES_DEVICE_INCOMING_MESSAGE`: A message was received (SMS or other messaging app) + +### Game pad controller + +Button events from a paired game pad. + +#### MES_DPAD_CONTROLLER_ID + +* `MES_DPAD_BUTTON_A_DOWN`: Button **A** pressed +* `MES_DPAD_BUTTON_A_UP`: Button **A** released +* `MES_DPAD_BUTTON_B_DOWN`: Button **B** pressed +* `MES_DPAD_BUTTON_B_UP`: Button **B** released +* `MES_DPAD_BUTTON_C_DOWN`: Button **C** pressed +* `MES_DPAD_BUTTON_C_UP`: Button **C** released +* `MES_DPAD_BUTTON_D_DOWN`: Button **D** pressed +* `MES_DPAD_BUTTON_D_UP`: Button **D** released +* `MES_DPAD_BUTTON_1_DOWN`: Button **1** pressed +* `MES_DPAD_BUTTON_1_UP`: Button **1** released +* `MES_DPAD_BUTTON_2_DOWN`: Button **2** pressed +* `MES_DPAD_BUTTON_2_UP`: Button **2** released +* `MES_DPAD_BUTTON_3_DOWN`: Button **3** pressed +* `MES_DPAD_BUTTON_3_UP`: Button **3** released +* `MES_DPAD_BUTTON_4_DOWN`: Button **4** pressed +* `MES_DPAD_BUTTON_4_UP`: Button **4** released + +## See also + +[raise event](/reference/control/raise-event), [on event](/reference/control/on-event), +[event value](/reference/control/event-value) diff --git a/docs/device/pins.md b/docs/device/pins.md new file mode 100644 index 00000000..14a97f7d --- /dev/null +++ b/docs/device/pins.md @@ -0,0 +1,64 @@ +# micro:bit pins + +The micro:bit pins + +![](/static/mb/device/pins-0.png) + +The micro:bit has 25 external connections on the edge connector of the board, which we refer to as ‘pins’. The edge connector is the grey area on the right side of the figure above. + +There are five large pins, that are also connected to holes in the board labelled: 0, 1, 2, 3V, and GND. And along the same edge, there are 20 small pins that you can use when plugging the micro:bit into an edge connector. + +## Large pins + +You can easily attach crocodile clips or 4mm banana plugs to the five large pins. + +The first three, labelled 0, 1 and 2 are flexible and can be used for many different things - which means they are often called ‘general purpose input and output’ (shortened to GPIO). These three pins also have the ability to read analogue voltages using something called an analogue-to-digital converter (ADC). They all have the same function: + +* **0**: GPIO (general purpose digital input and output) with analogue to digital convertor (ADC). +* **1**: GPIO with ADC +* **2**: GPIO with ADC + +The other two large pins (3V and GND) are very different! + +## ~hint + +Watch out! The pins labelled 3V and GND relate to the power supply of the board, and they should NEVER be connected together. +For details on the power, current and voltage limitations of the board, see [Power Supply](https://tech.microbit.org/hardware/powersupply/) + +## ~ + +*power input*: If the micro:bit is powered by USB or a battery, then you can use the 3V pin as a *power output* to power peripherals with. + +* **3V**: *3 volt power output* or *power input*. (1) *power output*: If the micro:bit is powered by USB or a battery, then you can use the 3V pin as a power output to power peripherals with; (2) *power input*: If the micro:bit is not being powered by USB or battery, you can use the 3V pin as a power input to power the micro:bit +* **GND**: attaches to ground in order to complete a circuit (required when using the 3V pin) + +If you hold the ‘GND’ pin with one hand, you can program the microbit to detect yourself touching the 0,1 or 2 pins with your other hand, giving you three more buttons to experiment with (you just used your body to complete an electrical circuit). + +## Small pins + +There are 20 small pins numbered sequentially from 3-22 (these pins are not labeled on the micro:bit, however, they are labelled in the picture above). + +Unlike the three large pins that are dedicated to being used for external connections, some of the small pins are shared with other components on the micro:bit board. For example, pin 3 is shared with some of the LEDs on the screen of the micro:bit, so if you are using the screen to scroll messages, you can’t use this pin as well. + +* **pin 3**: GPIO shared with LED Col 1 of the LED screen; can be used for ADC and digital I/O when the LED screen is turned off. +* **pin 4**: GPIO shared with LED Col 2 of the LED screen; can be used for ADC and digital I/O when the LED screen is turned off. +* **pin 5**: GPIO shared with Button A. This lets you trigger or detect a button "A" click externally. This pin has a pull-up resistor, which means that by default it is at voltage of 3V. To replace button A on the micro:bit with an external button, connect one end of the external button to pin 5 and the other end to GND. When the button is pressed, the voltage on pin 5 is pulled down to 0, which generates a button click event. +* **pin 6**: GPIO shared with LED Col 9 of the LED screen; can be used for digital I/O when the LED screen is turned off. +* **pin 7**: GPIO shared with LED Col 8 of the LED screen; can be used for digital I/O when the LED screen is turned off. +* **pin 8**: Dedicated GPIO, for sending and sensing digital signals. +* **pin 9**: GPIO shared with LED Col 7 of the LED screen; can be used for digital I/O when the LED screen is turned off. +* **pin 10**: GPIO shared with LED Col 3 of the LED screen; can be used for ADC and digital I/O when the LED screen is turned off. +* **pin 11**: GPIO shared with Button B. This lets you trigger or detect a button “B” click externally. +* **pin 12**: this GPIO pin has been reserved to provide support for accessibility. +* **pin 13**: GPIO that is conventionally used for the serial clock (SCK) signal of the 3-wire Serial Peripheral Interface (SPI) bus. +* **pin 14**: GPIO that is conventionally used for the Master In Slave Out (MISO) signal of the SPI bus. +* **pin 15**: GPIO that is conventionally used for the Master Out Slave In (MOSI) signal of the SPI bus. +* **pin 16**: Dedicated GPIO (conventionally also used for SPI ‘Chip Select’ function). +* **pins 17 and 18**: these pins are wired to the 3V supply, like the large ‘3V’ pad. +* **pins 19 and 20**: implement the clock signal (SCL) and data line (SDA) of the I2C bus communication protocol. With I2C, several devices can be connected on the same bus and send/read messages to and from the CPU. Internally, the accelerometer and the compass are connected to i2c. +* **pins 21 and 22**: these pins are wired to the GND pin and serve no other function + +## Connecting to the small pins + +It is recommended that an edge connector be acquired to connect to the small pins. More information on compatible edge connectors will be available later. + diff --git a/docs/device/reactive.md b/docs/device/reactive.md new file mode 100644 index 00000000..5f0c32b8 --- /dev/null +++ b/docs/device/reactive.md @@ -0,0 +1,172 @@ +# The micro:bit - a reactive system + +## Computing systems + +What sort of a *computing system* is the micro:bit? + +## ~hint + +There are different types of computing systems, to address different kinds of problems that arise in practice: *transaction processing systems* are used by banks to handle huge numbers of financial transactions by their customers; *distributed systems* make a set of networked computers appear as one big computer (like Google’s search engine); there are also *parallel systems*, such as graphic cards, which perform a huge number of primitive operations simultaneously, using a great number of small processing cores. + +## ~ + +The micro:bit is a *reactive system* – it reacts continuously to external events, such as a person pressing the **A** button of the micro:bit or shaking the device. The reaction to an event may be to perform a computation, update variables, and change the display. After the device reacts to an event, it is ready to react to the next one. If this sounds like a computer game, that’s because most computer games are reactive systems too! + +## Responsiveness + +We want reactive systems to be responsive, which means to react in a timely manner to events. For example, when you play a computer game, it’s frustrating if you press a button to make a character jump, but it doesn’t immediately jump. A delay in reacting, or lack of responsiveness, can be the difference between life and death, both in the real and virtual worlds. + +Let’s consider a simple example: you want to program your micro:bit to accurately count the number of times the **A** button has been pressed and continuously display the current count on the 5x5 [LED screen](/device/screen). Because the LED screen is small, we can only display one digit of a number at a time on it. The [show number](/reference/basic/show-number) function will scroll the digits of a number across the screen so you can read it. + +Let’s say that the current count is 42 and the number 42 is scrolling across the LED screen. This means there is some code executing to perform the scroll. So, what should happen if you press the **A** button during the scroll? It would be a bad idea to ignore the button press, so some code should record the occurrence of the button press. But we just said there already is code running in order to scroll the number 42! If we wait until the code scrolling the 42 has finished to look for a button press, we will miss the button press. We want to avoid this sort of unresponsiveness. + +## Concurrency + +To be responsive, a reactive system needs to be able to do several things at the same time (concurrently), just like you can. But the micro:bit only has one CPU for executing your program, which means it can only execute one program instruction at a time. It can, however, execute millions of instructions in a single second. This points the way to a solution. + +Think about how a motion picture projector works - it projects only 24 frames per second, yet this is good enough to provide the illusion of fluid motion on the screen. The micro:bit can execute millions of instructions per second, so it seems quite possible for the device to both to smoothly scroll the number 42 across the LED screen while looking for button presses and counting them. + +Let’s think about three sequences of instructions: + +* Sequence **S1**: contains the instructions (let’s say several hundred thousand or so) that scroll the number 42 across the LED screen. +* Sequence **S2**: contains a few instructions to check if button **A** is pressed. +* Sequence **S3**: contains a few instructions to increment a counter. + +In order to be responsive, we would like to *interrupt* the execution of sequence **S1** *periodically* to execute the sequence **S2**, which will check if button **A** is pressed, which looks like: + +![Execution sequence diagram: S1 and S2](/static/mb/device/reactive-0.png) + +The result is that it takes sequence **S1** a little longer to complete, due to the interruptions to execute sequence **S2**, but we are checking often enough to detect a press of button **A** . When **S2** detects a press of button **A**, then the sequence **S3** can be executed before **S1** resumes: + +![Execution sequence diagram: S1 and S2 with interrupt and one S3 slice](/static/mb/device/reactive-1.png) + +As we’ll soon see, there are other choices for how the sequences can be ordered to achieve the desired result. + +## The micro:bit scheduler and queuing up subprograms + +The micro:bit’s *scheduler* provides the capability to concurrently execute different code sequences, relieving us of a lot of low-level programming. In fact, scheduling is so useful that it is a part of every *operating system*! + +The first job of the scheduler is to allow multiple *subprograms* to be queued up for later execution. For our purposes, a subprogram is just a statement or sequence of statements in the context of a larger program. Consider the program below for counting button presses. + +```typescript +let count = 0 + +input.onButtonPressed(Button.A, () => { + count++; +}) + +basic.forever(() => { + basic.showNumber(count) +}) +``` + +The program above contains three statements that execute in order from top to bottom. +The first statement initializes the global variable `count` to zero. + +```typescript +// statement 1 +let count = 0 +``` + +The second statement informs the scheduler that on each and every event of the **A** button being pressed, a subprogram (called the event handler) should be queued for execution. The event handler code is contained within the braces `{...}`; it increments the global variable `count` by one. + +```typescript +// statement 1 +let count = 0 +// statement 2 +input.onButtonPressed(Button.A, () => { + count++; +}) +``` + +The third statement queues a `forever` loop for later execution by the scheduler; the body of this loop (also inside the braces `{...}`) displays the current value of global variable `count` on the LED screen. + +```typescript +// statement 1 +let count = 0 +// statement 2 +input.onButtonPressed(Button.A, () => { + count++; +}) +// statement 3 +basic.forever(() => { + basic.showNumber(count) +}) +``` + +There are no more statements after the execution of these three statements, but this is not the end of program execution! That’s because the program queued the `forever` loop for execution by the scheduler (and registered an event handler for presses of button A). + +The second job of the scheduler is to periodically interrupt execution to read (poll) the various inputs to the micro:bit (the buttons, pins, etc.) and fire off events (such as “button A pressed”). Recall that the firing of an event causes the event handler subprogram associated with that event to be queued for later execution. The scheduler uses a timer built into the micro:bit hardware to interrupt execution every 6 milliseconds and poll the inputs, which is more than fast enough to catch the quickest press of a button. + +## Cooperative passing of control + +How does the `forever` loop get to start execution? Furthermore, once the `forever` loop is running, how does any other subprogram (like the event handler that increments the count) ever get a chance to execute? + +The answer is “cooperation” and “passing”. Think of a football team doing a drill – there is one ball and each footballer gets to dribble the ball for a certain number of touches, after which they pass to another footballer. A footballer who never passes prevents all other footballers from dribbling. A cooperative footballer always passes to some other footballer after taking a few touches. + +If you hadn’t guessed already, a footballer represents subprogram and dribbling the ball corresponds to that subprogram executing. Only one subprogram gets to execute at a time, as there is only one ball (processor). Footballer Alice passing the ball to footballer Bob corresponds to stopping execution of Alice’s subprogram (and remembering where it stopped) and starting/resuming execution of Bob’s subprogram. + +We will call this “passing control of execution” rather than “passing the ball”. However, in the world of the micro:bit, the concurrently executing subprograms are not aware of each other, so they don’t actually pass control directly to one another. Rather they pass control of execution back to the scheduler and the scheduler determines the subprogram to pass control to next. The programmer inserts a call to the `pause` function to indicate a point in the subprogram where control of execution passes to the scheduler. Also, when a subprogram ends execution, control passes to the scheduler. + +Let’s take a look at the implementation of the `basic.forever` function to see an example of cooperative scheduling: + +```typescript +function forever_(body: () => void) { + control.inBackground(() => { + while(true) { + body() + basic.pause(20) + } + }) +} +``` + +The `forever` loop actually is a function that takes a subprogram (another function) as a parameter. The function uses the `control.inBackground` function of the micro:bit runtime to queue a `while true` loop for execution by the scheduler. The while loop has two statements. The first statement runs the subprogram represented by the `body` parameter. The second statement passes control to the scheduler (requesting to “sleep” for 20 milliseconds). + +Though the `while true` loop will repeatedly execute the body subprogram, between each execution of the body it will permit the scheduler to execute other subprograms. If the while loop did not contain the call to `pause`, then once control passed into the while loop, it would never pass back to the scheduler and no other subprogram would be able to execute (unless the body subprogram contained a call to `pause` itself). + +## Round-robin scheduling + +Now, we come to the third and final job of the scheduler, which is to determine which subprogram to pass control to next. The scheduler uses two queues to perform this task, the sleep queue and the run queue. The sleep queue contains the subprograms that have called the pause function and still have time left to sleep. The run queue contains all the non-sleeping subprograms, such as the event handlers queued by the firing of an event. + +The scheduler moves the subprogram that has just paused into the sleep queue and then removes the subprogram at the head of the run queue and resumes its execution. Once a subprogram’s sleep period is over, the scheduler moves it from the sleep queue to the back of the run queue. + +The property of such round-robin scheduling is that under the assumption that every subprogram periodically enters the sleep queue, then every subprogram will periodically get a chance to execute. + +## Putting it all together + +Let’s go back to the `count button presses` program and revisit its execution based on what we have learned about the micro:bit scheduler. As detailed before, the program executes three steps to: + +1. Initialize the global variable `count` to zero +2. Set up the event handler for each press of button **A** +3. Queue the forever loop to the run queue + +The program then ends execution and control passes back to the scheduler. Let’s assume the user has not pressed any buttons . The scheduler finds the `forever` loop in the run queue and passes control to it. The loop first calls `basic.showNumber(0)`. In the diagram below, we use “Show 0” to refer to the execution of this function: + +![Execution sequence diagram: display loop with increment and interrupt](/static/mb/device/reactive-3.png) + + +While "Show 0" (the blue sequence) is running, periodic interrupts by the scheduler (every 6 milliseconds) poll for button presses and queue an event handler for each press of button **A**. Let’s say that one button press takes place during this time, as shown above. This will cause an event handler (labelled “inc”) to be queued for later execution by the scheduler. Once the "Show 0" has completed, the loop then calls `basic.pause(20)` to put the forever loop to sleep for 20 milliseconds and give the scheduler an opportunity to run any newly queued event handler. Control passes to the “inc” event handler which will increment the global variable `count` from 0 to 1 and then complete, returning control to the scheduler. At some point, the `forever` loop moves from the sleep queue to the run queue; the `forever` loop then will resume and call `basic.showNumber(1)`. + +## Final thoughts + +Through this example, we have seen that the micro:bit scheduler enables you to create a program that is composed of concurrent subprograms. In essence, the programmer needs to only think about the concurrent subprograms cooperatively passing control back to the scheduler, making sure no subprogram hogs control (or “dribbles the ball without passing”) for too long. While a subprogram runs, the scheduler polls the buttons and other IO peripherals at a high frequency in order to fire off events and queue event handlers for later execution, but this is invisible to the programmer. + +As a result, you can easily add a new capability to the micro:bit by just adding a new subprogram. For example, if you want to add a reset feature to the counter program, all you need to do is add a new event handler for a press of button **B** that sets the global variable "count" to zero, as shown below: + +```typescript +let count = 0 + +input.onButtonPressed(Button.A, () => { + count = count + 1 +}) + +basic.forever(() => { + basic.showNumber(count) +}) + +input.onButtonPressed(Button.B, () => { + count = 0 +}) +``` + diff --git a/docs/device/screen.md b/docs/device/screen.md new file mode 100644 index 00000000..52f6812d --- /dev/null +++ b/docs/device/screen.md @@ -0,0 +1,97 @@ +# LED screen + +```sim + basic.showLeds(` + # . # . # + . # . # . + # . # . # + . # . # . + # . # . # + `); +``` + +The micro:bit LED screen has 25 red LED lights arranged in a 5X5 grid (5 LEDs across by 5 LEDs down). +In the screen above, we created a checkerboard pattern using the LEDs. + +## Which LED? + +You use `(x ,y)` coordinates to specify a particular LED in the grid; +where `x` is the horizontal position (0,1,2,3,4) and `y` is the vertical position +(0, 1, 2, 3, 4). + +To figure out the ``x``, ``y`` coordinates, position your micro:bit horizontally, like a credit card (see picture above). + +Here are the x, y coordinates for the LEDs in the 5X5 grid: + +`(0,0)` `(1,0)` `(2,0)` `(3,0)` `(4,0)` + +`(0,1)` `(1,1)` `(2,1)` `(3,1)` `(4,1)` + +`(0,2)` `(1,2)` `(2,2)` `(3,2)` `(4,2)` + +`(0,3)` `(1,3)` `(2,3)` `(3,3)` `(4,3)` + +`(0,4)` `(1,4)` `(2,4)` `(3,4)` `(4,4)` + +The x, y coordinates for the LED in the center of the grid are `(2,2)`. Starting from `(0,0)` count over 2 columns and then down 2 rows. + +## Check your understanding + +Which LEDs are turned on in the checkboard pattern above? + +## Row, column - 1 + +Since the row and column numbers start at 0, an easy way to figure out the (x,y) coordinates +is to subtract 1 from the row and column number (when counting from 1). +In other words, to specify the LED in the 4th column 5th row, subtract 1 from each number to get coordinates `(3,4)`. + +## Turn a LED on/off + +Use [plot](/reference/led/plot) and [unplot](/reference/led/unplot) to turn a LED on or off + +```blocks +led.plot(0,0); +led.plot(1,1); +basic.pause(1000); +led.unplot(0,0); +basic.pause(1000); +led.unplot(1,1); +``` + +## Is a LED on/off? + +Use the [point](/reference/led/point) function to find out if a LED is on or off. + +```blocks +if(led.point(0,0)) { +} +``` + +## Display images, strings and numbers + +Instead of turning individual LEDs on or off, as above, you can display an [image](/reference/images/image) directly to the screen or show text and numbers on screen using the [show number](/reference/basic/show-number) and [show string](/reference/basic/show-string) functions. + +## The display buffer + +The micro:bit runtime keeps a representation of the state of all 25 LEDS in memory. This state is known as the "display buffer" and controls which LEDs are on and which are off. The plot, unplot, and point functions access the display buffer directly. On the other hand, the functions that show an image, number, or string overwrite the buffer completely. To illustrate this, first try running this code sequence + +```blocks +basic.showString("d") +led.plot(0, 0) +``` + +You will see the letter "d" displayed as well as the LED in position `0,0` lit up. Now try reversing the order of the two statements above: + +```blocks +led.plot(0, 0) +basic.showString("d") +``` + +You will not see the LED at position `0,0` lit up because the `show string` function overwrites the whole display buffer. + +## Pins: P3, P4, P6, P7, P9, P10 + +These pins are coupled to the LED matrix display and also to the display's associated ambient light sensing mode. +To disable the display driver feature (which will automatically disable the light sensing feature) use the function [led.enable](/reference/led/enable). + +More information at http://tech.microbit.org/hardware/edgeconnector_ds/ . diff --git a/docs/device/serial.md b/docs/device/serial.md new file mode 100644 index 00000000..8f9499ac --- /dev/null +++ b/docs/device/serial.md @@ -0,0 +1,81 @@ +# Serial + +The [serial](/reference/serial) supports [serial communication](https://en.wikipedia.org/wiki/Serial_port) between the BBC micro:bit and another computer. Basically, this allows you to send data from the micro:bit to your own computer. This is very useful for debugging purposes: you can add `write line` statements in your code and see them display on your computer as the program executes. + +The code below shows a simple script that sends a line when the BBC micro:bit starts and another line each time the button ``A`` is pressed. + +```blocks +serial.writeLine("started...") +input.onButtonPressed(Button.A, () => { + serial.writeLine("A pressed") +}) +``` + +Data is also automatically streamed to serial by the ** bar graph** block +and picked up by the editor. This data can be streamed to the cloud as well. + +```blocks +basic.forever(() => { + led.plotBarGraph(input.acceleration(Dimension.X), 0); +}); +``` + +## How to read the micro:bit's serial output from your computer + +Unfortunately, using the serial library requires quite a bit of a setup. + +### ~ hint + +**Windows earlier than 10** + +If you are running a Windows version earlier than 10, you must [install a device driver](https://os.mbed.com/docs/latest/tutorials/windows-serial-driver.html) (for the computer to recognize the serial interface of the micro:bit). + +## ~ +Also, if you don't see the serial port as one of your computer's devices, you might need to [update the firmware](/device/firmware) on the @boardname@. Find the device name for the attached serial port in the following instructions for your operating system. + +### Windows > Tera Term + +* Install the terminal emulator [Tera Term](https://ttssh2.osdn.jp/index.html.en). At the time of this writing, the latest version is 4.88 and can be downloaded [from here](http://en.osdn.jp/frs/redir.php?m=jaist&f=%2Fttssh2%2F63767%2Fteraterm-4.88.exe). Follow the instructions from the installer. + +Once both the driver and the terminal emulator are installed, plug in the micro:bit and wait until the device is fully setup. Then, open TeraTerm. + +* Hit `File` > `New Connection` +* Check "Serial"; in the dropdown menu, pick the COM port that says "mbed Serial Port". Hit `Ok`. +* In the menus, hit `Setup` > `Serial Port` and set the baud rate to `115200`. + +You should be good. Feel free to hit `Setup` > `Save Setup` in the menus to erase the default configuration file with a new one so that you don't have to type in the settings again. + +Please note that Windows will assign you a different COM port if you plug in another micro:bit. If you're juggling between micro:bits, you'll have to change the COM port every time. + +### Windows > Putty + +If you prefer another terminal emulator (such as [PuTTY](http://www.putty.org/)), here are some instructions. + +* Open Windows's [Device Manager](https://windows.microsoft.com/en-us/windows/open-device-manager); expand the section called "Ports (COM & LPT)"; write down the com number for "mbed Serial Port" (e.g. COM14) +* Open PuTTY; on the main screen, use the following settings: Serial / COM14 / 115200. Replace COM14 with the COM port number you wrote down previously. Feel free to type in a name and hit "Save" to remember this configuration. + +![](/static/mb/serial-library-0.png) + +* (optional): in the "Terminal" section, check "implicit cr in every lf" + +![](/static/mb/serial-library-1.png) + +## Linux + +* Install the program `screen` if it is not already installed. +* Plug in the micro:bit. +* Open a terminal. +* Find which device node the micro:bit was assigned to with the command `ls /dev/ttyACM*`. +* If it was `/dev/ttyACM0`, type the command `screen /dev/ttyACM0 115200`. If it was some other device node, + use that one in the command instead. **Note:** You may need root access to run `screen` + successfully. You can probably use the command `sudo` like this: `sudo screen /dev/ttyACM0 115200`. +* To exit `screen`, type `Ctrl-A` `Ctrl-D`. + +Alternative programs include `minicom` and so on. + +## Mac OS + +* Plug in the micro:bit +* Open a terminal +* `ls /dev/cu.*` will return to you a list of serial devices; one of them will look like `/dev/cu.usbmodem1422` (the exact number depends on your computer) +* `screen /dev/cu.usbmodem1422 115200` will open up the micro:bit's serial output. To exit, hit `Ctrl-A` `Ctrl-D`. diff --git a/docs/device/servo.md b/docs/device/servo.md new file mode 100644 index 00000000..ea22180b --- /dev/null +++ b/docs/device/servo.md @@ -0,0 +1,144 @@ +# Equipping a microservo with Crocodile clips + +## ~ hint + +If you are conducting a class or group activity, you should consider preparing all servos ahead of time. + +## ~ + +## Using a microservo with the @boardname@ + +The @boardname@ provides just enough current to operate the SG90 microservo. This servo requires 3 connections: **GND**, **3V** and a logic **pin**. In this tutorial, we will equip the servo with crocodile clips to make it easier to use. However, you could also use a shield or crocodile clips with a male connector on one end to achieve the same result. + +### ~ hint + +To better understand how servos work and how they are controlled, take a few minutes to read this [Brief Guide to Servos](https://www.kitronik.co.uk/pdf/a-brief-guide-to-servos.pdf). + +### ~ + +## The easy way: Alligator/Crocodile Clip to Male Jumpers #hintconnection + +The easiest way to connect a servo to the @boardname@ is to use cables with an **Alligator/Crocodile clip** on one end +and a **Male jumper (pig tail)** on the other end. You can purchase bundles these cables from various electronic resellers or easily build some as shown here. + +https://youtu.be/XtzsydSTXEg + +### Materials + +* 1 Crocodile clip cable +* 1 male (pig tail) cable +* Cutting pliers or wire cutter +* 1 piece of heat shrink tubing and a lighter + +Simply cut the cables, strip them, twist the bare wires together, and cover the connection with some heat shrink tubing. + +### ~ hint + +It is very **important** to ensure a good connection between the 2 cables. If the connection is weak, the microservo will not receive enough current and it will not work. **If you have access to a soldering iron, we strongly recommend that you solder this connection.** + +### ~ + +## Direct connection + +You can also connect your crocodile clips directly to the servo. + +### Materials + +* Cutting pliers or wire cutter +* Tape (masking, duct tape, and/or packing tape) +* 3 crocodile clips, yellow, red and black. +* 1 micro servo 9g (SG90) + +### Step 1: Cut off the connector + +With the cutting pliers, cut off the dark plastic connector. + +![Cutting of the plastic connector from the servo cable](/static/mb/projects/inchworm/servo1.jpg) + +### Step 2: Strip the ends of the cables + +Using the pliers or a wire stripper, strip the plastic insulation from the cables. + +![Stripping the servo cable insulation](/static/mb/projects/inchworm/servotrim.jpg) + +### Step 3: Twist the wire strands together + +Twist the strands of bare wire at the ends of the servo cables together. + +![Strands of the servo wires twisted together](/static/mb/projects/inchworm/servo3.jpg) + +### Step 4: Crocodile clip + +Cut a crocodile cable in two and strip off the insulation. If it's possible, try to use cables with colors that match the cables on the servo! + +![Stripping insulation of a croc cable with cutting pliers](/static/mb/projects/inchworm/servo4.jpg) + +### Step 5: Thread the cable ends together + +Place the cables next to each other... + +![Bare wires place together before threading](/static/mb/projects/inchworm/servo5.jpg) + +... and thread them together. + +![Bare wires threaded together](/static/mb/projects/inchworm/servo6.jpg) + +### ~ hint + +It is very **important** to ensure that there is a good connection between the 2 cables. If the connection is weak, the microservo will not receive enough current and it will not work. **If you have access to a soldering iron, we strongly recommend soldering this connection.** + +### ~ + +### Step 6: Protect the connection + +Protect the connection with heat shrink tubing, electrical tape, or duct tape. + +![Wire connection protected with electrical tape](/static/mb/projects/inchworm/servo7.jpg) + +### Step 7: Repeat for all cables + +Repeat the same process until all cables are connected. + +![All three cables connected and taped](/static/mb/projects/inchworm/servo8.jpg) + +### Step 8: Testing! + +It's time to test and find out if your connections are all secure and that the servo will function **when the @boardname@ is powered by battery**. + +* Connect the microservo cables to these pins on the @boardname@: black to **GND**, red to **3V**, and the remaining cable to pin **0**. + +![Connect to the pins on the board](/static/mb/projects/inchworm/circuit1.jpg) + +## ~ hint + +When attaching the crocodile clips to the pins, don't be afraid to clamp on to the edge of the board with the clips. + +![Clippiing the cables to the edge of the board](/static/mb/projects/inchworm/circuit2.jpg) + +## ~ + +* Download the following code to your @boardname@. + +```blocks +basic.forever(() => { + pins.servoWritePin(AnalogPin.P0, pins.map( + input.acceleration(Dimension.X), + -512, + 512, + 0, + 180 + )) +}) +``` + +* Test with both power sources and make sure that the servo moves when you tilt the board: +>* Connected with USB. +>* Powered by batteries **only** and not connected with USB. + +## Calibrating + +Use the [servo calibrator](/projects/servo-calibrator) program to determine the best angles to use for your make. + +## Troubleshooting + +If your servo seems to stutter and remain stuck at a particular position, it means that it's not receiving enough power. This is probably due to a weak connection or low battery level. Make sure that each connection is good and check your batteries. diff --git a/docs/device/simulator.md b/docs/device/simulator.md new file mode 100644 index 00000000..f1f99a0d --- /dev/null +++ b/docs/device/simulator.md @@ -0,0 +1,25 @@ +# Simulator + +The JavaScript simulator allows you to test and execute most BBC micro:bit programs in the browser. +It allows you to emulate sensor data or user interactions. + +```sim +input.onButtonPressed(Button.A, () => { + basic.showString("A"); +}); +input.onButtonPressed(Button.B, () => { + basic.showString("B"); +}); +input.onPinPressed(TouchPin.P0, () => { + basic.showString("0"); +}); +input.onPinPressed(TouchPin.P1, () => { + basic.showString("1"); +}); +input.onPinPressed(TouchPin.P2, () => { + basic.showString("2"); +}); +input.temperature() +input.compassHeading() +input.lightLevel() +``` diff --git a/docs/device/usb.md b/docs/device/usb.md new file mode 100644 index 00000000..8376909d --- /dev/null +++ b/docs/device/usb.md @@ -0,0 +1,36 @@ +# Uploading programs to your @boardname@ + +Most of the time you'll be writing and testing your programs in the [simulator](/device/simulator). Once you've finished your program though, you can **compile** it and run it on your @boardname@. Transferring your program to the @boardname@ is as simple as saving a file to a drive on your computer. + +When you plug your @boardname@ into USB, a new drive is created with the **@drivename@** label. This is where you'll save your program. + +![](/static/mb/device/usb-thin.jpg) + +The basic steps are: + +1. Connect your @boardname@ to your computer with a USB cable. +2. Click **Download** to download the `.hex` file. +3. Move the `.hex` file from your computer onto the **@drivename@** drive. The next section has instructions for the browser that you're using. + +## How to transfer the program with your browser + +Here are instructions for different browsers on Windows and Mac computers. Choose the one you're using: + +### Windows browsers + +* [Microsoft Edge](/device/usb/windows-edge) +* [Internet Explorer](/device/usb/windows-ie) +* [Chrome](/device/usb/windows-chrome) +* [Firefox](/device/usb/windows-firefox) + +### Mac browsers + +* [Safari](/device/usb/mac-safari) +* [Chrome](/device/usb/mac-chrome) +* [Firefox](/device/usb/mac-firefox) + +## ~hint + +Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot). + +## ~ diff --git a/docs/device/usb/mac-chrome.md b/docs/device/usb/mac-chrome.md new file mode 100644 index 00000000..855582b9 --- /dev/null +++ b/docs/device/usb/mac-chrome.md @@ -0,0 +1,69 @@ +# Uploading from Chrome for Mac + +While you're writing and testing your programs, you'll mostly be [running them +in the simulator](/device/simulator), but once you've finished your program you +can **compile** it and run it on your micro:bit. + +The basic steps are: + +1. Connect your micro:bit to your computer via USB +2. Click **Download** and download the `.hex` file +3. Copy the `.hex` file from your computer onto the micro:bit drive + +## Requirements + +You need the following things to transfer and run a script on your micro:bit: + +* A-Male to Micro USB cable to connect your computer to your micro:bit. This is + the same cable that is commonly used to connect a smart phone to a computer. +* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later + +## Step 1: Connect your micro:bit to your computer + +First, connect the micro:bit: + +1. Connect the small end of the USB cable to the micro USB port on your micro:bit. + +2. Connect the other end of the USB cable to a USB port on your computer. + +Your computer should recognise your micro:bit as a new drive. On computers +running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac +it appears as a new drive under Devices. + +![](/static/mb/device/usb-osx-device.png) + +## Step 2: Download your program + +1. Open your project on @homeurl@ +2. Click **Download** +3. When prompted, choose to **save** the compiled file onto your computer. The + prompt will be different depending on which browser you are using, or + whether you are using a Windows computer or a Mac + +When you select **Download** in Chrome, the file will appear at the bottom of +the browser. Click on the small arrow and select **Show in Finder**. This will +show the file in your download folder. Drag and drop the file onto your +`MICROBIT` drive. + +![](/static/mb/device/usb-osx-chrome.png) + +## Step 3: Transfer the file to your micro:bit + +* Once you've found the folder containing your `.hex` file, drag and drop it + onto your `MICROBIT` drive +* The LED on the back of your micro:bit flashes during the transfer (which + should only take a few seconds). +* Once transferred, the code will run automatically on your micro:bit. To rerun + your program, press the reset button on the back of your micro:bit. The reset + button automatically runs the newest file on the micro:bit. + +By copying the script onto the `MICROBIT` drive, you have programmed it into the +flash memory on the micro:bit, which means even after you unplug the micro:bit, +your program will still run if the micro:bit is powered by battery. + + +## ~hint + +Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot). + +## ~ diff --git a/docs/device/usb/mac-firefox.md b/docs/device/usb/mac-firefox.md new file mode 100644 index 00000000..0aef7055 --- /dev/null +++ b/docs/device/usb/mac-firefox.md @@ -0,0 +1,71 @@ +# Uploading from Firefox for Mac + +While you're writing and testing your programs, you'll mostly be [running them +in the simulator](/device/simulator), but once you've finished your program you +can **compile** it and run it on your micro:bit. + +The basic steps are: + +1. Connect your micro:bit to your computer via USB +2. Click **Download** and download the `.hex` file +3. Copy the `.hex` file from your computer onto the micro:bit drive + +## Requirements + +You need the following things to transfer and run a script on your micro:bit: + +* A-Male to Micro USB cable to connect your computer to your micro:bit. This is + the same cable that is commonly used to connect a smart phone to a computer. +* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later + +## Step 1: Connect your micro:bit to your computer + +First, connect the micro:bit: + +1. Connect the small end of the USB cable to the micro USB port on your micro:bit. + +2. Connect the other end of the USB cable to a USB port on your computer. + +Your computer should recognise your micro:bit as a new drive. On computers +running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac +it appears as a new drive under Devices. + +![](/static/mb/device/usb-osx-device.png) + +## Step 2: Download your program + +1. Open your project on @homeurl@ +2. Click **Download** +3. When prompted, choose to **save** the compiled file onto your computer. The + prompt will be different depending on which browser you are using, or + whether you are using a Windows computer or a Mac + +A dialogue box will appear, asking whether you would like to open or save your +hex file. Select **Save file** and click **OK** and the file will then appear in +your downloads in the top right of your browser. Right click on the file and +click on **Show in Finder** and the file will appear in your downloads folder. +Select the file and drag and drop it onto your `MICROBIT` drive. + +![](/static/mb/device/usb-osx-firefox-1.jpg) + +![](/static/mb/device/usb-osx-firefox-2.png) + +## Step 3: Transfer the file to your micro:bit + +* Once you've found the folder containing your `.hex` file, drag and drop it + onto your `MICROBIT` drive +* The LED on the back of your micro:bit flashes during the transfer (which + should only take a few seconds). +* Once transferred, the code will run automatically on your micro:bit. To rerun + your program, press the reset button on the back of your micro:bit. The reset + button automatically runs the newest file on the micro:bit. + +By copying the script onto the `MICROBIT` drive, you have programmed it into the +flash memory on the micro:bit, which means even after you unplug the micro:bit, +your program will still run if the micro:bit is powered by battery. + +## ~hint + +Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot). + +## ~ diff --git a/docs/device/usb/mac-safari.md b/docs/device/usb/mac-safari.md new file mode 100644 index 00000000..e23fb433 --- /dev/null +++ b/docs/device/usb/mac-safari.md @@ -0,0 +1,68 @@ +# Uploading from Safari for Mac + +While you're writing and testing your programs, you'll mostly be [running them +in the simulator](/device/simulator), but once you've finished your program you +can **compile** it and run it on your micro:bit. + +The basic steps are: + +1. Connect your micro:bit to your computer via USB +2. Click **Download** and download the `.hex` file +3. Copy the `.hex` file from your computer onto the micro:bit drive + +## Requirements + +You need the following things to transfer and run a script on your micro:bit: + +* A-Male to Micro USB cable to connect your computer to your micro:bit. This is + the same cable that is commonly used to connect a smart phone to a computer. +* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later + +## Step 1: Connect your micro:bit to your computer + +First, connect the micro:bit: + +1. Connect the small end of the USB cable to the micro USB port on your micro:bit. + +2. Connect the other end of the USB cable to a USB port on your computer. + +Your computer should recognise your micro:bit as a new drive. On computers +running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac +it appears as a new drive under Devices. + +![](/static/mb/device/usb-osx-device.png) + +## Step 2: Download your program + +1. Open your project on @homeurl@ +2. Click **Download** +3. When prompted, choose to **save** the compiled file onto your computer. The + prompt will be different depending on which browser you are using, or + whether you are using a Windows computer or a Mac + +When you select **Download** in Safari a file called `Unknown` will be +downloaded into your Downloads folder. Open your Downloads folder and drag and +drop the file onto your `MICROBIT` drive, under Devices: + +![](/static/mb/device/usb-osx-dnd.png) + +## Step 3: Transfer the file to your micro:bit + +* Once you've found the folder containing your `.hex` file, drag and drop it + onto your `MICROBIT` drive +* The LED on the back of your micro:bit flashes during the transfer (which + should only take a few seconds). +* Once transferred, the code will run automatically on your micro:bit. To rerun + your program, press the reset button on the back of your micro:bit. The reset + button automatically runs the newest file on the micro:bit. + +By copying the script onto the `MICROBIT` drive, you have programmed it into the +flash memory on the micro:bit, which means even after you unplug the micro:bit, +your program will still run if the micro:bit is powered by battery. + + +## ~hint + +Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot). + +## ~ diff --git a/docs/device/usb/troubleshoot.md b/docs/device/usb/troubleshoot.md new file mode 100644 index 00000000..57ae3a8f --- /dev/null +++ b/docs/device/usb/troubleshoot.md @@ -0,0 +1,24 @@ +# Troubleshooting Transfer + +You can’t drag and drop more than one hex file at once onto your micro:bit. If +you try to drag and drop a second hex file onto your micro:bit before the first +file has finished downloading, then the second file may fail in different ways. + +When the first program has been written to the micro:bit, the drive will +disengage. If you drag and drop a second file at this point it may not find the +drive and the second write will fail. + +The errors may look like this: + +**Windows** + +![](/static/mb/device/usb-windows-copy-file-error.jpg) + +**Mac** + +![](/static/mb/device/usb-osx-copy-file-error.png) + +Or it may appear that there are two hex files on your micro:bit so the micro:bit +won’t be able to run multiple files. To rectify this, unplug your micro:bit and +plug it in again. Make sure that your micro:bit appears as `MICROBIT` and not +`MAINTENANCE`. diff --git a/docs/device/usb/webusb.md b/docs/device/usb/webusb.md new file mode 100644 index 00000000..1c9382ad --- /dev/null +++ b/docs/device/usb/webusb.md @@ -0,0 +1,44 @@ +# WebUSB + +[WebUSB](https://wicg.github.io/webusb/) is an emerging web standard that allows to access @boardname@ from web pages. +It allows for a **one-click download** without installing any additional app or software! It also allows to receive data from the @boardname@. + +## Support + +* Chrome 79+ browser for Android, Chrome OS, Linux, macOS and Windows 10. +* Microsoft Edge 79+ browser for Android, Chrome OS, Linux, macOS and Windows 10. + +## Prepare your @boardname@ + +Make sure that your @boardname@ is running version **0249** or above of the firmware. Upgrading is as easy as dragging a file and it takes a few seconds to get it done. + +* [Check out the instructions to check and upgrade your @boardname@.](/device/usb/webusb/troubleshoot) + +## Pair your @boardname@ + +Here are the steps on the supported browsers: + +* connect your @boardname@ to your computer with the microUSB cable +* open a project +* click the triple dot icon on the **Download** button and click **Pair device** +* click on the **Pair device** button and select **Calliope mini** or **DAPLink CMSIS-DAP** from the list. + +If you don't see any devices in the list and @boardname@ has the right firmware (**0249** or above), you can create a [support ticket](https://support.microbit.org/support/tickets/new) to notify the Micro:bit Foundation of the problem. Skip the rest of these steps. + +## Unpair your @boardname@ #unpair + +You will need to unpair your device from the editor to disable WebUSB. + +* Click on the **lock** icon in the address bar +* Uncheck each **Calliope mini** or **DAPLink CMSIS-DAP** device +* Reload the page + +![](/static/webusb/unpair.gif) + +## One-click Download + +Once your @boardname@ is paired, MakeCode will use WebUSB to transfer the code without having to drag and drop. Happy coding! + +## Console output + +MakeCode will be able to "listen" to your @boardname@ and display the console output. diff --git a/docs/device/usb/webusb/troubleshoot.md b/docs/device/usb/webusb/troubleshoot.md new file mode 100644 index 00000000..029078c0 --- /dev/null +++ b/docs/device/usb/webusb/troubleshoot.md @@ -0,0 +1,69 @@ +# Troubleshooting downloads with WebUSB + +### ~ avatar + +Having issues pairing your @boardname@ with [WebUSB](/device/usb/webusb)? Let's try to figure out why! + +### ~ + +## Step 1: Check your cable + +Make sure that your @boardname@ is connected to your computer with a micro USB cable. You should see a **MICROBIT** drive appear in Windows Explorer when it's connected. + +![MICROBIT drive](/static/mb/device/windows-microbit-drive.png) + +**If you can see the MICROBIT drive go to step 2**. + +If you can't see the drive: +* Make sure that the USB cable is working. +>Does the cable work on another computer? If not, find a different cable to use. Some cables may only provide a power connection and don't actually transfer data. +* Try another USB port on your computer. + +Is the cable good but you still can't see the **MICROBIT** drive? Hmm, you might have a problem with your @boardname@. Try the additional steps described in the [fault finding](https://support.microbit.org/support/solutions/articles/19000024000-fault-finding-with-a-micro-bit) page at microbit.org. If this doesn't help, you can create a [support ticket](https://support.microbit.org/support/tickets/new) to notify the Micro:bit Foundation of the problem. **Skip the rest of these steps**. + +## Step 2: Check your firmware version + +It's possible that the firmware version on the @boardname@ needs an update. Let's check: + +1. Go to the **MICROBIT** drive. +2. Open the **DETAILS.TXT** file.
+![](/static/mb/device/mb-drive-contents.jpg)
+3. Look for a line in the file that says the version number. It should say **Version: \.\.\.** +![](/static/mb/device/details-txt.jpg) + or **Interface Version: \.\.\.** + ![](/static/mb/device/details-243.png) +
+ +If the version is **0234**, **0241**, **0243** you **NEED** to update the [firmware](/device/firmware) on your @boardname@. Go to **Step 3** and follow the upgrade instructions. + +If the version is **0249**, **0250** or higher, **you have the right firmware** go to step **4**. + +## Step 3: Upgrade the firmware + +1. Put your @boardname@ into **MAINTENANCE Mode**. To do this, unplug the USB cable from the @boardname@ and then re-connect the USB cable while you hold down the reset button. Once you insert the cable, you can release the reset button. You should now see a **MAINTENANCE** drive instead of the **MICROBIT** drive like before. Also, a yellow LED light will stay on next to the reset button. +![MAINTENANCE gesture](/static/mb/device/maintenance.gif) +2. **[Download the firmware .hex file](https://microbit.org/guide/firmware/)** +3. Drag and drop that file onto the **MAINTENANCE** drive. +4. The yellow LED will flash while the `HEX` file is copying. When the copy finishes, the LED will go off and the @boardname@ resets. The **MAINTENANCE** drive now changes back to **MICROBIT**. +5. The upgrade is complete! You can open the **DETAILS.TXT** file to check and see that the firmware version changed to the match the version of the `HEX` file you copied. + +### ~hint + +If you want to know more about connecting the board, MAINTENANCE Mode, and upgrading the firmware, read about it in the [Firmware guide](https://microbit.org/guide/firmware/). + +### ~ + +## Step 4: Check your browser version + +WebUSB is a fairly new feature and may require you to update your browser. Check that your browser version matches one of these: + +* Chrome 65+ for Android, Chrome OS, Linux, macOS and Windows 10. + + +## Step 5: Pair device + +Once you've updated the firmware, open the **Chrome Browser**, go to the editor and click on **Pair Device** in the gearwheel menu. +See [WebUSB](/device/usb/webusb) for pairing instructions. + +Enjoy fast downloads! + diff --git a/docs/device/usb/windows-chrome.md b/docs/device/usb/windows-chrome.md new file mode 100644 index 00000000..156830f4 --- /dev/null +++ b/docs/device/usb/windows-chrome.md @@ -0,0 +1,92 @@ +# Uploading from Chrome for Windows + +## ~ hint + +Starting with Chrome 65 on Windows 10, +you can use **WebUSB** to download with one-click. +[Learn more about WebUSB...](/device/usb/webusb). + +## ~ + +While you're writing and testing your programs, you'll mostly be [running them +in the simulator](/device/simulator), but once you've finished your program you +can **compile** it and run it on your micro:bit. + +The basic steps are: + +1. Connect your micro:bit to your computer via USB +2. Click **Download** and download the `.hex` file +3. Copy the `.hex` file from your computer onto the micro:bit drive + +## Requirements + +You need the following things to transfer and run a script on your micro:bit: + +* A-Male to Micro USB cable to connect your computer to your micro:bit. This is + the same cable that is commonly used to connect a smart phone to a computer. +* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later + +## Step 1: Connect your micro:bit to your computer + +First, connect the micro:bit: + +1. Connect the small end of the USB cable to the micro USB port on your micro:bit. + +2. Connect the other end of the USB cable to a USB port on your computer. + +Your computer should recognise your micro:bit as a new drive. On computers +running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac +it appears as a new drive under Devices. + +![](/static/mb/device/usb-windows-device.jpg) + +## Step 2 (optional): Configure Chrome to ask where to save the file + +You only need to do this once. + +1. Open the **Settings** for Chrome. +2. Click **Advanced** at the bottom of the page. +3. Find the **Downloads** settings. +4. Enable the setting **Ask where to save each file before downloading**. + +## Step 3: Download your program + +1. Open your project on @homeurl@ +2. Click **Download** +3. If you did Step 2 above, Chrome will ask where to save the `.hex` file, + so save it into the `MICROBIT` drive. + Otherwise, continue with one of the options in Step 4 below. + +## Step 4: Transfer the file to your micro:bit + +If the file was saved onto your computer, you will need to transfer it to the micro:bit. + +## Manual transfer + +Your `.hex` file (created in Step 3 above) appears as a download at the bottom of the browser. +Click on the arrow next to the name of the file and then click **Show in folder**. + +![](/static/mb/device/usb-windows-chrome.png) + +In File Explorer, drag and drop the `.hex` file from the download folder onto the `MICROBIT` drive. + +Alternatively, right-click on the hex file, choose **Send to**, and then **MICROBIT**. + +![](/static/mb/device/usb-windows-sendto.jpg) + +## Step 5: After transferring the file + +* The LED on the back of your micro:bit flashes during the transfer (which + should only take a few seconds). +* Once transferred, the code will run automatically on your micro:bit. To rerun + your program, press the reset button on the back of your micro:bit. The reset + button automatically runs the newest file on the micro:bit. +* By copying the script onto the `MICROBIT` drive, you have programmed it into the + flash memory on the micro:bit, which means even after you unplug the micro:bit, + your program will still run if the micro:bit is powered by battery. + +## ~hint + +Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot). + +## ~ diff --git a/docs/device/usb/windows-edge.md b/docs/device/usb/windows-edge.md new file mode 100644 index 00000000..cd838b87 --- /dev/null +++ b/docs/device/usb/windows-edge.md @@ -0,0 +1,72 @@ +# Uploading from Microsoft Edge on Windows + +How to compile, transfer, and run a program on your micro:bit on **Microsoft Edge**. + +While you're writing and testing your programs, you'll mostly be [running them +in the simulator](/device/simulator), but once you've finished your program you +can **compile** it and run it on your micro:bit. + +The basic steps are: + +1. Connect your @boardname@ to your computer via USB +2. Click **Download** to download the `.hex` file +3. Click the **Save As** button in the bottom bar and save the `.hex` file into the MICROBIT drive + +## Requirements + +You need the following things to transfer and run a script on your micro:bit: + +* A-Male to Micro USB cable to connect your computer to your micro:bit. This is + the same cable that is commonly used to connect a smart phone to a computer. +* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later + +## Step 1: Connect your micro:bit to your computer + +First, connect the micro:bit: + +1. Connect the small end of the USB cable to the micro USB port on your micro:bit. + +2. Connect the other end of the USB cable to a USB port on your computer. + +Your computer should recognise your micro:bit as a new drive. On computers +running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac +it appears as a new drive under Devices. + +![](/static/mb/device/usb-windows-device.jpg) + +## Step 2: Download your program + +1. Open your project on @homeurl@ +2. Click **Download** +3. When prompted, choose to **save** the compiled file onto your computer. The + prompt will be different depending on which browser you are using, or + whether you are using a Windows computer or a Mac + +A message will appear at the bottom of the browser asking what you want to do +with the file. + +4. Click **Save As** + +![Save download file dialog](/static/mb/device/usb/save-as-edge.gif) + +5. Save the ``.hex`` file into the **MICROBIT** drive + +![Save hex file to MICROBIT drive](/static/mb/device/usb/save-as-windows.png) + +## Step 3: Transfer the file to your micro:bit + +* The LED on the back of your micro:bit flashes during the transfer (which + should only take a few seconds). +* Once transferred, the code will run automatically on your @boardname@. To rerun + your program, press the reset button on the back of your @boardname@. The reset + button automatically runs the newest file on the micro:bit. + +By copying the script onto the `MICROBIT` drive, you have programmed it into the +flash memory on the micro:bit, which means even after you unplug the micro:bit, +your program will still run if the micro:bit is powered by battery. + +## ~hint + +Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot). + +## ~ diff --git a/docs/device/usb/windows-firefox.md b/docs/device/usb/windows-firefox.md new file mode 100644 index 00000000..72ce4976 --- /dev/null +++ b/docs/device/usb/windows-firefox.md @@ -0,0 +1,71 @@ +# Uploading from Firefox on Windows + +How to compile, transfer, and run a program on your micro:bit on **Firefox for Windows**. + +While you're writing and testing your programs, you'll mostly be [running them +in the simulator](/device/simulator), but once you've finished your program you +can **compile** it and run it on your micro:bit. + +The basic steps are: + +1. Connect your micro:bit to your computer via USB +2. Click **Download** and download the `.hex` file +3. Click the **Save As** button and save the `.hex` file into the MICROBIT drive + +## Requirements + +You need the following things to transfer and run a script on your micro:bit: + +* A-Male to Micro USB cable to connect your computer to your micro:bit. This is + the same cable that is commonly used to connect a smart phone to a computer. +* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later + +## Step 1: Connect your micro:bit to your computer + +First, connect the micro:bit: + +1. Connect the small end of the USB cable to the micro USB port on your micro:bit. + +2. Connect the other end of the USB cable to a USB port on your computer. + +Your computer should recognise your micro:bit as a new drive. On computers +running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac +it appears as a new drive under Devices. + +![](/static/mb/device/usb-windows-device.jpg) + +## Step 2: Download your program + +1. Open your project on @homeurl@. +2. Click **Download**. +3. When prompted, choose to **save** the compiled file onto your computer. The + prompt will be different depending on which browser you are using, or + whether you are using a Windows computer or a Mac. + +![Save download file dialog](/static/mb/device/usb/save-file-firefox.gif) + +A window may appear asking whether you want to save or open the `.hex` file. If it doesn't, go click on the downloads icon at the top of the browser. + +![Save file prompt](/static/mb/device/usb/open-file-firefox.png) + +Click the folder icon and copy the file from the list of downloads to the **MICROBIT** drive. + +![Move hex file to MICROBIT drive](/static/mb/device/usb/move-hex-file-firefox.png) + +## Step 3: Transfer the file to your micro:bit + +* The LED on the back of your micro:bit flashes during the transfer (which + should only take a few seconds). +* Once transferred, the code will run automatically on your @boardname@. To rerun + your program, press the reset button on the back of your @boardname@. The reset + button automatically runs the newest file on the micro:bit. + +By copying the script onto the `MICROBIT` drive, you have programmed it into the +flash memory on the micro:bit, which means even after you unplug the micro:bit, +your program will still run if the micro:bit is powered by battery. + +## ~hint + +Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot). + +## ~ diff --git a/docs/device/usb/windows-ie.md b/docs/device/usb/windows-ie.md new file mode 100644 index 00000000..fcfa5428 --- /dev/null +++ b/docs/device/usb/windows-ie.md @@ -0,0 +1,70 @@ +# Uploading from Internet Explorer on Windows + +While you're writing and testing your programs, you'll mostly be [running them +in the simulator](/device/simulator), but once you've finished your program you +can **compile** it and run it on your micro:bit. + +The basic steps are: + +1. Connect your micro:bit to your computer via USB +2. Click **Download** and download the `.hex` file +3. **Click the down arrow next to Save** in the bottom bar and select **Save As**. +4. In the save dialog, save the `.hex` file into the MICROBIT drive + +## Requirements + +You need the following things to transfer and run a script on your micro:bit: + +* A-Male to Micro USB cable to connect your computer to your micro:bit. This is + the same cable that is commonly used to connect a smart phone to a computer. +* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later + +## Step 1: Connect your micro:bit to your computer + +First, connect the micro:bit: + +1. Connect the small end of the USB cable to the micro USB port on your micro:bit. + +2. Connect the other end of the USB cable to a USB port on your computer. + +Your computer should recognise your micro:bit as a new drive. On computers +running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac +it appears as a new drive under Devices. + +![](/static/mb/device/usb-windows-device.jpg) + +## Step 2: Download your program + +1. Open your project on @homeurl@ +2. Click **Download** +3. When prompted, choose to **save** the compiled file onto your computer. The + prompt will be different depending on which browser you are using, or + whether you are using a Windows computer or a Mac + +A message will appear at the bottom of the browser asking what you want to do +with the file. Click **on the arrow next to Save** and click **Save As** + +![Save download file dialog](/static/mb/device/usb/save-as-ie.gif) + +In the save dialog, save as the ``.hex`` file to the MICROBIT drive. + +![Save hex file to MICROBIT drive](/static/mb/device/usb/save-as-windows.png) + +## Step 3: Transfer the file to your micro:bit + +* The LED on the back of your micro:bit flashes during the transfer (which + should only take a few seconds). +* Once transferred, the code will run automatically on your @boardname@. To rerun + your program, press the reset button on the back of your @boardname@. The reset + button automatically runs the newest file on the micro:bit. + +By copying the script onto the `MICROBIT` drive, you have programmed it into the +flash memory on the micro:bit, which means even after you unplug the micro:bit, +your program will still run if the micro:bit is powered by battery. + + +## ~hint + +Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot). + +## ~ diff --git a/docs/device/windows-app/troubleshoot.md b/docs/device/windows-app/troubleshoot.md new file mode 100644 index 00000000..7a596367 --- /dev/null +++ b/docs/device/windows-app/troubleshoot.md @@ -0,0 +1,65 @@ +# Troubleshooting downloads from the Windows 10 App + +### ~ avatar + +Is the [Windows App](https://www.microsoft.com/store/apps/9pjc7sv48lcx) not downloading your program properly? Let's try to figure out why! + +### ~ + +## Step 1: Check your cable + +Make sure that your @boardname@ is connected to your computer with a micro USB cable. You should see a **MICROBIT** drive appear in Windows Explorer when it's connected. + +![MICROBIT drive](/static/mb/device/windows-microbit-drive.png) + +**If you can see the MICROBIT drive go to step 2**. + +If you can't see the drive: +* Make sure that the USB cable is working. +>Does the cable work on another computer? If not, find a different cable to use. Some cables may only provide a power connection and don't actually transfer data. +* Try another USB port on your computer. + +Is the cable good but you still can't see the **MICROBIT** drive? Hmm, you might have a problem with your @boardname@. Try the additional steps described in the [fault finding](https://support.microbit.org/support/solutions/articles/19000024000-fault-finding-with-a-micro-bit) page at microbit.org. If this doesn't help, you can create a [support ticket](https://support.microbit.org/support/tickets/new) to notify the Micro:bit Foundation of the problem. **Skip the rest of these steps**. + +## Step 2: Check your firmware version + +It's possible that the firmware version on the @boardname@ needs an update. Let's check: + +1. Go to the **MICROBIT** drive. +2. Open the **DETAILS.TXT** file.
+![](/static/mb/device/mb-drive-contents.jpg)
+3. Look for a line in the file that says the version number. It should say **Version: \.\.\.** +![](/static/mb/device/details-txt.jpg)
+ +If the version is **0234**, you **NEED** to update the [firmware](/device/firmware) on your @boardname@. Go to **Step 3** and follow the upgrade instructions. + +If the version is **0241**, **0243** or higher, **you have the right firmware**. You can create a [support ticket](https://support.microbit.org/support/tickets/new) to notify the Micro:bit Foundation of the problem. **Skip the rest of these steps**. + +## Step 3: Upgrade the firmware + +1. Put your @boardname@ into **MAINTENANCE Mode**. To do this, unplug the USB cable from the @boardname@ and then re-connect the USB cable while you hold down the reset button. Once you insert the cable, you can release the reset button. You should now see a **MAINTENANCE** drive instead of the **MICROBIT** drive like before. Also, a yellow LED light will stay on next to the reset button. +![MAINTENANCE gesture](/static/mb/device/maintenance.gif) +2. **[Download the firmware .hex file](https://microbit.org/guide/firmware/#update-firmware)** +3. Drag and drop that file onto the **MAINTENANCE** drive. +4. The yellow LED will flash while the `HEX` file is copying. When the copy finishes, the LED will go off and the @boardname@ resets. The **MAINTENANCE** drive now changes back to **MICROBIT**. +5. The upgrade is complete! You can open the **DETAILS.TXT** file to check and see that the firmware version changed to the match the version of the `HEX` file you copied. + +### ~hint + +If you want to know more about connecting the board, MAINTENANCE Mode, and upgrading the firmware, read about it in the [micro:bit firmware guide](https://microbit.org/guide/firmware). + +### ~ + +## Step 4: Wait for the driver updates + +Once you've updated the firmware, Windows will detect the updated device and install the drivers necessary to enable communication with the @boardname@. This step happens in the background and may take a minute or two. + +## Step 5: Drag and drop a fresh .hex file + +If different editors were used with this board, it may need a reset to bring it back to a known-good state. Do this by dragging a ``.hex`` file containing a simple program onto the drive. You can use the one here. Click on the **Download** icon below the blocks, then drag and drop the file onto the @drivename@ drive. + +```blocks +basic.forever(function() { + basic.showString("OK") +}) +``` diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 00000000..b02e6505 --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,47 @@ +# Examples + +Here are some fun programs for your @boardname@! + +## Fun stuff + +```codecard +[{ + "name": "Rando", + "description": "Randomly blinking LEDs", + "url": "/examples/rando", + "cardType": "example" +}, +{ + "name": "Game of Life", + "description": "A Game of Life simulation in LEDs", + "url": "/examples/gameofLife", + "cardType": "example" +}, +{ + "name": "Pi Monte Carlo", + "description": "Approximate the number Pi", + "url": "/examples/pi-montecarlo", + "cardType": "example" +}] +``` + +## Sensors + +```codecard +[{ + "name": "Egg & Spoon Race", + "description": "Balance a micro:bit like an egg and spoon race", + "url": "/examples/egg-and-spoon", + "cardType": "example" +},{ + "name": "Plot Acceleration", + "description": "Chart acceleration on the LED screen", + "url": "/examples/plot-acceleration", + "cardType": "example" +}, { + "name": "Radio Dashboard", + "description": "A dashboard for radio clients", + "url": "/examples/radio-dashboard", + "cardType": "example" +}] +``` diff --git a/docs/examples/pi-montecarlo.md b/docs/examples/pi-montecarlo.md index 72a67114..3a56f947 100644 --- a/docs/examples/pi-montecarlo.md +++ b/docs/examples/pi-montecarlo.md @@ -73,8 +73,8 @@ basic.forever(() => { inside = 0 for (let i = 0; i < n; i++) { // generate a point within the square - x = Math.randomRange(0, r + 1) - y = Math.randomRange(0, r + 1) + x = randint(0, r + 1) + y = randint(0, r + 1) // test if the point is within the circle // sqrt(x**2 + y**2) < r ==> x**2 + y**2 < r**2 if (x * x + y * y < r2) { diff --git a/docs/examples/rando.md b/docs/examples/rando.md index 00670ad5..7c244c27 100644 --- a/docs/examples/rando.md +++ b/docs/examples/rando.md @@ -4,6 +4,6 @@ Generate a random coordinate and display it on the LED screen. ```blocks basic.forever(() => { - led.toggle(Math.randomRange(0, 4), Math.randomRange(0, 4)) + led.toggle(randint(0, 4), randint(0, 4)) }) ``` \ No newline at end of file diff --git a/docs/live-coding.md b/docs/live-coding.md new file mode 100644 index 00000000..74cf9258 --- /dev/null +++ b/docs/live-coding.md @@ -0,0 +1,63 @@ +# Live coding sessions + +Here are some videos of live tutorial sessions with the @boardname@! + +## Fun stuff + +```codecard +[ +{ + "name": "Daily Coding Lessons!", + "description": "Subscribe to our mixer.com stream. Live coding Monday through Friday at 9AM PST / Noon EST / 4PM GMT", + "url": "https://mixer.com/MakeCode", + "imageUrl": "/static/live-coding/live.png" +}, +{ + "name": "Flashing Heart", + "description": "Demonstrating the Flashing Heart tutorial, live.", + "youTubeId": "NvEOKZ8wh9s", + "imageUrl": "/static/live-coding/showleds.jpg" +}, +{ + "name": "Name Tag", + "description": "A live illustration of the Name tag tutorial", + "youTubeId": "xpRI5jjQ31E", + "imageUrl": "/static/live-coding/showstring.jpg" +}, +{ + "name": "Smiley Button", + "description": "Step by step live coding of the Smiley Button tutorial.", + "youTubeId": "BgDxz3M7JIM" +}, +{ + "name": "Dice", + "description": "Step by step live coding of the Dice tutorial.", + "youTubeId": "OmrmjtOm_sQ" +}, +{ + "name": "Love Meter", + "description": "Steps by step live coding of the Love Meter tutorial", + "youTubeId": "1IYsy0_9n8g" +}, +{ + "name": "Micro Chat", + "description": "Steps by step live coding of the Micro Chat tutorial", + "youTubeId": "5XqsGROG2fI" +}, +{ + "name": "Rock Paper Scissor", + "description": "Steps by step live coding of the Rock Paper Scissor tutorial", + "youTubeId": "94lLBB3b1kU" +}, +{ + "name": "Playlist", + "description": "See all the previous live stream sessions", + "url": "https://www.youtube.com/watch?v=NvEOKZ8wh9s&list=PLMMBk9hE-SepocOwueEtTDyOPI_TBE9yC", + "imageUrl": "/static/live-coding/playlist.png" +} +] +``` + +## See Also + +[YouTube Playlist](https://www.youtube.com/watch?v=NvEOKZ8wh9s&list=PLMMBk9hE-SepocOwueEtTDyOPI_TBE9yC) diff --git a/docs/projects/dice.md b/docs/projects/dice.md index 5ed9faf6..df05f65f 100644 --- a/docs/projects/dice.md +++ b/docs/projects/dice.md @@ -35,7 +35,7 @@ Put a ``||Math:pick random||`` block in the ``||basic:show number||`` block to p ```blocks input.onGesture(Gesture.Shake, () => { - basic.showNumber(Math.randomRange(0, 10)) + basic.showNumber(randint(0, 10)) }) ``` @@ -45,7 +45,7 @@ A typical dice shows values from `1` to `6`. So, in ``||Math:pick random||``, do ```blocks input.onGesture(Gesture.Shake, () => { - basic.showNumber(Math.randomRange(1, 6)) + basic.showNumber(randint(1, 6)) }) ``` diff --git a/docs/projects/escape-room.md b/docs/projects/escape-room.md new file mode 100644 index 00000000..f3109ef2 --- /dev/null +++ b/docs/projects/escape-room.md @@ -0,0 +1,18 @@ +# Escape Room + +Projects used to create escape room experiences. + +## Radio + +```codecard +[{ + "name": "Rotary Dial Radio", + "url":"/projects/rotary-dial-radio", + "description": "Turn an antique rotary dial phone into a radio transmitter", + "imageUrl":"/static/mb/projects/rotary-dial-radio.png" +}] +``` + +## Acknowledgments + +Escape room ideas are gathered from a great discussion with [Pauline Maas](https://twitter.com/4pip) and [Peter Heldens](https://twitter.com/PeterHeldens) at https://microbit101.nl/. diff --git a/docs/projects/love-meter.md b/docs/projects/love-meter.md index 37fbc01b..64ef21cb 100644 --- a/docs/projects/love-meter.md +++ b/docs/projects/love-meter.md @@ -21,7 +21,7 @@ Using ``||basic:show number||`` and ``||Math:pick random||`` blocks, show a rand ```blocks input.onPinPressed(TouchPin.P0, () => { - basic.showNumber(Math.randomRange(0, 100)); + basic.showNumber(randint(0, 100)); }); ``` ## Step 3 @@ -35,7 +35,7 @@ Show ``"LOVE METER"`` on the screen when the @boardname@ starts. ```blocks basic.showString("LOVE METER"); input.onPinPressed(TouchPin.P0, () => { - basic.showNumber(Math.randomRange(0, 100)); + basic.showNumber(randint(0, 100)); }); ``` diff --git a/docs/projects/name-badge.md b/docs/projects/name-badge.md new file mode 100644 index 00000000..a58f8505 --- /dev/null +++ b/docs/projects/name-badge.md @@ -0,0 +1,98 @@ +# Name Badge + +![Name badge project](/static/mb/projects/name-badge/header.png) + +Make yourself known with a fancy name badge powered by your @boardname@! + +## Code + +First, let's get your name to display on the screen. + +### Button press + +From the ``||input:Input||`` Toolbox drawer, drag an ``||input:on button A pressed||`` block onto the Workspace. + +```blocks +input.onButtonPressed(Button.A, function () { + +}) +``` + +### Show a string + +From the ``||basic:Basic||`` Toolbox drawer drag a ``||basic:show string||`` block into the ``||input:on button A pressed||`` block. + +```blocks +input.onButtonPressed(Button.A, function () { + basic.showString("Hello!") +}) +``` + +### Show my name + +In the ``||basic:show string||`` block, type your name. + +```blocks +input.onButtonPressed(Button.A, function () { + basic.showString("My Name") +}) +``` + +### Test the badge + +Go to the simulator and test your name badge by pressing button **A**. + +```sim +input.onButtonPressed(Button.A, function () { + basic.showString("My Name") +}) +``` + +### Download + +Download the program to your @boardname@: + +1. Make sure your @boardname@ is plugged into the computer. +2. Click the `|Download|` button. + +## Make + +Now that you have your name showing on the @boardname@, let's make a proper badge to wear and display it on. + +Cut out a badge shape from a piece of colored construction paper. + +![Construction paper and scisssors](/static/mb/projects/name-badge/picture1.png) + +Loop a piece of duct tape and stick it on the back of your @boardname@. + +![Roll of tape with the other materials](/static/mb/projects/name-badge/picture2.png) + +Stick your @boardname@ onto the front of your badge. + +![Board attached to the paper](/static/mb/projects/name-badge/picture3.png) + +Using a hole-punch, punch out 2 holes in the top of your badge. + +![Holes punched in the paper](/static/mb/projects/name-badge/picture4.png) + +Attach the battery pack to the @boardname@. + +![Battery pack connected to the board](/static/mb/projects/name-badge/picture5.png) + +Tape battery pack onto the back of the badge. + +![Battery pack taped on](/static/mb/projects/name-badge/picture6.png) + +Thread a shoelace through the top 2 holes of your badge. + +![Shoelace threaded through a hole](/static/mb/projects/name-badge/picture7.png) + +Tie a knot at the end of your shoelace + +![Ends of shoelace tied together](/static/mb/projects/name-badge/picture8.png) + +Decorate your badge with colored paper, markers, stickers, glitter. + +![Completed name badge](/static/mb/projects/name-badge/picture9.png) + +It's now finished! your badge is ready let others know who you are. \ No newline at end of file diff --git a/docs/projects/robot-unicorn.md b/docs/projects/robot-unicorn.md new file mode 100644 index 00000000..46562447 --- /dev/null +++ b/docs/projects/robot-unicorn.md @@ -0,0 +1,200 @@ +# Robot Unicorn + +## by [Helen Leigh](https://twitter.com/helenleigh) + +Hey, I made a herd of very silly gesture controlled robot unicorns I did this because I was bored with those personality-free robots that only move in a straight line. This is a cheap, unreliable, hilarious robot unicorn project suitable for total beginners. You'll learn about LEDs, gesture control, radio, and servo control. + +On this project page, I've written up what you'll need to make your own Robot Unicorn, with all the steps you'll need to follow and the code you'll need to write. I've even have videos for each of the steps to help guide you through this project. Happy making and have fun! + +![Robot Unicorn](/static/mb/projects/robot-unicorn/robotunicorn.jpg) + +## Ingredients + +Here's what you'll need. The links telling where to get parts are just examples - with a bit of searching you will be able to find any of these parts cheaper in whatever shop you normally use to get parts like this: eBay, Amazon, Rapid, Digikey, Kitronik, etc. + +- Two @boardname@s plus a AAA battery pack for each of them. +- Two 360 continuous rotation servos with wheels (I used FS90R servos with wheels [like this](https://www.kitronik.co.uk/2574-wheel-for-fs90r-60mmx8mm.html)). 360 servos are super cheap, super unreliable and super easy to hook up, which is exactly why I chose them. Remember, the unicorn not going exactly where you expect it to go is kind of the point. +- One small swivelling castor wheel plus the nuts and bolts to fix it to the base (something [like this](https://www.amazon.co.uk/dp/B074WP1QJN/)). You can use a marble like castor wheel designed for robots but if you use the cheaper ones designed for furniture you can figure out a special way to get your robot unicorn to rear up like She Ra's flying unicorn Swift Wind. Or sometimes it will just fall over. Either way, it's funny. +- One 3XAA battery pack with on off switch and leads (something [like this](https://www.amazon.com/x1-5V-Battery-Holder-Switch-Wires/dp/B01C5J4K3Q/)). +- Three crocodile clips, or alligator clips as Americans apparently call them. Cute. +- One unicorn horn. Obviously. I modified an old ``stl`` from Adafruit at [Thingverse](https://www.thingiverse.com/thing:956359) to make it smaller and give it a solid base so it stuck securely onto my unicorn's head. I've included my revised ``stl`` file in the project files at the bottom of this project page if you want to 3D print your own, or you can make a horn from whatever kind of material you like! +- Something shiny for the tail. I used tinsel for some and tiny disco balls for some others. +- Three sheets of A4 card, the sparklier the better. I've made pdf templates for the shape of the body and head which you can either use as a printed template or as a lasercutting file. You'll find the pdfs in the project files at the bottom of this project page. If you want to experiment with using other materials for your Robot Unicorn, go for it! I've used a card base and a furry body, my friend made a leather version and I've also lasercut semi transparent polypropylene for the head, putting LEDs, jelly beans, copper tape and glitter inside. (The glitter was a total pain. 0/10 do not recommend.) +- Some wire strippers and some electrical tape. +- Some double sided sticky tape, some sellotape and/or some decent glue. Those double sided sticky pads work really well for fixing the servos to the cardboard chassis. + +![micro:bits and Unicorn Horn](/static/mb/projects/robot-unicorn/microbitsunicorn.jpg) + +### Instructions + +**1. Make the unicorn body!** I've made the video below to show how to put your unicorn together using the templates in the project files at the bottom of this project page. Not feeling crafty? That's okay! You can experiment with cutting wheel holes in a small box instead. + +https://www.youtube.com/watch?v=CKqrMxuZ6gQ +
+ +**2. Add in the electronics!** Put on the wheels, then wire up the servos and the battery and the first @boardname@. Just watch my video to see how. + +https://youtu.be/CKqrMxuZ6gQ?t=178 +
+ +**3. Code it!** I've supplied my code below, but I'd recommend that you watch the videos I've made so that you understand what is going on. The first video gets you started with one @boardname@, and the second helps you take the next step: gesture controlling your robot unicorn with two @boardname@s. **Pro tip**: there are lots of ways to get the same results using different code, so it's totaslly fine if your code works but doesn't match mine. + +**Getting started with @boardname@** + +https://www.youtube.com/watch?v=OBcVMPdAIoE +
+ +**Using gesture control and radio to control your Robot Unicorn with @boardname@** + +https://www.youtube.com/watch?v=qAakgfNouOI +
+ +**4. Play!** Make an obstacle course! Make another one and have a race or a dance off with a friend! Once you've mastered the basics of making your unicorn move around you might want to think about how to make improvements. + +**5. Tell me about it!** It brings me joy to know other people make my silly inventions. You can say hi [on Twitter](https://twitter.com/helenleigh), follow me [on Insta](https://www.instagram.com/helenleigh_makes/) or [subscribe to my channel on YouTube](https://youtube.com/c/HelenLeigh). + +## Code + +**MakeCode blocks for the body of the Robot Unicorn** + +```blocks +radio.onReceivedNumberDeprecated(function (receivedNumber) { + received = receivedNumber +}) +let received = 0 +radio.setGroup(1) +received = 4 +basic.forever(function () { + if (received == 0) { + basic.showLeds(` + . . # . . + . # # # . + # . # . # + . . # . . + . . # . . + `) + pins.analogWritePin(AnalogPin.P0, 100) + pins.analogWritePin(AnalogPin.P1, 10) + } else if (received == 1) { + basic.showLeds(` + . . # . . + . . # . . + # . # . # + . # # # . + . . # . . + `) + pins.analogWritePin(AnalogPin.P0, 10) + pins.analogWritePin(AnalogPin.P1, 100) + } else if (received == 2) { + pins.analogWritePin(AnalogPin.P0, 20) + pins.analogWritePin(AnalogPin.P1, 20) + basic.showLeds(` + . . # . . + . # . . . + # # # # # + . # . . . + . . # . . + `) + } else if (received == 3) { + pins.analogWritePin(AnalogPin.P0, 80) + pins.analogWritePin(AnalogPin.P1, 80) + basic.showLeds(` + . . # . . + . . . # . + # # # # # + . . . # . + . . # . . + `) + } else if (received == 4) { + pins.analogWritePin(AnalogPin.P0, 0) + pins.analogWritePin(AnalogPin.P1, 0) + basic.showLeds(` + # . . . # + . # . # . + . . # . . + . # . # . + # . . . # + `) + } +}) + +``` + +**MakeCode blocks for the Robot Unicorn controller** + +```blocks +input.onButtonPressed(Button.AB, function () { + radio.sendNumber(4) + basic.showLeds(` + # . . . # + . # . # . + . . # . . + . # . # . + # . . . # + `) +}) +input.onGesture(Gesture.Shake, function () { + radio.sendNumber(1) + basic.showLeds(` + . . # . . + . . # . . + # . # . # + . # # # . + . . # . . + `) +}) +input.onGesture(Gesture.LogoDown, function () { + radio.sendNumber(0) + basic.showLeds(` + . . # . . + . # # # . + # . # . # + . . # . . + . . # . . + `) +}) +input.onGesture(Gesture.TiltRight, function () { + radio.sendNumber(2) + basic.showLeds(` + . . # . . + . . . # . + # # # # # + . . . # . + . . # . . + `) +}) +input.onGesture(Gesture.TiltLeft, function () { + radio.sendNumber(3) + basic.showLeds(` + . . # . . + . # . . . + # # # # # + . # . . . + . . # . . + `) +}) +radio.setGroup(1) +radio.setTransmitPower(7) +basic.showLeds(` + . . # . . + . # # # . + # # # # # + # # # # # + . # . # . + `) +``` + +## Everythin Else + +Here's where you can find all the templates you need to make the Robot Unicorn. + +- Template for the main part of the body: [pdf file here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20chassis%20A4.pdf) and [ai file here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20chassis%20A4.ai). +- Template for the top part of the body: [pdf file here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20lid%20a4.pdf) and [ai file here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20lid%20a4.ai). +- Template for the head: [pdf file here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20head%20A4.pdf) and [ai file here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20head%20A4.ai). +- STL file for 3D printing your Robot Unicorn horn [is here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20horn%20solid%20base.stl). + +![Robot Unicorn Tail](/static/mb/projects/robot-unicorn/robotunicorntail.jpg) + +```package +radio +``` \ No newline at end of file diff --git a/docs/projects/rotary-dial-radio.md b/docs/projects/rotary-dial-radio.md new file mode 100644 index 00000000..f870aef8 --- /dev/null +++ b/docs/projects/rotary-dial-radio.md @@ -0,0 +1,232 @@ +# Rotary Dial Radio + +Rotary dial phones may not be one of the latest tech fashions but they've still got some wings if you pair them with a @boardname@. If you are lucky enough to still own one of these antiques, follow this guide and you can bring it into the 21st century. + +![A rotary dial phone connected to a @boardname@](/static/mb/projects/rotary-dial-radio/final.jpg) + +This guide is mainly a journal of notes and techniques used to convert a 1945 rotary dial into a @boardname@ radio encoder. This is an example of **reverse engineering**, a treasure hunt for engineers if you wish. + +### ~ hint + +### Stay safe + +Opening and handling any electrical device can be very dangerous. Make sure to unplug all sources of power. Unless you know what you are doing, stay away from wall power outlets (AC). + +### ~ + +## What is Pulse dialing? + + +The phone below is a Belgium rotary dial phone from 1945. It's really heavy and the dial makes a wonderful clicking noise when it turns. + +![Antique rotary dial phone](/static/mb/projects/rotary-dial-radio/oldphone.jpg) + +If you skim through the WikiPedia on "rotary dial phones", you'll quickly learn that they operated by using something called **pulse dialing** (https://en.wikipedia.org/wiki/Pulse_dialing). In a nutshell, the dialing mechanism opens and closes a circuit while it rotates which sends a series of electrical pulses on the phone line. One pulse for number 1, two pulses for number 2, and so on. (Hey, what about 0?) + +## Digging into the phone + +Fortunately for us, the bottom of the phone is easily removed by pressing lever. It reveals the internals of the phone. One can see the two massive bells to ring the phone and some other capacitors and circuitery. + +![Inside of a rotary phone](/static/mb/projects/rotary-dial-radio/guts.jpg) + +Most interestingly, there are 8 terminals near the 2 holes in the case for wires. + +* The 2 terminals on each side are connected by a black wire. This is most likely the ground wire. +* The phone line was missing but there is still a hole for it. Since phone lines carry a bit of electrical current, we'll inject electricity on those terminals. +* Three (3) terminals seem to be used by the handset so they must be carrying some kind of microphone/speaker signal. We'll try each of them. + +At this point, we have enough information to start "scoping" the lines and hopefully get lucky and see the pulses. (Did I mention treasure hunting?) + +## Scoping the lines + +Electrical engineers use tools called "scopes" to "see" the eletrical signals on the line. In our case, we'd like to see the pulses generated when the phone is dialing. We don't have a scope so we'll use the @boardname@ instead. + +We connect the @boardname@ to the phone using 3 croc clips: + +* **GND** pin goes to the ground terminal +* **3v** pin connects at the positive terminal on the phone line +* **P0** is attacned to one of the headset lines (not **GND**) + +![Wiring](/static/mb/projects/rotary-dial-radio/wired.jpg) + +In the MakeCode, we upload a program that reads the analog input on **P0** and plots it on the screen. If you pair your @boardname@, you can also see the data in the console view. + +```blocks +basic.forever(function () { + led.plotBarGraph( + pins.analogReadPin(AnalogPin.P0), + 1023 + ) +}) +``` + +Try moving the dial slowly...click, click and you should see the pulses, e.g. the signal going high and low. If you don't see anything, keep trying other cables. Be patient, don't give up. + +https://youtu.be/po9o77IEDaI + +## Detecting the pulses + +The @boardname@ can raise an event when an electrical signal on **P0** goes low or high. This is the most important step as it allows us to precisely detect and count pulses. Try the following program with the phone. When you move the dial, you see the first LED turn on and off as the line goes high and low. + +```blocks +pins.onPulsed(DigitalPin.P0, PulseValue.High, function () { + led.plot(0, 0) +}) +pins.onPulsed(DigitalPin.P0, PulseValue.Low, function () { + led.unplot(0, 0) +}) +``` + +## Counting the pulses + +Now that we are detecting pulses, we can use a variable to count them too. In this test program, we increment the **pulseCount** variable by one on each high pulse and we display the number when pressing the **A** button. Try dialing a number; then press A. + +```blocks +let pulseCount = 0 +input.onButtonPressed(Button.A, function () { + basic.showNumber(pulseCount) + pulseCount = 0 +}) +pins.onPulsed(DigitalPin.P0, PulseValue.High, function () { + led.plot(0, 0) +}) +pins.onPulsed(DigitalPin.P0, PulseValue.Low, function () { + led.unplot(0, 0) + pulseCount += 1 +}) +``` + +## Digits and Numbers + +Our next task is to detect that the pulses for a digit have finished and we should then record the final number. The phone generates a train of pulses (typically 10 per second) per digit; the user might then move the dial back to start the next digit. This leaves a window of time when nothing happens on the line. If our decoder detects that nothing happens on the line for a long time, say 200ms, we assume that the train is done and save the digit. + +Instead of using button **A**, we add a **forever** loop that monitors the elapsed time since the last pulse. +If we have had a pulse (``pulseCount > 0``) **and** the last pulse was more than 200ms ago, we have a digit and we can send it. + +```blocks +let pulseCount = 0 +let lastPulseMs = 0 +pins.onPulsed(DigitalPin.P0, PulseValue.High, function () { + led.plot(0, 0) +}) +pins.onPulsed(DigitalPin.P0, PulseValue.Low, function () { + led.unplot(0, 0) + pulseCount += 1 + lastPulseMs = input.runningTime() +}) +basic.forever(function () { + if (pulseCount > 0 && lastPulseMs - input.runningTime() > 200) { + radio.sendNumber(pulseCount) + basic.showNumber(pulseCount) + pulseCount = 0 + } +}) +``` + +## What about 0? + +Great question! ``0`` is a special case and is represented by 10 pulses, so we need to update our decoder to take this into account. + +```blocks +let pulseCount = 0 +let lastPulseMs = 0 +pins.onPulsed(DigitalPin.P0, PulseValue.High, function () { + led.plot(0, 0) +}) +pins.onPulsed(DigitalPin.P0, PulseValue.Low, function () { + led.unplot(0, 0) + pulseCount += 1 + lastPulseMs = input.runningTime() +}) +basic.forever(function () { + if (pulseCount > 0 && lastPulseMs - input.runningTime() > 200) { + if(pulseCount == 10) { + pulseCount = 0 + } + radio.sendNumber(pulseCount) + basic.showNumber(pulseCount) + pulseCount = 0 + } +}) +``` + +## Numbers and more + +Improving the program is left as a challenge for you (treasure hunt). The following program was the result of the initial investigation; it waits 3 seconds between digits to send the entire number over radio and uses the screen to display how many digits were entered. This is just an example, you can come up with your own twist on this too! + +https://youtu.be/gW6rLH7qH5Q + +```blocks +pins.onPulsed(DigitalPin.P0, PulseValue.High, function () { + led.plot(0, 0) +}) +function plotIndex (i: number, on: boolean) { + row = Math.idiv(i, 5) + col = i % 5 + if (on) { + led.plot(col, row) + } else { + led.unplot(col, row) + } +} +function codeDots () { + for (let index = 0; index <= 4; index++) { + led.plot(index, 2) + } + for (let index2 = 0; index2 <= 9; index2++) { + plotIndex(15 + index2, index2 < code.length) + } +} +pins.onPulsed(DigitalPin.P0, PulseValue.Low, function () { + led.unplot(0, 0) + if (lastPulseMs == 0) { + pulseCount = 0 + lastPulseMs = input.runningTime() + } else if (input.runningTime() - lastPulseMs > 85) { + pulseCount += 1 + lastPulseMs = input.runningTime() + } +}) +let codeNumber = 0 +let lastDigitMs = 0 +let col = 0 +let row = 0 +let pulseCount = 0 +let code = "" +let lastPulseMs = 0 +radio.setGroup(1) +lastPulseMs = 0 +code = "" +pulseCount = 0 +basic.forever(function () { + if (lastPulseMs > 0 && input.runningTime() - lastPulseMs >= 250) { + led.plot(1, 0) + if (pulseCount == 10) { + pulseCount = 0 + } + code = "" + code + convertToText(pulseCount) + lastPulseMs = 0 + lastDigitMs = input.runningTime() + } else if (lastPulseMs == 0 && (code.length > 0 && (code.length == 10 || input.runningTime() - lastDigitMs >= 3000))) { + led.plot(2, 0) + codeNumber = parseFloat(code) + for (let index = 0; index < 1; index++) { + radio.sendNumber(codeNumber) + basic.pause(10) + } + basic.clearScreen() + basic.showNumber(codeNumber) + basic.clearScreen() + code = "" + lastPulseMs = 0 + } else { + led.unplot(1, 0) + led.unplot(2, 0) + } + codeDots() +}) +``` + +```package +radio +``` \ No newline at end of file diff --git a/docs/reference/control/millis.md b/docs/reference/control/millis.md new file mode 100644 index 00000000..ed531c13 --- /dev/null +++ b/docs/reference/control/millis.md @@ -0,0 +1,25 @@ +# millis + +Get the number of milliseconds of time passed since the board was turned on. + +```sig +control.millis() +``` + +## Returns + +* the [number](/types/number) of milliseconds of time since the board was turned on. + +## Example #example + +Find how many days, hours, minutes, and seconds the @boardname@ has been running. + +```blocks +let msecs = control.millis() +let seconds = msecs / 1000 +let mins = seconds / 60 +let hours = mins / 60 +let days = hours / 24 +``` + +## #seealso \ No newline at end of file diff --git a/docs/reference/control/wait-for-event.md b/docs/reference/control/wait-for-event.md new file mode 100644 index 00000000..6eaa5bfa --- /dev/null +++ b/docs/reference/control/wait-for-event.md @@ -0,0 +1,67 @@ +# wait For Event + +Stop running the current code and wait for an event. + +```sig +control.waitForEvent(0, 0) +``` +You might want your code to stop for a while until some event you're expecting happens. +If you want your code to pause until a known event happens, use a ``||control:wait for event||`` block. +A known event is something you identify that happens on the board or in your program. +An event has both a source and a cause. The source is where the event comes from, like a sensor or +some condition in your program. The cause is what made the event happen at the source. + +You assign numbers for your event sources and causes. These numbers are used by [``||control:raise event||``](/reference/control/raise-event) to announce to your program that an event just happened. + +As an example, you could make a timer that always causes an event every 100 milliseconds. The source +number for the timer is `6` and the cause value is `1`. The program could wait for one of the time +events like this: + +```blocks +const myTimer = 6; +const timerTimeout = 1; + +control.runInParallel(function() { + while (true) { + control.waitMicros(100000) + control.raiseEvent(myTimer, timerTimeout) + } +}) + +control.waitForEvent(myTimer, timerTimeout) +``` + +## Parameters + +* **id**: the identification [number](/types/number) (the source) of this event, such as: `10`. +* **value**: a [number](/types/number) tells what the cause of the event is, like: `4`. + +## Example #example + +Make a timeout timer to signal every 2 seconds. Wait two times and write to the +console each time. + +```blocks +const myTimer = 6; +const timerTimeout = 1; + +control.runInParallel(function() { + while (true) { + pause(2000) + control.raiseEvent(myTimer, timerTimeout) + } +}) + +control.waitForEvent(myTimer, timerTimeout) +console.log("Timer timeout") +control.waitForEvent(myTimer, timerTimeout) +console.log("Timer timeout") +``` + +**This is an advanced API.** For more information, see the +[@boardname@ runtime messageBus documentation](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/). + + +## See also #seealso + +[raise event](/reference/control/raise-event), [on event](/reference/control/on-event) \ No newline at end of file diff --git a/docs/reference/input/is-gesture.md b/docs/reference/input/is-gesture.md index 3becc968..4096ac36 100644 --- a/docs/reference/input/is-gesture.md +++ b/docs/reference/input/is-gesture.md @@ -17,7 +17,7 @@ This program shows a number from `2` to `9` when you shake the @boardname@. ```blocks forever(function() { if (input.isGesture(Gesture.Shake)) { - let x = Math.randomRange(2, 9) + let x = randint(2, 9) basic.showNumber(x) } }) diff --git a/docs/reference/input/on-button-pressed.md b/docs/reference/input/on-button-pressed.md index c17d7049..62331fcf 100644 --- a/docs/reference/input/on-button-pressed.md +++ b/docs/reference/input/on-button-pressed.md @@ -1,6 +1,6 @@ # On Button Pressed -Start an [event handler](/reference/event-handler) (part of the program that will run when something happens, like when a button is pressed). +Start an [event handler](/reference/event-handler) (part of the program that will run when something happens, like when a button is pressed). This handler works when button `A` or `B` is pressed, or `A` and `B` together. When you are using this function in a web browser, click the buttons on the screen instead of the ones on the @boardname@. @@ -18,7 +18,7 @@ https://www.youtube.com/watch?v=t_Qujjd_38o ## Example: count button clicks -This example counts how many times you press the `A` button. +This example counts how many times you press the `A` button. Each time you press the button, the [LED screen](/device/screen) shows the `count` variable getting bigger. ```blocks @@ -36,7 +36,7 @@ This example shows a number from 1 to 6 when you press the `B` button. ```blocks input.onButtonPressed(Button.B, () => { - let dice = Math.randomRange(0, 5) + 1 + let dice = randint(0, 5) + 1 basic.showNumber(dice) }) ``` diff --git a/docs/reference/input/on-gesture.md b/docs/reference/input/on-gesture.md index 29e98e5a..87ff0a47 100644 --- a/docs/reference/input/on-gesture.md +++ b/docs/reference/input/on-gesture.md @@ -19,7 +19,7 @@ This program shows a number from `2` to `9` when you shake the @boardname@. ```blocks input.onGesture(Gesture.Shake,() => { - let x = Math.randomRange(2, 9) + let x = randint(2, 9) basic.showNumber(x) }) ``` diff --git a/docs/reference/led/point-brightness.md b/docs/reference/led/point-brightness.md new file mode 100644 index 00000000..1d5adb7a --- /dev/null +++ b/docs/reference/led/point-brightness.md @@ -0,0 +1,46 @@ +# Point Brightness + +Read the brightness of a LED on the [LED screen](/device/screen). + +```sig +led.pointBrightness(0,0); +``` + +## Parameters + +* ``x`` is a [number](/types/number) that means the + horizontal spot on the LED screen (from left to right: 0, 1, 2, 3, + or 4) +* ``y`` is a [number](/types/number) that means the vertical + spot on the LED screen (from top to bottom: 0, 1, 2, 3, or 4) + +If a parameter is [out of bounds](/reference/out-of-bounds) (a value +other than 0 to 4), this function will return `false`. + +## Returns + +* a [number](/blocks/logic/number). If it is `true`, that means the LED is on. If it is `false`, that means the LED is off. + +## ~hint + +The LED screen is a solid square of LEDs with five LEDs on each side. +To learn more about how you number the LEDs with ``x`` and ``y`` +coordinates, see [LED screen](/device/screen). + +## ~ + +## Example: Toggle off + +This program turns the center LED (2, 2) off it is not bright enough. (If +it is already off, this program leaves it off.) + +```blocks +if (led.pointBrightness(2, 2) < 100) { + led.unplot(2, 2) +} +``` + +## See also + +[unplot](/reference/led/unplot), [plot](/reference/led/plot), [LED screen](/device/screen) + diff --git a/docs/reference/music.md b/docs/reference/music.md index 92d0c5e9..02be446d 100644 --- a/docs/reference/music.md +++ b/docs/reference/music.md @@ -3,22 +3,25 @@ Generation of music tones through pin ``P0``. ```cards -music.playTone(0, 0); -music.ringTone(0); -music.rest(0); -music.beginMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once); -music.stopMelody(MelodyStopOptions.All); -music.onEvent(MusicEvent.MelodyNotePlayed, () => {}); -music.beat(BeatFraction.Whole); -music.tempo(); -music.changeTempoBy(20); -music.setTempo(120); +music.playTone(0, 0) +music.ringTone(0) +music.rest(0) +music.startMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once) +music.stopMelody(MelodyStopOptions.All) +music.onEvent(MusicEvent.MelodyNotePlayed, () => {}) +music.beat(BeatFraction.Whole) +music.tempo() +music.changeTempoBy(20) +music.setTempo(120) +music.setVolume(0) +music.volume() ``` ## See Also -[playTone](/reference/music/play-tone), [ringTone](/reference/music/ring-tone), [rest](/reference/music/rest), -[beginMelody](/reference/music/begin-melody), -[stopMelody](/reference/music/stop-melody), -[onEvent](/reference/music/on-event), -[beat](/reference/music/beat), [tempo](/reference/music/tempo), [changeTempoBy](/reference/music/change-tempo-by), [setTempo](/reference/music/set-tempo), +[playTone](/reference/music/play-tone), [ringTone](/reference/music/ring-tone), +[rest](/reference/music/rest), [startMelody](/reference/music/start-melody), +[stopMelody](/reference/music/stop-melody), [onEvent](/reference/music/on-event), +[beat](/reference/music/beat), [tempo](/reference/music/tempo), +[changeTempoBy](/reference/music/change-tempo-by), [setTempo](/reference/music/set-tempo), +[setVolume](/reference/music/set-volume), [volume](/reference/music/volume) diff --git a/docs/reference/music/making-melodies.md b/docs/reference/music/making-melodies.md index 85f35670..10fe4d30 100644 --- a/docs/reference/music/making-melodies.md +++ b/docs/reference/music/making-melodies.md @@ -6,9 +6,11 @@ Composing some sound, or maybe some music, is done by putting tones to together, A _note_ is a tone that is recognized as part of music. A note has a name like '**C**'. A note is played for an amount of time called its _duration_. -On your @boardname@, a note is played on the speaker by sending a signal to a it with a certain _frequency_ called [Hertz](http://wikipedia.org/Hertz). Frequency is how fast something vibrates during one second. If you ring a bell that was made to play an '**A**' note, the bell will vibrate at 440 Hertz (440 times per second). So, notes are just certain frequencies that have special names. +On your @boardname@, a note is played on the speaker by sending a signal to it with a certain _frequency_ called [Hertz](http://wikipedia.org/Hertz). Frequency is how fast something vibrates during one second. If you ring a bell that was made to play an '**A**' note, the bell will vibrate at 440 Hertz (440 times per second). So, notes are just certain frequencies that have special names. -## ~ hint +### ~ hint + +#### Listen to music with headphones Watch this video to see how speakers and headphones make sound when connected to your @boardname@. @@ -24,7 +26,7 @@ Basic notes have names that use one of the first nine letters of the alphabet. T ``|A|``, ``|B|``, ``|C|``, ``|D|``, ``|E|``, ``|F|``, ``|G|`` -Ther are other notes named like the basic notes but have extra parts to the name called _sharp_ and _flat_. These other notes are just a bit different from the basic notes and have frequencies a little higher or lower than the basic note. This makes music a little more complicated but much more interesting! +There are other notes named like the basic notes but have extra parts to the name called _sharp_ and _flat_. These other notes are just a bit different from the basic notes and have frequencies a little higher or lower than the basic note. This makes music a little more complicated but much more interesting! Some of these other notes look like: @@ -32,6 +34,14 @@ Some of these other notes look like: When a small amount music or even a song is written down it is called [sheet music](https://wikipedia.org/wiki/Sheet_music). +### ~ hint + +#### Note names in different languages + +Many languages other than English use different names for some or all of the musical notes. MakeCode uses English for names in code. + +### ~ + ## Sounds and music in code Of course, we can't use written music in our code. We can make music another way. The way to do it is to put names of notes in [strings](/types/string). We make our notes using letters, symbols, and numbers. The notes of a melody are put together in an array like: @@ -51,13 +61,13 @@ What you see here is not some alien language but a bunch of notes with their dur You might notice that the sound string has an ``'R:1'`` in it. The '**R**` means _rest_ and to rest for one beat. A rest is a pause, or a time of silence, in the sound. -#### ~ hint +### ~ hint -**Duration** +#### Duration The amount of time a note is played (duration) is measured as _beats_. The standard number _beats per minute_ (bpm) in music is 120 bpm which is one-half of a second of time. A _whole_ note lasts for 4 beats and a _quarter_ note takes just one beat. -#### ~ +### ~ ## Example diff --git a/docs/reference/music/on-event.md b/docs/reference/music/on-event.md index 4c019542..b6c0e7d0 100644 --- a/docs/reference/music/on-event.md +++ b/docs/reference/music/on-event.md @@ -56,7 +56,7 @@ The events related to background melody get triggered by a melody that is played ``` control.inBackground(function () { - basic.pause(Math.randomRange(0, 5000)) + basic.pause(randint(0, 5000)) music.beginMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once) }) music.onEvent(MusicEvent.BackgroundMelodyStarted, function () { diff --git a/docs/reference/music/set-volume.md b/docs/reference/music/set-volume.md new file mode 100644 index 00000000..f0a68970 --- /dev/null +++ b/docs/reference/music/set-volume.md @@ -0,0 +1,35 @@ +# set Volume + +Set the volume for the sound synthesizer. + +```sig +music.setVolume(128) +``` + +### ~hint + +#### Simulator + +``||music:set volume||`` works on the @boardname@. It might not work in the simulator on every browser. + +### ~ + +## Parameters + +* ``volume``: the volume of of the sounds played to the sound output. The volume [number](/types/number) can be between `0` for silent and `255` for the loudest sound. + +## Example #example + +Set the synthesizer volume to something quieter. + +```blocks +music.setVolume(50) +``` + +## See also + +[volume](/reference/music/volume) + +```package +music +``` diff --git a/docs/reference/music/start-melody.md b/docs/reference/music/start-melody.md new file mode 100644 index 00000000..43990f7e --- /dev/null +++ b/docs/reference/music/start-melody.md @@ -0,0 +1,64 @@ +# start Melody + +Start playing a musical melody through pin ``P0`` of the @boardname@. + +```sig +music.startMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once) +``` + +## ~ hint + +**Simulator**: This function only works on the @boardname@ and in some browsers. + +## ~ + +There are built-in melodies that you can choose from the ``||start melody||`` block. These are already composed for you and are easy to use by just selecting the one you want. If you want to play your own melody, you can [compose](/reference/music/making-melodies) one and use it instead of one of the built-in ones. + +Melodies are a sequence of notes, each played for some small amount time, one after the other. The notes in a melody are held in an [array](/types/array) of [strings](/types/string). Each string in the array is a note of the melody. You make a melody by assembling the notes along with the _duration_ that the note plays for. The melody is [formed](/reference/music/making-melodies) like this: + +``NOTE[octave][:duration] eg: ['g5:1']`` + +```block +music.startMelody(['g4:1', 'c5', 'e', 'g:2', 'e:1', 'g:3'], MelodyOptions.Once) +``` + +Melodies are played either in the _foreground_ or _background_. This allows more than one melody to be active at once. If a melody is set to play in the background, it can be interrupeted, or paused, temporarily while a melody set for the foreground is played. If the foreground melody is not set to play ``forever``, then the background melody resumes when the foreground melody is finished. + +You can set options for how you want the melody to play. You can ask that the melody plays just one time, ``once``, or have it keep repeating, ``forever``. With these options the melody will play in the foreground either once or continue to repeat. Of course, if you set ``forever``, any melody that was started in background will never play unless you [stop](/reference/music/stop-melody) the foreground melody. To make a background melody, set the option to ``once in background`` or ``forever in background``. + +## Parameters + +* **melody**: A built-in melody or an [array](/types/array) representation of a [melody](reference/music/making-melodies) you wish to play. +* **options**: the play option for the melody: +>* ``once``: play the melody in the foreground one time +>* ``forever``: play the melody in the foreground and keep repeating it +>* ``once in background``: play the melody in the background one time +>* ``forever in background``: play the melody in the background and keep repeating it + +## Examples + +### Play the "Entertainer" + +This example plays the ``Entertainer`` built-in melody. + +```blocks +music.startMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once) +``` + +### Play a composed melody forever + +Play a made-up melody in the background forever. + +```blocks +music.startMelody(['g4:1', 'c5', 'e', 'g:2', 'e:1', 'g:3'], MelodyOptions.ForeverInBackground) +``` + +## See also + +[stop melody](/reference/music/stop-melody), [play tone](/reference/music/play-tone), +[rest](/reference/music/rest), [ring tone](/reference/music/ring-tone), +[tempo](/reference/music/tempo), [set tempo](/reference/music/set-tempo), +[change tempo by](/reference/music/change-tempo-by) + +[Making Melodies](/reference/music/making-melodies) + diff --git a/docs/reference/music/volume.md b/docs/reference/music/volume.md new file mode 100644 index 00000000..3f22f79b --- /dev/null +++ b/docs/reference/music/volume.md @@ -0,0 +1,27 @@ +# volume + +Get the current volume level of the sound synthesizer. + +```sig +music.volume() +``` + +### ~hint + +#### Simulator + +Using ``||music:volume||`` works on the @boardname@. It might not work in the simulator on every browser. + +### ~ + +## Returns + +* a [number](/types/number) that is the current volume level of output from the sound synthesizer. The value can be between `0` for silent and `255` for the loudest sound. + +## See also + +[set volume](/reference/music/set-volume) + +```package +music +``` diff --git a/docs/reference/pins/set-pull.md b/docs/reference/pins/set-pull.md index 8de7d274..9935c20d 100644 --- a/docs/reference/pins/set-pull.md +++ b/docs/reference/pins/set-pull.md @@ -11,7 +11,7 @@ is connected to ``GND`` (0 volts), then when you press the button, button press. ```sig -pins.setPull(DigitalPin.P9, PinPullMode.PullDown); +pins.setPull(DigitalPin.C9, PinPullMode.PullDown); ``` The pull-up and -down resistors are about 13kOhm. diff --git a/docs/reference/pins/spi-format.md b/docs/reference/pins/spi-format.md index 7272b5c3..9a4e8f76 100644 --- a/docs/reference/pins/spi-format.md +++ b/docs/reference/pins/spi-format.md @@ -30,7 +30,7 @@ The default number of bits is `8` and the default mode value is `3`. Set the pins and format for the SPI connection. ```blocks -pins.spiPins(DigitalPin.P15, DigitalPin.P14, DigitalPin.P13); +pins.spiPins(DigitalPin.C15, DigitalPin.C14, DigitalPin.C13); pins.spiFormat(8, 3); ``` diff --git a/docs/reference/pins/spi-frequency.md b/docs/reference/pins/spi-frequency.md index 7dd81241..c65f7584 100644 --- a/docs/reference/pins/spi-frequency.md +++ b/docs/reference/pins/spi-frequency.md @@ -26,7 +26,7 @@ Read the value of the _WHOAMI_ register from the device connected to the SPI bus ```blocks pins.digitalWritePin(DigitalPin.P0, 1); -pins.spiPins(DigitalPin.P15, DigitalPin.P14, DigitalPin.P13); +pins.spiPins(DigitalPin.C15, DigitalPin.C14, DigitalPin.C13); pins.spiFormat(8, 3); pins.spiFrequency(1000000); pins.digitalWritePin(DigitalPin.P0, 0); diff --git a/docs/reference/pins/spi-pins.md b/docs/reference/pins/spi-pins.md index 3d75d180..1d1fe111 100644 --- a/docs/reference/pins/spi-pins.md +++ b/docs/reference/pins/spi-pins.md @@ -31,7 +31,7 @@ If you don't set the pins for the SPI connection, the default pin assignments ar Set the pin assignments for a SPI connection to the default pins. ```blocks -pins.spiPins(DigitalPin.P15, DigitalPin.P14, DigitalPin.P13); +pins.spiPins(DigitalPin.C15, DigitalPin.C14, DigitalPin.C13); ``` ## See also diff --git a/docs/reference/pins/spi-write.md b/docs/reference/pins/spi-write.md index b7345f51..0d4c7cd1 100644 --- a/docs/reference/pins/spi-write.md +++ b/docs/reference/pins/spi-write.md @@ -28,7 +28,7 @@ Send the command to read the value of the _WHOAMI_ register from the device conn ```blocks pins.digitalWritePin(DigitalPin.P0, 1); -pins.spiPins(DigitalPin.P15, DigitalPin.P14, DigitalPin.P13); +pins.spiPins(DigitalPin.C15, DigitalPin.C14, DigitalPin.C13); pins.spiFormat(8, 3); pins.spiFrequency(1000000); pins.digitalWritePin(DigitalPin.P0, 0); diff --git a/docs/reference/serial/read-line.md b/docs/reference/serial/read-line.md index 1f988789..0d621cfe 100644 --- a/docs/reference/serial/read-line.md +++ b/docs/reference/serial/read-line.md @@ -8,9 +8,12 @@ serial.readLine(); ### ~hint -This function expects the line it reads to be terminated with the `\r` +This function expects the line it reads to be terminated with the `\n` character. If your terminal software does not terminate lines with -`\r`, this function will probably never return a value. +`\n`, this function will probably never return a value. + + +You can override the ``serial.NEW_LINE_DELIMITER`` field to change the newline delimiter. ### ~ diff --git a/docs/science-experiments.md b/docs/science-experiments.md new file mode 100644 index 00000000..3cfdd206 --- /dev/null +++ b/docs/science-experiments.md @@ -0,0 +1,58 @@ +# Science Experiments + +* [Watch Playlist on Youtube](https://www.youtube.com/playlist?list=PLMMBk9hE-SepXDy_290SeRmEpGA2u1pwW) + +## Videos + +```codecard +[ + { + "name": "Data Collection", + "description": "Collect, view, and analyze the data from your experiments.", + "youTubeId": "tZy9Ev21B4c", + "imageUrl": "/static/mb/science-experiments/data-collection.jpg" + }, + { + "name": "Population Trait Counter", + "description": "Observe population traits by collecting survey data from people, analyze and track the genetic traits.", + "youTubeId": "NNZEMiJHY2o", + "imageUrl": "/static/mb/science-experiments/population-trait.jpg" + }, + { + "name": "Temperature Sensor", + "description": "Chart temperature data in and out of direct sunlight using a sun shield, see if using a windshield sun shade in your car really makes it cooler.", + "youTubeId": "pHDYsy6xyE4", + "imageUrl": "/static/mb/science-experiments/temperature-sensor.jpg" + }, + { + "name": "Soil Moisture Sensor", + "description": "Watch this video to find out how you can create a soil moisture sensor to measure the health of your plants!", + "youTubeId": "n0WRQf11Pzo", + "imageUrl": "/static/mb/science-experiments/soil-moisture.jpg" + }, + { + "name": "EMG Muscle Sensor", + "description": "Monitor the movement of your muscles and measure the signals to them", + "youTubeId": "vxlPQZIwYRc", + "imageUrl": "/static/mb/science-experiments/emg-muscle-sensor.jpg" + }, + { + "name": "Egg Drop", + "description": "Can the egg survive a drop, test the drop force on an egg to find out when it might crack", + "youTubeId": "tnDJFdC3Nd4", + "imageUrl": "/static/mb/science-experiments/egg-drop.jpg" + }, + { + "name": "Battery Tester", + "description": "See if your batteries still have their voltage with this battery tester", + "youTubeId": "gdlc34nhjK4", + "imageUrl": "/static/mb/science-experiments/battery-tester.jpg" + }, + { + "name": "Rocket Acceleration", + "description": "Have a blast building, launching, and tracking your own rocket!", + "youTubeId": "m9ntqxh8FvQ", + "imageUrl": "/static/mb/science-experiments/rocket-acceleration.jpg" + } +] +``` \ No newline at end of file diff --git a/docs/static/bluetooth/Bluetooth_SIG.png b/docs/static/bluetooth/Bluetooth_SIG.png new file mode 100644 index 00000000..5479e652 Binary files /dev/null and b/docs/static/bluetooth/Bluetooth_SIG.png differ diff --git a/docs/static/bluetooth/gatt_hierarchy.png b/docs/static/bluetooth/gatt_hierarchy.png new file mode 100644 index 00000000..d5171d3a Binary files /dev/null and b/docs/static/bluetooth/gatt_hierarchy.png differ diff --git a/docs/static/bluetooth/services_and_GATT.png b/docs/static/bluetooth/services_and_GATT.png new file mode 100644 index 00000000..7fd212d0 Binary files /dev/null and b/docs/static/bluetooth/services_and_GATT.png differ diff --git a/docs/static/courses/logic-lab.png b/docs/static/courses/logic-lab.png new file mode 100644 index 00000000..913547b6 Binary files /dev/null and b/docs/static/courses/logic-lab.png differ diff --git a/docs/static/courses/logic-lab/logic-gates/and-gate.png b/docs/static/courses/logic-lab/logic-gates/and-gate.png new file mode 100644 index 00000000..21beeee4 Binary files /dev/null and b/docs/static/courses/logic-lab/logic-gates/and-gate.png differ diff --git a/docs/static/courses/logic-lab/logic-gates/combinatorial1-xor.png b/docs/static/courses/logic-lab/logic-gates/combinatorial1-xor.png new file mode 100644 index 00000000..addd335c Binary files /dev/null and b/docs/static/courses/logic-lab/logic-gates/combinatorial1-xor.png differ diff --git a/docs/static/courses/logic-lab/logic-gates/combinatorial2-xor.png b/docs/static/courses/logic-lab/logic-gates/combinatorial2-xor.png new file mode 100644 index 00000000..88085c48 Binary files /dev/null and b/docs/static/courses/logic-lab/logic-gates/combinatorial2-xor.png differ diff --git a/docs/static/courses/logic-lab/logic-gates/full-adder.png b/docs/static/courses/logic-lab/logic-gates/full-adder.png new file mode 100644 index 00000000..c4db02c7 Binary files /dev/null and b/docs/static/courses/logic-lab/logic-gates/full-adder.png differ diff --git a/docs/static/courses/logic-lab/logic-gates/logic-lab-header.jpg b/docs/static/courses/logic-lab/logic-gates/logic-lab-header.jpg new file mode 100644 index 00000000..bcaafb8c Binary files /dev/null and b/docs/static/courses/logic-lab/logic-gates/logic-lab-header.jpg differ diff --git a/docs/static/courses/logic-lab/logic-gates/not-gate.png b/docs/static/courses/logic-lab/logic-gates/not-gate.png new file mode 100644 index 00000000..f543c51c Binary files /dev/null and b/docs/static/courses/logic-lab/logic-gates/not-gate.png differ diff --git a/docs/static/courses/logic-lab/logic-gates/or-gate.png b/docs/static/courses/logic-lab/logic-gates/or-gate.png new file mode 100644 index 00000000..a19b6103 Binary files /dev/null and b/docs/static/courses/logic-lab/logic-gates/or-gate.png differ diff --git a/docs/static/courses/logic-lab/logic-gates/xor-gate.png b/docs/static/courses/logic-lab/logic-gates/xor-gate.png new file mode 100644 index 00000000..3c3cfeb0 Binary files /dev/null and b/docs/static/courses/logic-lab/logic-gates/xor-gate.png differ diff --git a/docs/static/courses/logic-lab/logic-lab-header.jpg b/docs/static/courses/logic-lab/logic-lab-header.jpg new file mode 100644 index 00000000..f27892b1 Binary files /dev/null and b/docs/static/courses/logic-lab/logic-lab-header.jpg differ diff --git a/docs/static/courses/logic-lab/pld/and-gate-pins.png b/docs/static/courses/logic-lab/pld/and-gate-pins.png new file mode 100644 index 00000000..a61bc826 Binary files /dev/null and b/docs/static/courses/logic-lab/pld/and-gate-pins.png differ diff --git a/docs/static/courses/logic-lab/pld/and-gate-pld.png b/docs/static/courses/logic-lab/pld/and-gate-pld.png new file mode 100644 index 00000000..0848e799 Binary files /dev/null and b/docs/static/courses/logic-lab/pld/and-gate-pld.png differ diff --git a/docs/static/courses/logic-lab/pld/generic-pld.png b/docs/static/courses/logic-lab/pld/generic-pld.png new file mode 100644 index 00000000..67b1ad0d Binary files /dev/null and b/docs/static/courses/logic-lab/pld/generic-pld.png differ diff --git a/docs/static/courses/logic-lab/pld/mbit-pld.png b/docs/static/courses/logic-lab/pld/mbit-pld.png new file mode 100644 index 00000000..3ecc14b5 Binary files /dev/null and b/docs/static/courses/logic-lab/pld/mbit-pld.png differ diff --git a/docs/static/courses/logic-lab/pld/not-and-or-pld.png b/docs/static/courses/logic-lab/pld/not-and-or-pld.png new file mode 100644 index 00000000..d28eb9ba Binary files /dev/null and b/docs/static/courses/logic-lab/pld/not-and-or-pld.png differ diff --git a/docs/static/courses/logic-lab/pld/not-and-or.png b/docs/static/courses/logic-lab/pld/not-and-or.png new file mode 100644 index 00000000..abdebb51 Binary files /dev/null and b/docs/static/courses/logic-lab/pld/not-and-or.png differ diff --git a/docs/static/courses/logic-lab/pld/not-gate-pins.png b/docs/static/courses/logic-lab/pld/not-gate-pins.png new file mode 100644 index 00000000..4024124a Binary files /dev/null and b/docs/static/courses/logic-lab/pld/not-gate-pins.png differ diff --git a/docs/static/courses/logic-lab/pld/not-gate-pld.png b/docs/static/courses/logic-lab/pld/not-gate-pld.png new file mode 100644 index 00000000..f8c0e916 Binary files /dev/null and b/docs/static/courses/logic-lab/pld/not-gate-pld.png differ diff --git a/docs/static/courses/logic-lab/pld/or-gate-pins.png b/docs/static/courses/logic-lab/pld/or-gate-pins.png new file mode 100644 index 00000000..e69cb603 Binary files /dev/null and b/docs/static/courses/logic-lab/pld/or-gate-pins.png differ diff --git a/docs/static/courses/logic-lab/pld/or-gate-pld.png b/docs/static/courses/logic-lab/pld/or-gate-pld.png new file mode 100644 index 00000000..43a182c3 Binary files /dev/null and b/docs/static/courses/logic-lab/pld/or-gate-pld.png differ diff --git a/docs/static/courses/logic-lab/pld/xor-gate-pld.png b/docs/static/courses/logic-lab/pld/xor-gate-pld.png new file mode 100644 index 00000000..adc5bc1f Binary files /dev/null and b/docs/static/courses/logic-lab/pld/xor-gate-pld.png differ diff --git a/docs/static/courses/logic-lab/pld/xor-mbit.png b/docs/static/courses/logic-lab/pld/xor-mbit.png new file mode 100644 index 00000000..34b44178 Binary files /dev/null and b/docs/static/courses/logic-lab/pld/xor-mbit.png differ diff --git a/docs/static/fonts/Roboto_400_normal.svg b/docs/static/fonts/Roboto_400_normal.svg new file mode 100644 index 00000000..627f5a36 --- /dev/null +++ b/docs/static/fonts/Roboto_400_normal.svg @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/static/fonts/Roboto_400_normal.ttf b/docs/static/fonts/Roboto_400_normal.ttf new file mode 100644 index 00000000..45d1e376 Binary files /dev/null and b/docs/static/fonts/Roboto_400_normal.ttf differ diff --git a/docs/static/fonts/Roboto_400_normal.woff b/docs/static/fonts/Roboto_400_normal.woff new file mode 100644 index 00000000..296609e0 Binary files /dev/null and b/docs/static/fonts/Roboto_400_normal.woff differ diff --git a/docs/static/libs/radio.png b/docs/static/libs/radio.png new file mode 100644 index 00000000..e211d6eb Binary files /dev/null and b/docs/static/libs/radio.png differ diff --git a/docs/static/live-coding/live.jpg b/docs/static/live-coding/live.jpg new file mode 100644 index 00000000..0e07f77a Binary files /dev/null and b/docs/static/live-coding/live.jpg differ diff --git a/docs/static/live-coding/live.png b/docs/static/live-coding/live.png new file mode 100644 index 00000000..77c27a79 Binary files /dev/null and b/docs/static/live-coding/live.png differ diff --git a/docs/static/live-coding/playlist.png b/docs/static/live-coding/playlist.png new file mode 100644 index 00000000..a0fcafcb Binary files /dev/null and b/docs/static/live-coding/playlist.png differ diff --git a/docs/static/live-coding/showleds.jpg b/docs/static/live-coding/showleds.jpg new file mode 100644 index 00000000..56e5465e Binary files /dev/null and b/docs/static/live-coding/showleds.jpg differ diff --git a/docs/static/live-coding/showstring.jpg b/docs/static/live-coding/showstring.jpg new file mode 100644 index 00000000..93845e2f Binary files /dev/null and b/docs/static/live-coding/showstring.jpg differ diff --git a/docs/static/mb/projects/name-badge.png b/docs/static/mb/projects/name-badge.png new file mode 100644 index 00000000..97fb9369 Binary files /dev/null and b/docs/static/mb/projects/name-badge.png differ diff --git a/docs/static/mb/projects/name-badge/header.png b/docs/static/mb/projects/name-badge/header.png new file mode 100644 index 00000000..3d8dede2 Binary files /dev/null and b/docs/static/mb/projects/name-badge/header.png differ diff --git a/docs/static/mb/projects/name-badge/picture1.png b/docs/static/mb/projects/name-badge/picture1.png new file mode 100644 index 00000000..120dd908 Binary files /dev/null and b/docs/static/mb/projects/name-badge/picture1.png differ diff --git a/docs/static/mb/projects/name-badge/picture2.png b/docs/static/mb/projects/name-badge/picture2.png new file mode 100644 index 00000000..9256ecd6 Binary files /dev/null and b/docs/static/mb/projects/name-badge/picture2.png differ diff --git a/docs/static/mb/projects/name-badge/picture3.png b/docs/static/mb/projects/name-badge/picture3.png new file mode 100644 index 00000000..c4138451 Binary files /dev/null and b/docs/static/mb/projects/name-badge/picture3.png differ diff --git a/docs/static/mb/projects/name-badge/picture4.png b/docs/static/mb/projects/name-badge/picture4.png new file mode 100644 index 00000000..241dc087 Binary files /dev/null and b/docs/static/mb/projects/name-badge/picture4.png differ diff --git a/docs/static/mb/projects/name-badge/picture5.png b/docs/static/mb/projects/name-badge/picture5.png new file mode 100644 index 00000000..0baa5154 Binary files /dev/null and b/docs/static/mb/projects/name-badge/picture5.png differ diff --git a/docs/static/mb/projects/name-badge/picture6.png b/docs/static/mb/projects/name-badge/picture6.png new file mode 100644 index 00000000..ae16d6c7 Binary files /dev/null and b/docs/static/mb/projects/name-badge/picture6.png differ diff --git a/docs/static/mb/projects/name-badge/picture7.png b/docs/static/mb/projects/name-badge/picture7.png new file mode 100644 index 00000000..6e759577 Binary files /dev/null and b/docs/static/mb/projects/name-badge/picture7.png differ diff --git a/docs/static/mb/projects/name-badge/picture8.png b/docs/static/mb/projects/name-badge/picture8.png new file mode 100644 index 00000000..47648d8a Binary files /dev/null and b/docs/static/mb/projects/name-badge/picture8.png differ diff --git a/docs/static/mb/projects/name-badge/picture9.png b/docs/static/mb/projects/name-badge/picture9.png new file mode 100644 index 00000000..9b77ff9a Binary files /dev/null and b/docs/static/mb/projects/name-badge/picture9.png differ diff --git a/docs/static/mb/projects/robot-unicorn/microbitsunicorn.jpg b/docs/static/mb/projects/robot-unicorn/microbitsunicorn.jpg new file mode 100644 index 00000000..01814d15 Binary files /dev/null and b/docs/static/mb/projects/robot-unicorn/microbitsunicorn.jpg differ diff --git a/docs/static/mb/projects/robot-unicorn/robotunicorn.jpg b/docs/static/mb/projects/robot-unicorn/robotunicorn.jpg new file mode 100644 index 00000000..0299b851 Binary files /dev/null and b/docs/static/mb/projects/robot-unicorn/robotunicorn.jpg differ diff --git a/docs/static/mb/projects/robot-unicorn/robotunicorntail.jpg b/docs/static/mb/projects/robot-unicorn/robotunicorntail.jpg new file mode 100644 index 00000000..bbaa8d62 Binary files /dev/null and b/docs/static/mb/projects/robot-unicorn/robotunicorntail.jpg differ diff --git a/docs/static/mb/projects/rotary-dial-radio.png b/docs/static/mb/projects/rotary-dial-radio.png new file mode 100644 index 00000000..9e1df002 Binary files /dev/null and b/docs/static/mb/projects/rotary-dial-radio.png differ diff --git a/docs/static/mb/projects/rotary-dial-radio/final.jpg b/docs/static/mb/projects/rotary-dial-radio/final.jpg new file mode 100644 index 00000000..2a2ab2db Binary files /dev/null and b/docs/static/mb/projects/rotary-dial-radio/final.jpg differ diff --git a/docs/static/mb/projects/rotary-dial-radio/guts.jpg b/docs/static/mb/projects/rotary-dial-radio/guts.jpg new file mode 100644 index 00000000..463f818a Binary files /dev/null and b/docs/static/mb/projects/rotary-dial-radio/guts.jpg differ diff --git a/docs/static/mb/projects/rotary-dial-radio/oldphone.jpg b/docs/static/mb/projects/rotary-dial-radio/oldphone.jpg new file mode 100644 index 00000000..be98a978 Binary files /dev/null and b/docs/static/mb/projects/rotary-dial-radio/oldphone.jpg differ diff --git a/docs/static/mb/projects/rotary-dial-radio/wired.jpg b/docs/static/mb/projects/rotary-dial-radio/wired.jpg new file mode 100644 index 00000000..19a5d252 Binary files /dev/null and b/docs/static/mb/projects/rotary-dial-radio/wired.jpg differ diff --git a/docs/static/mb/science-experiments/battery-tester.jpg b/docs/static/mb/science-experiments/battery-tester.jpg new file mode 100644 index 00000000..bc44f336 Binary files /dev/null and b/docs/static/mb/science-experiments/battery-tester.jpg differ diff --git a/docs/static/mb/science-experiments/data-collection.jpg b/docs/static/mb/science-experiments/data-collection.jpg new file mode 100644 index 00000000..73c4fc32 Binary files /dev/null and b/docs/static/mb/science-experiments/data-collection.jpg differ diff --git a/docs/static/mb/science-experiments/egg-drop.jpg b/docs/static/mb/science-experiments/egg-drop.jpg new file mode 100644 index 00000000..70af283e Binary files /dev/null and b/docs/static/mb/science-experiments/egg-drop.jpg differ diff --git a/docs/static/mb/science-experiments/emg-muscle-sensor.jpg b/docs/static/mb/science-experiments/emg-muscle-sensor.jpg new file mode 100644 index 00000000..bc90db9f Binary files /dev/null and b/docs/static/mb/science-experiments/emg-muscle-sensor.jpg differ diff --git a/docs/static/mb/science-experiments/population-trait.jpg b/docs/static/mb/science-experiments/population-trait.jpg new file mode 100644 index 00000000..672132fe Binary files /dev/null and b/docs/static/mb/science-experiments/population-trait.jpg differ diff --git a/docs/static/mb/science-experiments/rocket-acceleration.jpg b/docs/static/mb/science-experiments/rocket-acceleration.jpg new file mode 100644 index 00000000..b8f11bd2 Binary files /dev/null and b/docs/static/mb/science-experiments/rocket-acceleration.jpg differ diff --git a/docs/static/mb/science-experiments/soil-moisture.jpg b/docs/static/mb/science-experiments/soil-moisture.jpg new file mode 100644 index 00000000..276ed772 Binary files /dev/null and b/docs/static/mb/science-experiments/soil-moisture.jpg differ diff --git a/docs/static/mb/science-experiments/temperature-sensor.jpg b/docs/static/mb/science-experiments/temperature-sensor.jpg new file mode 100644 index 00000000..dd8866cd Binary files /dev/null and b/docs/static/mb/science-experiments/temperature-sensor.jpg differ diff --git a/docs/static/mb/translate/libsfiles.png b/docs/static/mb/translate/libsfiles.png new file mode 100644 index 00000000..3005c6f5 Binary files /dev/null and b/docs/static/mb/translate/libsfiles.png differ diff --git a/docs/static/mb/translate/stringsfile.png b/docs/static/mb/translate/stringsfile.png new file mode 100644 index 00000000..45f03b23 Binary files /dev/null and b/docs/static/mb/translate/stringsfile.png differ diff --git a/docs/static/mb/translate/targetstringsfile.png b/docs/static/mb/translate/targetstringsfile.png new file mode 100644 index 00000000..9a3b5848 Binary files /dev/null and b/docs/static/mb/translate/targetstringsfile.png differ diff --git a/docs/static/packages/radio-broadcast/icon.png b/docs/static/packages/radio-broadcast/icon.png new file mode 100644 index 00000000..e211d6eb Binary files /dev/null and b/docs/static/packages/radio-broadcast/icon.png differ diff --git a/docs/static/packages/radio-broadcast/icon.svg b/docs/static/packages/radio-broadcast/icon.svg new file mode 100644 index 00000000..7ff5d6a4 --- /dev/null +++ b/docs/static/packages/radio-broadcast/icon.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + diff --git a/docs/static/translate/targetjsonfile.png b/docs/static/translate/targetjsonfile.png new file mode 100644 index 00000000..9a3b5848 Binary files /dev/null and b/docs/static/translate/targetjsonfile.png differ diff --git a/docs/static/translate/targetstringsfile.png b/docs/static/translate/targetstringsfile.png new file mode 100644 index 00000000..9a3b5848 Binary files /dev/null and b/docs/static/translate/targetstringsfile.png differ diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md new file mode 100644 index 00000000..4252084e --- /dev/null +++ b/docs/tutorials/getting-started.md @@ -0,0 +1,69 @@ +# Getting Started + +## Step 1 + +Welcome! Place the ``||basic:show string||`` block in the ``||basic:on start||`` slot. Replace the ``"Hello"`` text with your name. Did you see it scroll in the simulator? + +```blocks +basic.showString("Micro!") +``` + +## Step 2 + +Well, the text stopped scrolling. Place the ``||basic:show string||`` block in the ``||input:on button pressed||`` slot to scroll your name when button **A** is pressed. + +```blocks +input.onButtonPressed(Button.A, () => { + basic.showString("Micro!") +}); +``` + +## Step 3 + +Place some blocks to display a smiley when button **B** is pressed. + +Use the dropdown to find ``B``! + +```blocks +input.onButtonPressed(Button.B, () => { + basic.showLeds(` + # # . # # + # # . # # + . . . . . + # . . . # + . # # # . + `) +}) +``` + +## Step 4 + +Place the ``||basic:show number||`` and ``||Math:pick random||`` blocks in an ``||input:on shake||`` block to build a dice. + +```blocks +input.onGesture(Gesture.Shake, () => { + basic.showNumber(randint(0, 10)) +}) +``` + +## Step 5 + +A typical dice shows values from `1` to `6`. So, in ``||Math:pick random||``, don't forget to choose the right minimum and maximum values! + +```blocks +input.onGesture(Gesture.Shake, () => { + basic.showNumber(randint(1, 6)) +}) +``` + +## Step 6 + +If you have a @boardname@, connect a USB cable to it and click ``|Download|``. Save the program to the **@drivename@** drive. This transfers your code to the @boardname@! + +## Step 7 + +On the @boardname@, press button **A** to scroll your text. Press button **B** to show a smiley. Shake the @boardname@ and see which number is chosen. + +## Step 8 + +Well done! You've completed your first Microsoft MakeCode activity. diff --git a/docs/tutorials/hour-of-code/hey-microbit.md b/docs/tutorials/hour-of-code/hey-microbit.md new file mode 100644 index 00000000..f8057e71 --- /dev/null +++ b/docs/tutorials/hour-of-code/hey-microbit.md @@ -0,0 +1,149 @@ +# Hey, @boardname@! + +## Step 1 + +Welcome, let's code the @boardname@! Place the ``||basic:show string||`` block in the ``||basic:on start||`` slot. Change the ``"Hello"`` text to be your name instead. Did you see it scroll in the simulator?. + +```blocks +basic.showString("My Name") +``` + +## Step 2 + +Well, you noticed that the text stopped. Place the ``||basic:show string||`` block in an ``||input:on button pressed||`` block to scroll your name whenever button **A** is pressed. + +```block +input.onButtonPressed(Button.A, () => { + basic.showString("My Name") +}); +``` + +## Step 3 + +Ok, let's try to talk to the @boardname@ using a button. Change the text in ``||basic:show string||`` to ask the question "How are you?". Add another ``||basic:show string||`` with "....." to show that the @boardname@ is thinking. + +```block +input.onButtonPressed(Button.A, () => { + basic.showString("How are you?") + basic.showString("....."); +}) +``` + +## Step 4 + +Now, make the @boardname@ give an answer with a smiley face! Find the ``||basic:show leds||`` and draw a smiley face on the block by clicking on the LEDs. Press button **A** in the simulator and see the @boardname@ respond to your question. + +```block +input.onButtonPressed(Button.A, () => { + basic.showString("How are you?") + basic.showString("....."); + basic.showLeds(` + # # . # # + # # . # # + . . . . . + # . . . # + . # # # . + `) +}) +``` + +## Step 5 + +OK, let's ask @boardname@ how it's feeling just now, but by a different method. We can use the shake gesture to ask the question. Go get an ``||input:on shake||`` block. Go grab your ``||basic:show leds||`` block from before and and put it in the ``||input:on shake||``. + +```block +input.onGesture(Gesture.Shake, () => { + basic.showLeds(` + # # . # # + # # . # # + . . . . . + # . . . # + . # # # . + `) +}) +``` + +## Step 6 + +We want the @boardname@ to change how it feels at different times. It will have two moods, happy and sad. Go to **Logic** and get an ``||logic:if then else||``. Put it in the ``||input:on shake||`` and move the ``||basic:show leds||`` into the ``||logic:if then||`` slot. + +```block +input.onGesture(Gesture.Shake, () => { + if (true) { + basic.showLeds(` + # # . # # + # # . # # + . . . . . + # . . . # + . # # # . + `) + } else { + + } +}) +``` + +## Step 7 + +Duplicate the ``||basic:show leds||`` block (right-click, then choose Duplicate). Put the new one into the ``||logic:else||`` part of the ``||logic:if then else||``. This time, turn that one into a frowny face. + +```block +input.onGesture(Gesture.Shake, () => { + if (true) { + basic.showLeds(` + # # . # # + # # . # # + . . . . . + # . . . # + . # # # . + `) + } else { + basic.showLeds(` + # # . # # + # # . # # + . . . . . + . # # # . + # . . . # + `) + } +}) +``` + +## Step 8 + +Test it's mood by changing the condition in the ``||logic:if||`` from `true` to `false` and then click the **SHAKE** spot in the simulator. + +## Step 9 + +So, to make the @boardname@ more fickle, let's give it a random mood. Find the ``||math:pick random true or false||`` block in **Math**. Pull it out and use it in the ``||logic:if||`` condition instead of the `true` value. + +```block +input.onGesture(Gesture.Shake, () => { + if (Math.randomBoolean()) { + basic.showLeds(` + # # . # # + # # . # # + . . . . . + # . . . # + . # # # . + `) + } else { + basic.showLeds(` + # # . # # + # # . # # + . . . . . + . # # # . + # . . . # + `) + } +}) +``` + +## Step 10 + +Now, click the **SHAKE** spot a few times to see how the @boardname@ is feeling. Hmm, it's mood is different sometimes! + +## Step 11 + +Awesome job! You've completed your Microsoft MakeCode activity. If you have a @boardname@ to use, click the `|Download|` button and try your code on the board. + diff --git a/docs/tutorials/hour-of-code/rock-paper-scissors.md b/docs/tutorials/hour-of-code/rock-paper-scissors.md new file mode 100644 index 00000000..959a0913 --- /dev/null +++ b/docs/tutorials/hour-of-code/rock-paper-scissors.md @@ -0,0 +1,160 @@ +# Rock Paper Scissors + +## Step 1 + +We want the @boardname@ to choose rock, paper, or scissors when you shake it. +Place a ``||input:on shake||`` block so when you shake the @boardname@, it will run part of a program. + +```blocks +input.onGesture(Gesture.Shake, () => { + +}) +``` + +## Step 2 + +Add a ``tool`` variable to store a random number computed with ``||math:pick random||``. + +When you shake the @boardname@, it should pick a random number from `0` to `2` +and store it in the variable `tool`. (This variable is named `tool` because +rock, paper, and scissors are the tools you use to challenge your friends!) + +```blocks +let tool = 0; +input.onGesture(Gesture.Shake, () => { + tool = randint(0, 3) +}) +``` + +In a later step, each of the possible numbers (`0`, `1`, or `2`) is matched to its own picture. The picture is shown on the LEDs when its number is picked. + +## Step 3 + +Place an ``if`` block under the ``||math:pick random||`` and +check whether ``tool`` is equal to ``0``. + +```blocks +let tool = 0; +input.onGesture(Gesture.Shake, () => { + let tool = randint(0, 3) + if (tool == 0) { + } +}) +``` + +## Step 4 + +In the ``if`` block, place a ``||basic:show leds||`` block that shows a +picture of a piece of paper. + +```blocks +let tool = 0; +input.onGesture(Gesture.Shake, () => { + let tool = randint(0, 3) + if (tool == 0) { + basic.showLeds(` + # # # # # + # . . . # + # . . . # + # . . . # + # # # # # + `) + } +}) +``` + +## Step 5 + +Add an ``else if`` block to the ``if`` block and check whether ``tool`` +is equal to ``1``. + +Click on the **(+)** at the bottom of the ``if`` block to add an ``else if`` section. + +```blocks +let tool = 0; +input.onGesture(Gesture.Shake, () => { + let tool = randint(0, 3) + if (tool == 0) { + basic.showLeds(` + # # # # # + # . . . # + # . . . # + # . . . # + # # # # # + `) + } else if (tool == 1) { + } +}) +``` + +## Step 6 + +Place a ``||basic:show leds||`` block under the else if and draw a **rock** image on the screen. + +```blocks +let tool = 0; +input.onGesture(Gesture.Shake, () => { + let tool = randint(0, 3) + if (tool == 0) { + basic.showLeds(` + # # # # # + # . . . # + # . . . # + # . . . # + # # # # # + `) + } else if (tool == 1) { + basic.showLeds(` + . . . . . + . # # # . + . # # # . + . # # # . + . . . . . + `) + } +}) +``` + +## Step 7 + +Add a ``||basic:show leds||`` block with a picture of scissors to the ``else`` part. + +You don't need to check if `tool` 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``. + +```blocks +let tool = 0; +input.onGesture(Gesture.Shake, () => { + let tool = randint(0, 3) + if (tool == 0) { + basic.showLeds(` + # # # # # + # . . . # + # . . . # + # . . . # + # # # # # + `) + } else if (tool == 1) { + basic.showLeds(` + . . . . . + . # # # . + . # # # . + . # # # . + . . . . . + `) + } else { + basic.showLeds(` + # # . . # + # # . # . + . . # . . + # # . # . + # # . . # + `) + } +}) + +``` + +## Step 8 + +Your game is ready! Gather your friends and play Rock Paper Scissors! \ No newline at end of file diff --git a/editor/dialogs.tsx b/editor/dialogs.tsx new file mode 100644 index 00000000..b5190fae --- /dev/null +++ b/editor/dialogs.tsx @@ -0,0 +1,123 @@ +import * as React from "react"; + +export function renderUsbPairDialog(firmwareUrl?: string, failedOnce?: boolean): JSX.Element { + const boardName = pxt.appTarget.appTheme.boardName || "???"; + const helpUrl = pxt.appTarget.appTheme.usbDocs; + firmwareUrl = failedOnce && `${helpUrl}/webusb/troubleshoot`; // todo mo + + const instructions =
+
+
+
+
+
+
+ {lf("Comic +
+
+
+ 1 + {lf("Connect the {0} to your computer with a USB cable", boardName)} +
+ {lf("Use the microUSB port on the top of the {0}", boardName)} +
+
+
+
+
+
+
+ {lf("Comic +
+
+
+ 2 + {lf("Pair your {0}", boardName)} +
+ {lf("Click 'Pair device' below and select 'Calliope mini' or 'DAPLink CMSIS-DAP' from the list")} +
+
+
+
+
+
+
+
; + + if (!firmwareUrl) return instructions; + + return
+
+
{lf("Update Firmware")}
+ {lf("You must have version 0249 or above of the firmware")} +
+ {lf("Comic +
+ {lf("Check Firmware")} +
+
+ {instructions} +
+
; +} + +export function renderBrowserDownloadInstructions(): JSX.Element { + const boardName = pxt.appTarget.appTheme.boardName || lf("device"); + const boardDriveName = pxt.appTarget.appTheme.driveDisplayName || pxt.appTarget.compile.driveName || "???"; + return
+
+
+
+
+
+
+
+
+ {lf("Comic +
+
+
+ 1 + {lf("Connect the {0} to your computer with a USB cable", boardName)} +
+ {lf("Use the microUSB port on the top of the {0}", boardName)} +
+
+
+
+
+
+
+ {lf("Comic +
+
+
+ 2 + {lf("Move the .hex file to the {0}", boardName)} +
+ {lf("Locate the downloaded .hex file and drag it to the {0} drive", boardDriveName)} +
+
+
+
+
+
+
+
+
+
; +} + +export function cantImportAsync(project: pxt.editor.IProjectView) { + // this feature is support in v0 only + return project.showModalDialogAsync({ + header: lf("Can't import microbit.co.uk scripts..."), + body: lf("Importing microbit.co.uk programs is not supported in this editor anymore. Please open this script in the https://makecode.microbit.org/v0 editor."), + buttons: [ + { + label: lf("Go to the old editor"), + url: `https://makecode.microbit.org/v0` + } + ] + }).then(() => project.openHome()) +} diff --git a/editor/extension.tsx b/editor/extension.tsx index 30d282db..1992e32c 100644 --- a/editor/extension.tsx +++ b/editor/extension.tsx @@ -4,810 +4,13 @@ /// /// /// -import * as React from "react"; - -const imul = (Math as any).imul; -const pageSize = 1024; -const numPages = 256; -const timeoutMessage = "timeout"; - -function murmur3_core(data: Uint8Array) { - let h0 = 0x2F9BE6CC; - let h1 = 0x1EC3A6C8; - - for (let i = 0; i < data.length; i += 4) { - let k = pxt.HF2.read32(data, i) >>> 0 - k = imul(k, 0xcc9e2d51); - k = (k << 15) | (k >>> 17); - k = imul(k, 0x1b873593); - - h0 ^= k; - h1 ^= k; - h0 = (h0 << 13) | (h0 >>> 19); - h1 = (h1 << 13) | (h1 >>> 19); - h0 = (imul(h0, 5) + 0xe6546b64) >>> 0; - h1 = (imul(h1, 5) + 0xe6546b64) >>> 0; - } - return [h0, h1] -} - -class DAPWrapper { - cortexM: DapJS.CortexM - packetIo: pxt.HF2.PacketIO; - cmsisdap: any; - flashing = true; - pbuf = new pxt.U.PromiseBuffer(); - private useSerial = true; - - constructor(h: pxt.HF2.PacketIO) { - this.packetIo = h; - - h.onData = buf => { - // console.log("RD: " + pxt.Util.toHex(buf)) - this.pbuf.push(buf); - } - - this.allocDAP() - - const readSerial = () => { - if (!this.useSerial) { - return - } - - if (this.flashing) { - setTimeout(readSerial, 300) - return - } - - this.cmsisdap.cmdNums(0x83, []) - .then((r: number[]) => { - const len = r[1] - let str = "" - for (let i = 2; i < len + 2; ++i) { - str += String.fromCharCode(r[i]) - } - if (str.length > 0) { - pxt.U.nextTick(readSerial) - window.postMessage({ - type: 'serial', - id: 'n/a', // TODO - data: str - }, "*") - // console.log("SERIAL: " + str) - } else - setTimeout(readSerial, 50) - }, (err: any) => { - setTimeout(readSerial, 1000) - }) - } - - readSerial() - } - - private allocDAP() { - /* - let sendMany = (cmds: Uint8Array[]) => { - return h.talksAsync(cmds.map(c => ({ cmd: 0, data: c }))); - } - - if (!h.talksAsync) - sendMany = null; - */ - - let dev = new DapJS.DAP({ - write: writeAsync, - close: this.disconnectAsync, - read: readAsync, - //sendMany: sendMany - }); - this.cmsisdap = (dev as any).dap; - this.cortexM = new DapJS.CortexM(dev); - - let h = this.packetIo - let pbuf = this.pbuf - - function writeAsync(data: ArrayBuffer) { - // console.log("WR: " + pxt.Util.toHex(new Uint8Array(data))); - return h.sendPacketAsync(new Uint8Array(data)); - } - - function readAsync() { - return pbuf.shiftAsync(); - } - } - - reconnectAsync(first: boolean) { - // configure serial at 115200 - let p = Promise.resolve(); - if (!first) { - p = this.packetIo.reconnectAsync() - .then(() => this.allocDAP()); - } - - return p - .then(() => this.cortexM.init()) - .then(() => { - return this.cmsisdap.cmdNums(0x82, [0x00, 0xC2, 0x01, 0x00]) - .then(() => { this.useSerial = true }, (err: any) => { this.useSerial = false; }); - }); - } - - disconnectAsync() { - return this.packetIo.disconnectAsync(); - } -} - -let packetIoPromise: Promise; -function initPacketIOAsync(): Promise { - if (!packetIoPromise) { - packetIoPromise = pxt.HF2.mkPacketIOAsync() - .catch(err => { - packetIoPromise = null; - return Promise.reject(err); - }); - return packetIoPromise; - } else { - let packetIo: pxt.HF2.PacketIO; - return packetIoPromise - .then((io) => { - packetIo = io; - return io.reconnectAsync(); - }) - .then(() => packetIo); - } -} - -let previousDapWrapper: DAPWrapper; -function dapAsync() { - if (previousDapWrapper) - return previousDapWrapper.reconnectAsync(false) // Always fully reconnect to handle device unplugged mid-session - .then(() => previousDapWrapper); - return Promise.resolve() - .then(() => { - if (previousDapWrapper) { - return previousDapWrapper.disconnectAsync() - .finally(() => { - previousDapWrapper = null; - }); - } - return Promise.resolve(); - }) - .then(() => initPacketIOAsync()) - .then(h => { - let w = new DAPWrapper(h) - previousDapWrapper = w; - return w.reconnectAsync(true) - .then(() => { - return w - }) - }) -} - -function canHID(): boolean { - let r = false - if (pxt.usb.isEnabled) { - r = true - } else if (pxt.U.isNodeJS) { - r = true - } else { - const forceHexDownload = /forceHexDownload/i.test(window.location.href); - const isUwp = !!(window as any).Windows; - if (pxt.BrowserUtils.isLocalHost() && pxt.Cloud.localToken && !forceHexDownload || isUwp) - r = true - } - return r; -} - -function initAsync() { - if (canHID()) { - return dapAsync(); - } else { - return Promise.reject(new Error("no HID")) - } -} - -function pageAlignBlocks(blocks: ts.pxtc.UF2.Block[], pageSize: number) { - pxt.U.assert(pageSize % 256 == 0) - let res: ts.pxtc.UF2.Block[] = [] - for (let i = 0; i < blocks.length;) { - let b0 = blocks[i] - let newbuf = new Uint8Array(pageSize) - let startPad = b0.targetAddr & (pageSize - 1) - let newAddr = b0.targetAddr - startPad - for (; i < blocks.length; ++i) { - let b = blocks[i] - if (b.targetAddr + b.payloadSize > newAddr + pageSize) - break - pxt.U.memcpy(newbuf, b.targetAddr - newAddr, b.data, 0, b.payloadSize) - } - let bb = pxt.U.flatClone(b0) - bb.data = newbuf - bb.targetAddr = newAddr - bb.payloadSize = pageSize - res.push(bb) - } - return res -} - -const flashPageBINquick = new Uint32Array([ - 0xbe00be00, // bkpt - LR is set to this - 0x2480b5f0, 0x00e42300, 0x58cd58c2, 0xd10342aa, 0x42a33304, 0xbdf0d1f8, - 0x4b162502, 0x509d4a16, 0x2d00591d, 0x24a1d0fc, 0x511800e4, 0x3cff3c09, - 0x591e0025, 0xd0fc2e00, 0x509c2400, 0x2c00595c, 0x2401d0fc, 0x509c2580, - 0x595c00ed, 0xd0fc2c00, 0x00ed2580, 0x002e2400, 0x5107590f, 0x2f00595f, - 0x3404d0fc, 0xd1f742ac, 0x50992100, 0x2a00599a, 0xe7d0d0fc, 0x4001e000, - 0x00000504, -]) - -// doesn't check if data is already there - for timing -const flashPageBIN = new Uint32Array([ - 0xbe00be00, // bkpt - LR is set to this - 0x2402b5f0, 0x4a174b16, 0x2480509c, 0x002500e4, 0x2e00591e, 0x24a1d0fc, - 0x511800e4, 0x2c00595c, 0x2400d0fc, 0x2480509c, 0x002500e4, 0x2e00591e, - 0x2401d0fc, 0x595c509c, 0xd0fc2c00, 0x00ed2580, 0x002e2400, 0x5107590f, - 0x2f00595f, 0x3404d0fc, 0xd1f742ac, 0x50992100, 0x2a00599a, 0xbdf0d0fc, - 0x4001e000, 0x00000504, -]) - -// void computeHashes(uint32_t *dst, uint8_t *ptr, uint32_t pageSize, uint32_t numPages) -const computeChecksums2 = new Uint32Array([ - 0x4c27b5f0, 0x44a52680, 0x22009201, 0x91004f25, 0x00769303, 0x24080013, - 0x25010019, 0x40eb4029, 0xd0002900, 0x3c01407b, 0xd1f52c00, 0x468c0091, - 0xa9044665, 0x506b3201, 0xd1eb42b2, 0x089b9b01, 0x23139302, 0x9b03469c, - 0xd104429c, 0x2000be2a, 0x449d4b15, 0x9f00bdf0, 0x4d149e02, 0x49154a14, - 0x3e01cf08, 0x2111434b, 0x491341cb, 0x405a434b, 0x4663405d, 0x230541da, - 0x4b10435a, 0x466318d2, 0x230541dd, 0x4b0d435d, 0x2e0018ed, 0x6002d1e7, - 0x9a009b01, 0x18d36045, 0x93003008, 0xe7d23401, 0xfffffbec, 0xedb88320, - 0x00000414, 0x1ec3a6c8, 0x2f9be6cc, 0xcc9e2d51, 0x1b873593, 0xe6546b64, -]) - -let startTime = 0 -function log(msg: string) { - let now = Date.now() - if (!startTime) startTime = now - now -= startTime - let ts = ("00000" + now).slice(-5) - pxt.log(`HID ${ts}: ${msg}`) -} - -const membase = 0x20000000 -const loadAddr = membase -const dataAddr = 0x20002000 -const stackAddr = 0x20001000 - -export const bufferConcat = (bufs: Uint8Array[]) => { - let len = 0; - for (const b of bufs) { - len += b.length; - } - const r = new Uint8Array(len); - len = 0; - for (const b of bufs) { - r.set(b, len); - len += b.length; - } - return r; -}; - -function fullVendorCommandFlashAsync(resp: pxtc.CompileResult, wrap: DAPWrapper): Promise { - const chunkSize = 62; - let aborted = false; - - return Promise.resolve() - .then(() => { - return wrap.cmsisdap.cmdNums(0x8A /* DAPLinkFlash.OPEN */, [1]); - }) - .then((res) => { - const hexUint8 = pxt.U.stringToUint8Array(resp.outfiles[pxtc.BINARY_HEX]); - const hexArray: number[] = Array.prototype.slice.call(hexUint8); - - const sendPages = (offset: number = 0): Promise => { - const end = Math.min(hexArray.length, offset + chunkSize); - const nextPage = hexArray.slice(offset, end); - nextPage.unshift(nextPage.length); - return wrap.cmsisdap.cmdNums(0x8C /* DAPLinkFlash.WRITE */, nextPage) - .then(() => { - if (!aborted && end < hexArray.length) { - return sendPages(end); - } - return Promise.resolve(); - }); - } - - return sendPages(); - }) - .then((res) => { - return wrap.cmsisdap.cmdNums(0x8B /* DAPLinkFlash.CLOSE */, []); - }) - .timeout(60000, timeoutMessage) - .catch((e) => { - aborted = true; - return wrap.cmsisdap.cmdNums(0x89 /* DAPLinkFlash.RESET */, []) - .catch((e2: any) => { - // Best effort reset, no-op if there's an error - }) - .then(() => { - return Promise.reject(e); - }); - }); -} - -function quickHidFlashAsync(resp: pxtc.CompileResult, wrap: DAPWrapper): Promise { - let logV = (msg: string) => { } - //let logV = log - let aborted = false; - - const runFlash = (b: ts.pxtc.UF2.Block, dataAddr: number) => { - const cmd = wrap.cortexM.prepareCommand(); - - cmd.halt(); - - cmd.writeCoreRegister(DapJS.CortexReg.PC, loadAddr + 4 + 1); - cmd.writeCoreRegister(DapJS.CortexReg.LR, loadAddr + 1); - cmd.writeCoreRegister(DapJS.CortexReg.SP, stackAddr); - - cmd.writeCoreRegister(0, b.targetAddr); - cmd.writeCoreRegister(1, dataAddr); - - return Promise.resolve() - .then(() => { - logV("setregs") - return cmd.go() - }) - .then(() => { - logV("dbg en") - // starts the program - return wrap.cortexM.debug.enable() - }) - } - - let checksums: Uint8Array - return getFlashChecksumsAsync(wrap) - .then(buf => { - checksums = buf; - log("write code"); - return wrap.cortexM.memory.writeBlock(loadAddr, flashPageBIN); - }) - .then(() => { - log("convert"); - // TODO this is seriously inefficient (130ms on a fast machine) - let uf2 = ts.pxtc.UF2.newBlockFile(); - ts.pxtc.UF2.writeHex(uf2, resp.outfiles[pxtc.BINARY_HEX].split(/\r?\n/)); - let bytes = pxt.U.stringToUint8Array(ts.pxtc.UF2.serializeFile(uf2)); - let parsed = ts.pxtc.UF2.parseFile(bytes); - - let aligned = pageAlignBlocks(parsed, pageSize); - log(`initial: ${aligned.length} pages`); - aligned = onlyChanged(aligned, checksums); - log(`incremental: ${aligned.length} pages`); - - return Promise.mapSeries(pxt.U.range(aligned.length), - i => { - if (aborted) return Promise.resolve(); - let b = aligned[i]; - if (b.targetAddr >= 0x10000000) - return Promise.resolve(); - - logV("about to write at 0x" + b.targetAddr.toString(16)); - - let writeBl = Promise.resolve(); - - let thisAddr = (i & 1) ? dataAddr : dataAddr + pageSize; - let nextAddr = (i & 1) ? dataAddr + pageSize : dataAddr; - - if (i == 0) { - let u32data = new Uint32Array(b.data.length / 4); - for (let i = 0; i < b.data.length; i += 4) - u32data[i >> 2] = pxt.HF2.read32(b.data, i); - writeBl = wrap.cortexM.memory.writeBlock(thisAddr, u32data); - } - - return writeBl - .then(() => runFlash(b, thisAddr)) - .then(() => { - let next = aligned[i + 1]; - if (!next) - return Promise.resolve(); - logV("write next"); - let buf = new Uint32Array(next.data.buffer); - return wrap.cortexM.memory.writeBlock(nextAddr, buf); - }) - .then(() => { - logV("wait"); - return wrap.cortexM.waitForHalt(500); - }) - .then(() => { - logV("done block"); - }); - }) - .then(() => { - log("flash done"); - pxt.tickEvent("hid.flash.done"); - return wrap.cortexM.reset(false); - }) - .then(() => { - wrap.flashing = false; - }); - }) - .timeout(25000, timeoutMessage) - .catch((e) => { - aborted = true; - return Promise.reject(e); - }); -} - -function flashAsync(resp: pxtc.CompileResult, d: pxt.commands.DeployOptions = {}): Promise { - startTime = 0 - let wrap: DAPWrapper - log("init") - - d.showNotification(pxt.U.lf("Downloading...")); - pxt.tickEvent("hid.flash.start"); - return Promise.resolve() - .then(() => { - if (previousDapWrapper) { - previousDapWrapper.flashing = true; - return Promise.delay(100); - } - return Promise.resolve(); - }) - .then(initAsync) - .then(w => { - wrap = w - log("reset"); - return wrap.cortexM.init() - .then(() => wrap.cortexM.reset(true)) - .catch(e => { - log("trying re-connect"); - return wrap.reconnectAsync(false) - .then(() => wrap.cortexM.reset(true)); - }); - }) - .then(() => wrap.cortexM.memory.readBlock(0x10001014, 1, pageSize)) - .then(v => { - if (pxt.HF2.read32(v, 0) != 0x3C000) { - pxt.tickEvent("hid.flash.uicrfail"); - return fullVendorCommandFlashAsync(resp, wrap); - } - return quickHidFlashAsync(resp, wrap); - }) - .catch(e => { - pxt.log(`flash error: ${e.type}`); - if (e.type === "devicenotfound" && d.reportDeviceNotFoundAsync) { - pxt.tickEvent("hid.flash.devicenotfound"); - return d.reportDeviceNotFoundAsync("/device/windows-app/troubleshoot", resp); - } else if (e.message === timeoutMessage) { - pxt.tickEvent("hid.flash.timeout"); - return previousDapWrapper.reconnectAsync(true) - .catch((e) => { }) - .then(() => { - // Best effort disconnect; at this point we don't even know the state of the device - pxt.reportException(e); - return resp.confirmAsync({ - header: lf("Something went wrong..."), - body: lf("One-click download took too long. Please disconnect your {0} from your computer and reconnect it, then manually download your program using drag and drop.", pxt.appTarget.appTheme.boardName || lf("device")), - agreeLbl: lf("Ok"), - hideCancel: true - }); - }) - .then(() => { - return pxt.commands.saveOnlyAsync(resp); - }); - } else if (e.isUserError) { - d.reportError(e.message); - return Promise.resolve(); - } else { - pxt.tickEvent("hid.flash.unknownerror"); - pxt.reportException(e); - return resp.confirmAsync({ - header: pxt.U.lf("Something went wrong..."), - body: pxt.U.lf("Please manually download your program to your device using drag and drop. One-click download might work afterwards."), - agreeLbl: lf("Ok"), - hideCancel: true - }) - .then(() => { - return pxt.commands.saveOnlyAsync(resp); - }); - } - }); -} - -function getFlashChecksumsAsync(wrap: DAPWrapper) { - log("getting existing flash checksums") - let pages = numPages - return wrap.cortexM.runCode(computeChecksums2, loadAddr, loadAddr + 1, 0xffffffff, stackAddr, true, - dataAddr, 0, pageSize, pages) - .then(() => wrap.cortexM.memory.readBlock(dataAddr, pages * 2, pageSize)) -} - -function onlyChanged(blocks: ts.pxtc.UF2.Block[], checksums: Uint8Array) { - return blocks.filter(b => { - let idx = b.targetAddr / pageSize - pxt.U.assert((idx | 0) == idx) - pxt.U.assert(b.data.length == pageSize) - if (idx * 8 + 8 > checksums.length) - return true // out of range? - let c0 = pxt.HF2.read32(checksums, idx * 8) - let c1 = pxt.HF2.read32(checksums, idx * 8 + 4) - let ch = murmur3_core(b.data) - if (c0 == ch[0] && c1 == ch[1]) - return false - return true - }) -} - -function uwpDeployCoreAsync(resp: pxtc.CompileResult, d: pxt.commands.DeployOptions = {}): Promise { - // Go straight to flashing - return flashAsync(resp, d); -} - -function deployCoreAsync(resp: pxtc.CompileResult, d: pxt.commands.DeployOptions = {}): Promise { - return pxt.usb.isPairedAsync() - .then(isPaired => { - if (isPaired) { - // Already paired from earlier in the session or from previous session - return flashAsync(resp, d); - } - - // try bluetooth if device is paired - if (pxt.webBluetooth.isPaired()) - return pxt.webBluetooth.flashAsync(resp, d) - .catch(e => pxt.commands.saveOnlyAsync(resp)); - - // No device paired, prompt user - return pxt.commands.saveOnlyAsync(resp); - }); -} - -/** - * - FALSE - FALSE - FALSE - FALSE - FALSE - FALSE - FALSE - FALSE - TRUE - FALSE - FALSE - FALSE - FALSE - FALSE - FALSE - FALSE - TRUE - FALSE - FALSE - FALSE - FALSE - FALSE - FALSE - FALSE - FALSE - - - to - - ` - # # # # # - . . . . # - . . . . . - . . . . # - . . . . # - ` - - - */ - -function patchBlocks(pkgTargetVersion: string, dom: Element) { - // is this a old script? - if (pxt.semver.majorCmp(pkgTargetVersion || "0.0.0", "1.0.0") >= 0) return; - - // showleds - const nodes = pxt.U.toArray(dom.querySelectorAll("block[type=device_show_leds]")) - .concat(pxt.U.toArray(dom.querySelectorAll("block[type=device_build_image]"))) - .concat(pxt.U.toArray(dom.querySelectorAll("shadow[type=device_build_image]"))) - .concat(pxt.U.toArray(dom.querySelectorAll("block[type=device_build_big_image]"))) - .concat(pxt.U.toArray(dom.querySelectorAll("shadow[type=device_build_big_image]"))); - nodes.forEach(node => { - // don't rewrite if already upgraded, eg. field LEDS already present - if (pxt.U.toArray(node.children).filter(child => child.tagName == "field" && "LEDS" == child.getAttribute("name"))[0]) - return; - // read LEDxx value and assmebly into a new field - const leds: string[][] = [[], [], [], [], []]; - pxt.U.toArray(node.children) - .filter(child => child.tagName == "field" && /^LED\d+$/.test(child.getAttribute("name"))) - .forEach(lednode => { - let n = lednode.getAttribute("name"); - let col = parseInt(n[3]); - let row = parseInt(n[4]); - leds[row][col] = lednode.innerHTML == "TRUE" ? "#" : "."; - // remove node - node.removeChild(lednode); - }); - // add new field - const f = node.ownerDocument.createElement("field"); - f.setAttribute("name", "LEDS"); - const s = '`\n' + leds.map(row => row.join('')).join('\n') + '\n`'; - f.appendChild(node.ownerDocument.createTextNode(s)); - node.insertBefore(f, null); - }); - - // radio - /* - - -receivedNumber - - - -name -value - - - -receivedString - - -converts to - - -receivedNumber - - -name -value - - -receivedString - -*/ - const varids: pxt.Map = {}; - - function addField(node: Element, renameMap: pxt.Map, name: string) { - const f = node.ownerDocument.createElement("field"); - f.setAttribute("name", "HANDLER_" + name) - f.setAttribute("id", varids[renameMap[name] || name]); - f.appendChild(node.ownerDocument.createTextNode(name)); - node.appendChild(f); - } - - pxt.U.toArray(dom.querySelectorAll("variable")).forEach(node => varids[node.innerHTML] = node.getAttribute("id")); - pxt.U.toArray(dom.querySelectorAll("block[type=radio_on_packet]")) - .forEach(node => { - const mutation = node.querySelector("mutation"); - if (!mutation) return; - const renameMap = JSON.parse(node.getAttribute("renamemap") || "{}"); - const props = mutation.getAttribute("callbackproperties"); - - if (props) { - const parts = props.split(","); - - // It's tempting to generate radio_on_number if parts.length === 0 but - // that would create a variable named "receivedNumber" and possibly shadow - // an existing variable in the user's program. It's safer to stick to the - // old block. - if (parts.length === 1) { - if (parts[0] === "receivedNumber") { - node.setAttribute("type", "radio_on_number"); - node.removeChild(node.querySelector("field[name=receivedNumber]")); - addField(node, renameMap, "receivedNumber"); - } - else if (parts[0] === "receivedString") { - node.setAttribute("type", "radio_on_string"); - node.removeChild(node.querySelector("field[name=receivedString]")); - addField(node, renameMap, "receivedString"); - } - else { - return; - } - node.removeChild(mutation); - } - else if (parts.length === 2 && parts.indexOf("receivedNumber") !== -1 && parts.indexOf("receivedString") !== -1) { - node.setAttribute("type", "radio_on_value"); - node.removeChild(node.querySelector("field[name=receivedNumber]")); - node.removeChild(node.querySelector("field[name=receivedString]")); - addField(node, renameMap, "name"); - addField(node, renameMap, "value"); - node.removeChild(mutation); - } - } - }) - - - // device_random now refers to randomRange() so we need to add the missing lower bound argument - pxt.U.toArray(dom.querySelectorAll("block[type=device_random]")) - .concat(pxt.U.toArray(dom.querySelectorAll("shadow[type=device_random]"))) - .forEach(node => { - if (getValue(node, "min")) return; - const v = node.ownerDocument.createElement("value"); - v.setAttribute("name", "min"); - addNumberShadow(v); - node.appendChild(v); - }); - - /* - - DIVIDE - - 0 - 2 - - - 1 - 3 - - - */ - pxt.U.toArray(dom.querySelectorAll("block[type=math_arithmetic]")) - .concat(pxt.U.toArray(dom.querySelectorAll("shadow[type=math_arithmetic]"))) - .forEach(node => { - const op = getField(node, "OP"); - if (!op || op.textContent.trim() !== "DIVIDE") return; - - // Convert to integer division - /* - - - idiv - - 0 - - - 0 - - - */ - - node.setAttribute("type", "math_js_op"); - op.textContent = "idiv"; - - const mutation = node.ownerDocument.createElement("mutation"); - mutation.setAttribute("op-type", "infix"); - // mutation has to be first or Blockly will drop the second argument - node.insertBefore(mutation, node.firstChild); - - const a = getValue(node, "A"); - if (a) a.setAttribute("name", "ARG0"); - - const b = getValue(node, "B"); - if (b) b.setAttribute("name", "ARG1"); - }); - - renameField(dom, "math_number_minmax", "NUM", "SLIDER"); - renameField(dom, "device_note", "note", "name"); -} - -function renameField(dom: Element, blockType: string, oldName: string, newName: string) { - pxt.U.toArray(dom.querySelectorAll(`block[type=${blockType}]`)) - .concat(pxt.U.toArray(dom.querySelectorAll(`shadow[type=${blockType}]`))) - .forEach(node => { - const thefield = getField(node, oldName); - if (thefield) { - thefield.setAttribute("name", newName); - } - }); -} +import * as dialogs from "./dialogs"; +import * as flash from "./flash"; +import * as patch from "./patch"; pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise { pxt.debug('loading microbit target extensions...') - function cantImportAsync(project: pxt.editor.IProjectView) { - // this feature is support in v0 only - return project.showModalDialogAsync({ - header: lf("Can't import microbit.co.uk scripts..."), - body: lf("Importing microbit.co.uk programs is not supported in this editor anymore. Please open this script in the https://makecode.microbit.org/v0 editor."), - buttons: [ - { - label: lf("Go to the old editor"), - url: `https://makecode.microbit.org/v0` - } - ] - }).then(() => project.openHome()) - } - const manyAny = Math as any; if (!manyAny.imul) manyAny.imul = function (a: number, b: number): number { @@ -826,234 +29,30 @@ pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): P canImport: data => data.meta.cloudId == "microbit.co.uk" && data.meta.editor == "blockly", importAsync: (project, data) => { pxt.tickEvent('import.legacyblocks.redirect'); - return cantImportAsync(project); + return dialogs.cantImportAsync(project); } }, { id: "td", canImport: data => data.meta.cloudId == "microbit.co.uk" && data.meta.editor == "touchdevelop", importAsync: (project, data) => { pxt.tickEvent('import.legacytd.redirect'); - return cantImportAsync(project); + return dialogs.cantImportAsync(project); } }] }; pxt.usb.setFilters([{ + vendorId: 0x1366, + productId: 0x1025 + }, + { vendorId: 0x0D28, - productId: 0x0204, - classCode: 0xff, - subclassCode: 0x03 + productId: 0x0204 }]) - const isUwp = !!(window as any).Windows; - if (isUwp) - pxt.commands.deployCoreAsync = uwpDeployCoreAsync; - else if ((canHID() || pxt.webBluetooth.hasPartialFlash()) && !pxt.BrowserUtils.isPxtElectron()) - pxt.commands.deployCoreAsync = deployCoreAsync; - - res.blocklyPatch = patchBlocks; - res.showUploadInstructionsAsync = showUploadInstructionsAsync; - res.webUsbPairDialogAsync = webUsbPairDialogAsync; + res.mkPacketIOWrapper = flash.mkDAPLinkPacketIOWrapper; + res.blocklyPatch = patch.patchBlocks; + res.renderBrowserDownloadInstructions = dialogs.renderBrowserDownloadInstructions; + res.renderUsbPairDialog = dialogs.renderUsbPairDialog; return Promise.resolve(res); } - -function getField(parent: Element, name: string) { - return getFieldOrValue(parent, name, true); -} - -function getValue(parent: Element, name: string) { - return getFieldOrValue(parent, name, false); -} - -function getFieldOrValue(parent: Element, name: string, isField: boolean) { - const nodeType = isField ? "field" : "value"; - for (let i = 0; i < parent.children.length; i++) { - const child = parent.children.item(i); - if (child.tagName === nodeType && child.getAttribute("name") === name) { - return child; - } - } - return undefined; -} - -function addNumberShadow(valueNode: Element) { - const s = valueNode.ownerDocument.createElement("shadow"); - s.setAttribute("type", "math_number"); - - const f = valueNode.ownerDocument.createElement("field"); - f.setAttribute("name", "NUM"); - f.textContent = "0"; - - s.appendChild(f); - valueNode.appendChild(s); -} - -function webUsbPairDialogAsync(confirmAsync: (options: any) => Promise): Promise { - const boardName = pxt.appTarget.appTheme.boardName || "???"; - const docUrl = pxt.appTarget.appTheme.usbDocs; - const jsx = -
-
-
{lf("First time here?")}
- {lf("You must have version 0249 or above of the firmware")} -
- -
- {lf("Check your firmware version here and update if needed")} -
-
-
-
-
-
-
-
-
- -
-
-
- 1 - {lf("Connect the {0} to your computer with a USB cable", boardName)} -
- {lf("Use the microUSB port on the top of the {0}", boardName)} -
-
-
-
-
-
-
- -
-
-
- 2 - {lf("Pair your {0}", boardName)} -
- {lf("Click 'Pair device' below and select Calliope Mini CMSIS-DAP or DAPLink CMSIS-DAP from the list")} -
-
-
-
-
-
-
-
-
-
; - - const buttons: any[] = []; - if (docUrl) { - buttons.push({ - label: lf("Help"), - icon: "help", - className: "lightgrey", - url: `${docUrl}/webusb` - }); - } - - return confirmAsync({ - header: lf("Pair device for one-click downloads"), - jsx, - hasCloseIcon: true, - agreeLbl: lf("Pair device"), - agreeIcon: "usb", - hideCancel: true, - className: 'downloaddialog', - buttons - }); -} - -function showUploadInstructionsAsync(fn: string, url: string, confirmAsync: (options: any) => Promise) { - const boardName = pxt.appTarget.appTheme.boardName || "???"; - const boardDriveName = pxt.appTarget.appTheme.driveDisplayName || pxt.appTarget.compile.driveName || "???"; - - // https://msdn.microsoft.com/en-us/library/cc848897.aspx - // "For security reasons, data URIs are restricted to downloaded resources. - // Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements" - const userDownload = pxt.BrowserUtils.isBrowserDownloadWithinUserContext(); - const downloadAgain = !pxt.BrowserUtils.isIE() && !pxt.BrowserUtils.isEdge(); - const docUrl = pxt.appTarget.appTheme.usbDocs; - - const body = - userDownload - ? lf("Click 'Download' to open the {0} app.", pxt.appTarget.appTheme.boardName || "") - : undefined; - const jsx = !userDownload ? -
-
-
-
-
-
-
-
-
- -
-
-
- 1 - {lf("Connect the {0} to your computer with a USB cable", boardName)} -
- {lf("Use the microUSB port on the top of the {0}", boardName)} -
-
-
-
-
-
-
- -
-
-
- 2 - {lf("Move the .hex file to the {0}", boardName)} -
- {lf("Locate the downloaded .hex file and drag it to the {0} drive", boardDriveName)} -
-
-
-
-
-
-
-
-
-
: undefined; - - const buttons: any[] = []; - - if (downloadAgain) { - buttons.push({ - label: userDownload ? lf("Download") : fn, - icon: "download", - class: `${userDownload ? "primary" : "lightgrey"}`, - url, - fileName: fn - }); - } - - if (docUrl) { - buttons.push({ - label: lf("Help"), - icon: "help", - className: "lightgrey", - url: docUrl - }); - } - - return confirmAsync({ - header: lf("Download to your {0}", pxt.appTarget.appTheme.boardName), - body, - jsx, - hasCloseIcon: true, - hideCancel: true, - hideAgree: true, - className: 'downloaddialog', - buttons - //timeout: 20000 - }).then(() => { }); -} \ No newline at end of file diff --git a/editor/flash.ts b/editor/flash.ts new file mode 100644 index 00000000..bc3f4f35 --- /dev/null +++ b/editor/flash.ts @@ -0,0 +1,400 @@ +const imul = (Math as any).imul; +const timeoutMessage = "timeout" +const membase = 0x20000000 +const loadAddr = membase +const dataAddr = 0x20002000 +const stackAddr = 0x20001000 + +const flashPageBIN = new Uint32Array([ + 0xbe00be00, // bkpt - LR is set to this + 0x2502b5f0, 0x4c204b1f, 0xf3bf511d, 0xf3bf8f6f, 0x25808f4f, 0x002e00ed, + 0x2f00595f, 0x25a1d0fc, 0x515800ed, 0x2d00599d, 0x2500d0fc, 0xf3bf511d, + 0xf3bf8f6f, 0x25808f4f, 0x002e00ed, 0x2f00595f, 0x2501d0fc, 0xf3bf511d, + 0xf3bf8f6f, 0x599d8f4f, 0xd0fc2d00, 0x25002680, 0x00f60092, 0xd1094295, + 0x511a2200, 0x8f6ff3bf, 0x8f4ff3bf, 0x2a00599a, 0xbdf0d0fc, 0x5147594f, + 0x2f00599f, 0x3504d0fc, 0x46c0e7ec, 0x4001e000, 0x00000504, +]) + +// void computeHashes(uint32_t *dst, uint8_t *ptr, uint32_t pageSize, uint32_t numPages) +const computeChecksums2 = new Uint32Array([ + 0x4c27b5f0, 0x44a52680, 0x22009201, 0x91004f25, 0x00769303, 0x24080013, + 0x25010019, 0x40eb4029, 0xd0002900, 0x3c01407b, 0xd1f52c00, 0x468c0091, + 0xa9044665, 0x506b3201, 0xd1eb42b2, 0x089b9b01, 0x23139302, 0x9b03469c, + 0xd104429c, 0x2000be2a, 0x449d4b15, 0x9f00bdf0, 0x4d149e02, 0x49154a14, + 0x3e01cf08, 0x2111434b, 0x491341cb, 0x405a434b, 0x4663405d, 0x230541da, + 0x4b10435a, 0x466318d2, 0x230541dd, 0x4b0d435d, 0x2e0018ed, 0x6002d1e7, + 0x9a009b01, 0x18d36045, 0x93003008, 0xe7d23401, 0xfffffbec, 0xedb88320, + 0x00000414, 0x1ec3a6c8, 0x2f9be6cc, 0xcc9e2d51, 0x1b873593, 0xe6546b64, +]) + +let startTime = 0 +function log(msg: string) { + let now = Date.now() + if (!startTime) startTime = now + now -= startTime + let ts = ("00000" + now).slice(-5) + pxt.debug(`dap ${ts}: ${msg}`) +} + + +function murmur3_core(data: Uint8Array) { + let h0 = 0x2F9BE6CC; + let h1 = 0x1EC3A6C8; + + for (let i = 0; i < data.length; i += 4) { + let k = pxt.HF2.read32(data, i) >>> 0 + k = imul(k, 0xcc9e2d51); + k = (k << 15) | (k >>> 17); + k = imul(k, 0x1b873593); + + h0 ^= k; + h1 ^= k; + h0 = (h0 << 13) | (h0 >>> 19); + h1 = (h1 << 13) | (h1 >>> 19); + h0 = (imul(h0, 5) + 0xe6546b64) >>> 0; + h1 = (imul(h1, 5) + 0xe6546b64) >>> 0; + } + return [h0, h1] +} + +class DAPWrapper implements pxt.packetio.PacketIOWrapper { + familyID: number; + private dap: DapJS.DAP; + private cortexM: DapJS.CortexM + private cmsisdap: any; + private flashing = false; + private readSerialId = 0; + private pbuf = new pxt.U.PromiseBuffer(); + private pageSize = 1024; + private numPages = 256; + private binName = pxtc.BINARY_HEX; + + constructor(public readonly io: pxt.packetio.PacketIO) { + this.familyID = 0x1366; // this is the microbit vendor id, not quite UF2 family id + this.io.onDeviceConnectionChanged = (connect) => + this.disconnectAsync() + .then(() => connect && this.reconnectAsync()); + this.io.onData = buf => { + // console.log("RD: " + pxt.Util.toHex(buf)) + this.pbuf.push(buf); + } + + this.allocDAP(); + } + + icon = "usb"; + + private startReadSerial() { + log(`start read serial`) + const rid = this.readSerialId; + const readSerial = () => { + if (rid != this.readSerialId) { + log(`stopped read serial ${rid}`) + return; + } + if (this.flashing) { + setTimeout(readSerial, 500); + return; + } + // done + this.cmsisdap.cmdNums(0x83, []) + .then((r: number[]) => { + const len = r[1] + let str = "" + for (let i = 2; i < len + 2; ++i) { + str += String.fromCharCode(r[i]) + } + if (str.length > 0) { + pxt.U.nextTick(readSerial) + if (this.onSerial) { + const utf8Str = pxt.U.toUTF8(str); + this.onSerial(pxt.U.stringToUint8Array(utf8Str), false) + } + } else + setTimeout(readSerial, 50) + }, (err: any) => { + log(`read error: ` + err.message); + this.disconnectAsync(); // force disconnect + }); + } + readSerial(); + } + + private stopSerialAsync() { + log(`stopping serial reader`) + this.readSerialId++; + return Promise.delay(200); + } + + onSerial: (buf: Uint8Array, isStderr: boolean) => void; + + private allocDAP() { + log(`alloc dap`); + this.dap = new DapJS.DAP({ + write: writeAsync, + close: this.disconnectAsync, + read: readAsync, + //sendMany: sendMany + }); + this.cmsisdap = (this.dap as any).dap; + this.cortexM = new DapJS.CortexM(this.dap); + + const h = this.io; + const pbuf = this.pbuf; + function writeAsync(data: ArrayBuffer) { + //console.log("WR: " + pxt.Util.toHex(new Uint8Array(data))); + return h.sendPacketAsync(new Uint8Array(data)); + } + + function readAsync() { + return pbuf.shiftAsync(); + } + } + + reconnectAsync(): Promise { + log(`reconnect`) + // configure serial at 115200 + return this.stopSerialAsync() + .then(() => this.io.reconnectAsync()) + .then(() => this.cortexM.init()) + .then(() => this.cmsisdap.cmdNums(0x80, [])) + .then(r => { + this.binName = (r[2] == 57 && r[3] == 57 && r[5] >= 51 ? "mbcodal-" : "") + pxtc.BINARY_HEX + }) + .then(() => this.cortexM.memory.readBlock(0x10000010, 2, this.pageSize)) + .then(res => { + this.pageSize = pxt.HF2.read32(res, 0) + this.numPages = pxt.HF2.read32(res, 4) + }) + .then(() => this.cmsisdap.cmdNums(0x82, [0x00, 0xC2, 0x01, 0x00])) + .then(() => this.startReadSerial()); + } + + disconnectAsync() { + log(`disconnect`) + return this.stopSerialAsync() + .then(() => this.io.disconnectAsync()); + } + + reflashAsync(resp: pxtc.CompileResult): Promise { + log("reflash") + startTime = 0 + pxt.tickEvent("hid.flash.start"); + this.flashing = true; + return (this.io.isConnected() ? Promise.resolve() : this.io.reconnectAsync()) + .then(() => this.cortexM.init()) + .then(() => this.cortexM.reset(true)) + .then(() => this.cortexM.memory.readBlock(0x10001014, 1, this.pageSize)) + .then(v => { + if ((pxt.HF2.read32(v, 0) & 0xff) != 0) { + pxt.tickEvent("hid.flash.uicrfail"); + return this.fullVendorCommandFlashAsync(resp); + } + return this.quickHidFlashAsync(resp); + }) + .finally(() => { this.flashing = false }) + .then(() => Promise.delay(100)) + .then(() => this.disconnectAsync()) + } + + private fullVendorCommandFlashAsync(resp: pxtc.CompileResult): Promise { + log("full flash") + + const chunkSize = 62; + let aborted = false; + return Promise.resolve() + .then(() => { + return this.cmsisdap.cmdNums(0x8A /* DAPLinkFlash.OPEN */, [1]); + }) + .then((res) => { + const hexUint8 = pxt.U.stringToUint8Array(resp.outfiles[this.binName]); + const hexArray: number[] = Array.prototype.slice.call(hexUint8); + + const sendPages = (offset: number = 0): Promise => { + const end = Math.min(hexArray.length, offset + chunkSize); + const nextPage = hexArray.slice(offset, end); + nextPage.unshift(nextPage.length); + return this.cmsisdap.cmdNums(0x8C /* DAPLinkFlash.WRITE */, nextPage) + .then(() => { + if (!aborted && end < hexArray.length) { + return sendPages(end); + } + return Promise.resolve(); + }); + } + + return sendPages(); + }) + .then((res) => { + return this.cmsisdap.cmdNums(0x8B /* DAPLinkFlash.CLOSE */, []); + }) + .timeout(60000, timeoutMessage) + .catch((e) => { + aborted = true; + return this.cmsisdap.cmdNums(0x89 /* DAPLinkFlash.RESET */, []) + .catch((e2: any) => { + // Best effort reset, no-op if there's an error + }) + .then(() => { + return Promise.reject(e); + }); + }); + } + + private quickHidFlashAsync(resp: pxtc.CompileResult): Promise { + log("quick flash") + let logV = (msg: string) => { } + //let logV = log + let aborted = false; + + const runFlash = (b: ts.pxtc.UF2.Block, dataAddr: number) => { + const cmd = this.cortexM.prepareCommand(); + + cmd.halt(); + + cmd.writeCoreRegister(DapJS.CortexReg.PC, loadAddr + 4 + 1); + cmd.writeCoreRegister(DapJS.CortexReg.LR, loadAddr + 1); + cmd.writeCoreRegister(DapJS.CortexReg.SP, stackAddr); + + cmd.writeCoreRegister(0, b.targetAddr); + cmd.writeCoreRegister(1, dataAddr); + cmd.writeCoreRegister(2, this.pageSize >> 2); + + return Promise.resolve() + .then(() => { + logV("setregs") + return cmd.go() + }) + .then(() => { + logV("dbg en") + // starts the program + return this.cortexM.debug.enable() + }) + } + + let checksums: Uint8Array + return this.getFlashChecksumsAsync() + .then(buf => { + checksums = buf; + log("write code"); + return this.cortexM.memory.writeBlock(loadAddr, flashPageBIN); + }) + .then(() => { + log("convert"); + // TODO this is seriously inefficient (130ms on a fast machine) + let uf2 = ts.pxtc.UF2.newBlockFile(); + ts.pxtc.UF2.writeHex(uf2, resp.outfiles[this.binName].split(/\r?\n/)); + let bytes = pxt.U.stringToUint8Array(ts.pxtc.UF2.serializeFile(uf2)); + let parsed = ts.pxtc.UF2.parseFile(bytes); + + let aligned = DAPWrapper.pageAlignBlocks(parsed, this.pageSize); + log(`initial: ${aligned.length} pages`); + aligned = DAPWrapper.onlyChanged(aligned, checksums, this.pageSize); + log(`incremental: ${aligned.length} pages`); + + return Promise.mapSeries(pxt.U.range(aligned.length), + i => { + if (aborted) return Promise.resolve(); + let b = aligned[i]; + if (b.targetAddr >= 0x10000000) + return Promise.resolve(); + + logV("about to write at 0x" + b.targetAddr.toString(16)); + + let writeBl = Promise.resolve(); + + let thisAddr = (i & 1) ? dataAddr : dataAddr + this.pageSize; + let nextAddr = (i & 1) ? dataAddr + this.pageSize : dataAddr; + + if (i == 0) { + let u32data = new Uint32Array(b.data.length / 4); + for (let i = 0; i < b.data.length; i += 4) + u32data[i >> 2] = pxt.HF2.read32(b.data, i); + writeBl = this.cortexM.memory.writeBlock(thisAddr, u32data); + } + + return writeBl + .then(() => runFlash(b, thisAddr)) + .then(() => { + let next = aligned[i + 1]; + if (!next) + return Promise.resolve(); + logV("write next"); + let buf = new Uint32Array(next.data.buffer); + return this.cortexM.memory.writeBlock(nextAddr, buf); + }) + .then(() => { + logV("wait"); + return this.cortexM.waitForHalt(500); + }) + .then(() => { + logV("done block"); + }); + }) + .then(() => { + log("flash done"); + pxt.tickEvent("hid.flash.done"); + return this.cortexM.reset(false); + }); + }) + .timeout(25000, timeoutMessage) + .catch((e) => { + aborted = true; + return Promise.reject(e); + }); + } + + private getFlashChecksumsAsync() { + log("flash checksums") + let pages = this.numPages + return this.cortexM.runCode(computeChecksums2, loadAddr, loadAddr + 1, 0xffffffff, stackAddr, true, + dataAddr, 0, this.pageSize, pages) + .then(() => this.cortexM.memory.readBlock(dataAddr, pages * 2, this.pageSize)) + } + + static onlyChanged(blocks: ts.pxtc.UF2.Block[], checksums: Uint8Array, pageSize: number) { + return blocks.filter(b => { + let idx = b.targetAddr / pageSize + pxt.U.assert((idx | 0) == idx) + pxt.U.assert(b.data.length == pageSize) + if (idx * 8 + 8 > checksums.length) + return true // out of range? + let c0 = pxt.HF2.read32(checksums, idx * 8) + let c1 = pxt.HF2.read32(checksums, idx * 8 + 4) + let ch = murmur3_core(b.data) + if (c0 == ch[0] && c1 == ch[1]) + return false + return true + }) + } + + static pageAlignBlocks(blocks: ts.pxtc.UF2.Block[], pageSize: number) { + pxt.U.assert(pageSize % 256 == 0) + let res: ts.pxtc.UF2.Block[] = [] + for (let i = 0; i < blocks.length;) { + let b0 = blocks[i] + let newbuf = new Uint8Array(pageSize) + for (let i = 0; i < newbuf.length; ++i) + newbuf[i] = 0xff + let startPad = b0.targetAddr & (pageSize - 1) + let newAddr = b0.targetAddr - startPad + for (; i < blocks.length; ++i) { + let b = blocks[i] + if (b.targetAddr + b.payloadSize > newAddr + pageSize) + break + pxt.U.memcpy(newbuf, b.targetAddr - newAddr, b.data, 0, b.payloadSize) + } + let bb = pxt.U.flatClone(b0) + bb.data = newbuf + bb.targetAddr = newAddr + bb.payloadSize = pageSize + res.push(bb) + } + return res + } +} + +export function mkDAPLinkPacketIOWrapper(io: pxt.packetio.PacketIO): pxt.packetio.PacketIOWrapper { + pxt.log(`packetio: mk wrapper dap wrapper`) + return new DAPWrapper(io); +} diff --git a/editor/patch.ts b/editor/patch.ts new file mode 100644 index 00000000..f1474a11 --- /dev/null +++ b/editor/patch.ts @@ -0,0 +1,263 @@ +/** + * + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + TRUE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + TRUE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + + + to + + ` + # # # # # + . . . . # + . . . . . + . . . . # + . . . . # + ` + + + */ + +export function patchBlocks(pkgTargetVersion: string, dom: Element) { + // is this a old script? + if (pxt.semver.majorCmp(pkgTargetVersion || "0.0.0", "1.0.0") >= 0) return; + + // showleds + const nodes = pxt.U.toArray(dom.querySelectorAll("block[type=device_show_leds]")) + .concat(pxt.U.toArray(dom.querySelectorAll("block[type=device_build_image]"))) + .concat(pxt.U.toArray(dom.querySelectorAll("shadow[type=device_build_image]"))) + .concat(pxt.U.toArray(dom.querySelectorAll("block[type=device_build_big_image]"))) + .concat(pxt.U.toArray(dom.querySelectorAll("shadow[type=device_build_big_image]"))); + nodes.forEach(node => { + // don't rewrite if already upgraded, eg. field LEDS already present + if (pxt.U.toArray(node.children).filter(child => child.tagName == "field" && "LEDS" == child.getAttribute("name"))[0]) + return; + // read LEDxx value and assmebly into a new field + const leds: string[][] = [[], [], [], [], []]; + pxt.U.toArray(node.children) + .filter(child => child.tagName == "field" && /^LED\d+$/.test(child.getAttribute("name"))) + .forEach(lednode => { + let n = lednode.getAttribute("name"); + let col = parseInt(n[3]); + let row = parseInt(n[4]); + leds[row][col] = lednode.innerHTML == "TRUE" ? "#" : "."; + // remove node + node.removeChild(lednode); + }); + // add new field + const f = node.ownerDocument.createElement("field"); + f.setAttribute("name", "LEDS"); + const s = '`\n' + leds.map(row => row.join('')).join('\n') + '\n`'; + f.appendChild(node.ownerDocument.createTextNode(s)); + node.insertBefore(f, null); + }); + + // radio + /* + + +receivedNumber + + + +name +value + + + +receivedString + + +converts to + + +receivedNumber + + +name +value + + +receivedString + +*/ + const varids: pxt.Map = {}; + + function addField(node: Element, renameMap: pxt.Map, name: string) { + const f = node.ownerDocument.createElement("field"); + f.setAttribute("name", "HANDLER_" + name) + f.setAttribute("id", varids[renameMap[name] || name]); + f.appendChild(node.ownerDocument.createTextNode(name)); + node.appendChild(f); + } + + pxt.U.toArray(dom.querySelectorAll("variable")).forEach(node => varids[node.innerHTML] = node.getAttribute("id")); + pxt.U.toArray(dom.querySelectorAll("block[type=radio_on_packet]")) + .forEach(node => { + const mutation = node.querySelector("mutation"); + if (!mutation) return; + const renameMap = JSON.parse(node.getAttribute("renamemap") || "{}"); + const props = mutation.getAttribute("callbackproperties"); + + if (props) { + const parts = props.split(","); + + // It's tempting to generate radio_on_number if parts.length === 0 but + // that would create a variable named "receivedNumber" and possibly shadow + // an existing variable in the user's program. It's safer to stick to the + // old block. + if (parts.length === 1) { + if (parts[0] === "receivedNumber") { + node.setAttribute("type", "radio_on_number"); + node.removeChild(node.querySelector("field[name=receivedNumber]")); + addField(node, renameMap, "receivedNumber"); + } + else if (parts[0] === "receivedString") { + node.setAttribute("type", "radio_on_string"); + node.removeChild(node.querySelector("field[name=receivedString]")); + addField(node, renameMap, "receivedString"); + } + else { + return; + } + node.removeChild(mutation); + } + else if (parts.length === 2 && parts.indexOf("receivedNumber") !== -1 && parts.indexOf("receivedString") !== -1) { + node.setAttribute("type", "radio_on_value"); + node.removeChild(node.querySelector("field[name=receivedNumber]")); + node.removeChild(node.querySelector("field[name=receivedString]")); + addField(node, renameMap, "name"); + addField(node, renameMap, "value"); + node.removeChild(mutation); + } + } + }) + + + // device_random now refers to randomRange() so we need to add the missing lower bound argument + pxt.U.toArray(dom.querySelectorAll("block[type=device_random]")) + .concat(pxt.U.toArray(dom.querySelectorAll("shadow[type=device_random]"))) + .forEach(node => { + if (getValue(node, "min")) return; + const v = node.ownerDocument.createElement("value"); + v.setAttribute("name", "min"); + addNumberShadow(v); + node.appendChild(v); + }); + + /* + + DIVIDE + + 0 + 2 + + + 1 + 3 + + + */ + pxt.U.toArray(dom.querySelectorAll("block[type=math_arithmetic]")) + .concat(pxt.U.toArray(dom.querySelectorAll("shadow[type=math_arithmetic]"))) + .forEach(node => { + const op = getField(node, "OP"); + if (!op || op.textContent.trim() !== "DIVIDE") return; + + // Convert to integer division + /* + + + idiv + + 0 + + + 0 + + + */ + + node.setAttribute("type", "math_js_op"); + op.textContent = "idiv"; + + const mutation = node.ownerDocument.createElement("mutation"); + mutation.setAttribute("op-type", "infix"); + // mutation has to be first or Blockly will drop the second argument + node.insertBefore(mutation, node.firstChild); + + const a = getValue(node, "A"); + if (a) a.setAttribute("name", "ARG0"); + + const b = getValue(node, "B"); + if (b) b.setAttribute("name", "ARG1"); + }); + + renameField(dom, "math_number_minmax", "NUM", "SLIDER"); + renameField(dom, "device_note", "note", "name"); +} + +function renameField(dom: Element, blockType: string, oldName: string, newName: string) { + pxt.U.toArray(dom.querySelectorAll(`block[type=${blockType}]`)) + .concat(pxt.U.toArray(dom.querySelectorAll(`shadow[type=${blockType}]`))) + .forEach(node => { + const thefield = getField(node, oldName); + if (thefield) { + thefield.setAttribute("name", newName); + } + }); +} + + +function getField(parent: Element, name: string) { + return getFieldOrValue(parent, name, true); +} + +function getValue(parent: Element, name: string) { + return getFieldOrValue(parent, name, false); +} + +function getFieldOrValue(parent: Element, name: string, isField: boolean) { + const nodeType = isField ? "field" : "value"; + for (let i = 0; i < parent.children.length; i++) { + const child = parent.children.item(i); + if (child.tagName === nodeType && child.getAttribute("name") === name) { + return child; + } + } + return undefined; +} + +function addNumberShadow(valueNode: Element) { + const s = valueNode.ownerDocument.createElement("shadow"); + s.setAttribute("type", "math_number"); + + const f = valueNode.ownerDocument.createElement("field"); + f.setAttribute("name", "NUM"); + f.textContent = "0"; + + s.appendChild(f); + valueNode.appendChild(s); +} diff --git a/external/sha/buildflash.sh b/external/sha/buildflash.sh index ff40de0e..d3be484a 100755 --- a/external/sha/buildflash.sh +++ b/external/sha/buildflash.sh @@ -1,4 +1,5 @@ #!/bin/sh +set -e yotta build arm-none-eabi-objdump -d `find -name main.c.o` > disasm node genapplet.js disasm Reset_Handler diff --git a/external/sha/module.json b/external/sha/module.json index 54dc0216..b28408f6 100644 --- a/external/sha/module.json +++ b/external/sha/module.json @@ -4,6 +4,8 @@ "keywords": [], "author": "", "license": "MIT", - "dependencies": {}, + "dependencies": { + "microbit-dal": "Amerlander/microbit-dal#v2.1.1" + }, "bin": "./source" } diff --git a/external/sha/source/main.c b/external/sha/source/main.c index af00cfa9..81bcfe27 100644 --- a/external/sha/source/main.c +++ b/external/sha/source/main.c @@ -143,6 +143,7 @@ INLINE void murmur3_core_2(const uint8_t *data, uint32_t len, uint32_t *dst) { dst[1] = h1; } +#if 0 int Reset_Handler(uint32_t *dst, uint8_t *ptr, uint32_t pageSize, uint32_t numPages) { uint32_t crcTable[256]; @@ -165,19 +166,23 @@ int Reset_Handler(uint32_t *dst, uint8_t *ptr, uint32_t pageSize, #endif return 0; } +#endif + +#if 1 +#include "nrf.h" -#if 0 -#define PAGE_SIZE 0x400 #define SIZE_IN_WORDS (PAGE_SIZE / 4) #define setConfig(v) \ do { \ NRF_NVMC->CONFIG = v; \ + __ISB(); __DSB(); \ while (NRF_NVMC->READY == NVMC_READY_READY_Busy) \ ; \ } while (0) -void overwriteFlashPage(uint32_t *to, uint32_t *from) { +void Reset_Handler(uint32_t *to, uint32_t *from, uint32_t numWords) { +#if 0 int same = 1; for (int i = 0; i <= (SIZE_IN_WORDS - 1); i++) { if (to[i] != from[i]) { @@ -187,6 +192,7 @@ void overwriteFlashPage(uint32_t *to, uint32_t *from) { } if (same) return; +#endif // Turn on flash erase enable and wait until the NVMC is ready: setConfig(NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos); @@ -202,7 +208,7 @@ void overwriteFlashPage(uint32_t *to, uint32_t *from) { // Turn on flash write enable and wait until the NVMC is ready: setConfig(NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos); - for (int i = 0; i <= (SIZE_IN_WORDS - 1); i++) { + for (uint32_t i = 0; i < numWords; i++) { *(to + i) = *(from + i); while (NRF_NVMC->READY == NVMC_READY_READY_Busy) ; diff --git a/fieldeditors/field_gestures.ts b/fieldeditors/field_gestures.ts index 266fbd53..0a4dbf12 100644 --- a/fieldeditors/field_gestures.ts +++ b/fieldeditors/field_gestures.ts @@ -17,7 +17,7 @@ export class FieldGestures extends pxtblockly.FieldImages implements Blockly.Fie this.width_ = parseInt(options.width) || 350; this.addLabel_ = true; - this.setText = Blockly.FieldDropdown.prototype.setText; + this.renderSelectedImage_ = Blockly.FieldDropdown.prototype.renderSelectedText_; this.updateSize_ = (Blockly.Field as any).prototype.updateSize_; } diff --git a/libs/bluetooth/pxt.json b/libs/bluetooth/pxt.json index f5818816..8c4a4bc2 100644 --- a/libs/bluetooth/pxt.json +++ b/libs/bluetooth/pxt.json @@ -15,6 +15,7 @@ "dependencies": { "core": "file:../core" }, + "disablesVariants": ["mbcodal"], "yotta": { "config": { "microbit-dal": { diff --git a/libs/core/_locales/core-jsdoc-strings.json b/libs/core/_locales/core-jsdoc-strings.json index d43084a7..860eb1e0 100644 --- a/libs/core/_locales/core-jsdoc-strings.json +++ b/libs/core/_locales/core-jsdoc-strings.json @@ -4,6 +4,10 @@ "AcceleratorRange.OneG": "The accelerator measures forces up to 1 gravity", "AcceleratorRange.TwoG": "The accelerator measures forces up to 2 gravity", "Array": "Add, remove, and replace items in lists.", + "Array._popStatement": "Remove the last element from an array and return it.", + "Array._removeAtStatement": "Remove the element at a certain index.", + "Array._shiftStatement": "Remove the first element from an array and return it. This method changes the length of the array.", + "Array._unshiftStatement": "Add one element to the beginning of an array and return the new length of the array.", "Array.concat": "Concatenates the values with another array.", "Array.concat|param|arr": "The other array that is being concatenated with", "Array.every": "Tests whether all elements in the array pass the test implemented by the provided function.", @@ -50,17 +54,20 @@ "Array.unshift": "Add one element to the beginning of an array and return the new length of the array.", "Array@type": "Add, remove, and replace items in lists.", "Boolean.toString": "Returns a string representation of an object.", + "Buffer.chunked": "Splits buffer into parts no larger than specified", "Buffer.concat": "Return concatenation of current buffer and the given buffer\n\nConcatenates all buffers in the list", "Buffer.create": "Allocate a new buffer.", "Buffer.create|param|size": "number of bytes in the buffer", + "Buffer.equals": "Returns true if this and the other buffer hold the same data", "Buffer.fill": "Fill (a fragment) of the buffer with given value.", - "Buffer.fromArray": "Create a new buffer initalized to bytes from given array.", - "Buffer.fromArray|param|bytes": "data to initalize with", + "Buffer.fromArray": "Create a new buffer initialized to bytes from given array.", + "Buffer.fromArray|param|bytes": "data to initialize with", "Buffer.fromHex": "Create a new buffer, decoding a hex string", "Buffer.fromUTF8": "Create a new buffer with UTF8-encoded string", "Buffer.fromUTF8|param|str": "the string to put in the buffer", "Buffer.getNumber": "Read a number in specified format from the buffer.", "Buffer.getUint8": "Reads an unsigned byte at a particular location", + "Buffer.hash": "Compute k-bit FNV-1 non-cryptographic hash of the buffer.", "Buffer.indexOf": "Return position of other buffer in current buffer", "Buffer.isReadOnly": "Returns false when the buffer can be written to.", "Buffer.length": "Returns the length of a Buffer object.", @@ -77,6 +84,7 @@ "Buffer.shift|param|start": "start offset in buffer. Default is 0.", "Buffer.sizeOfNumberFormat": "Get the size in bytes of specified number format.", "Buffer.slice": "Return a copy of a fragment of a buffer.", + "Buffer.toArray": "Read contents of buffer as an array in specified format", "Buffer.toHex": "Convert a buffer to its hexadecimal representation.", "Buffer.toString": "Convert a buffer to string assuming UTF8 encoding", "Buffer.unpack": "Reads numbers from the buffer according to the format", @@ -220,8 +228,15 @@ "String.substr|param|length": "number of characters to extract", "String.substr|param|start": "first character index; can be negative from counting from the end, eg:0", "String.toLowerCase": "Converts the string to lower case characters.", + "String.trim": "Return a substring of the current string with whitespace removed from both ends", "String@type": "Combine, split, and search text strings.", "StringMap": "A dictionary from string key to string values", + "_py.range": "Returns a sequence of numbers up to but not including the limit\n\nIf more than one argument is passed, this argument is instead used for the first value in the range", + "_py.range|param|first": "The value to end the sequence before. This value will not show up in the result.", + "_py.range|param|step": "The value to increase or decrease by for each step in the range. Must be a nonzero integer", + "_py.range|param|stop": "The value to end the sequence before. This value will not show up in the result", + "_py.slice": "Returns a section of an array according to python's extended slice syntax", + "_py.stringSlice": "Returns a section of a string according to python's extended slice syntax", "basic": "Provides access to basic micro:bit functionality.\n\nProvides access to basic micro:bit functionality.", "basic.clearScreen": "Turn off all LEDs", "basic.color": "Converts the color name to a number", @@ -256,6 +271,9 @@ "basic.turnRgbLedOff": "Sets the color on the build-in LED. Set to 0 to turn off.", "console": "Reading and writing data to the console output.", "console.addListener": "Adds a listener for the log messages", + "console.inspect": "Convert any object or value to a string representation", + "console.inspect|param|maxElements": "[optional] max number values in an object to include in output", + "console.inspect|param|obj": "value to be converted to a string", "console.log": "Write a line of text to the console output.", "console.logValue": "Write a name:value pair as a line of text to the console output.", "console.logValue|param|name": "name of the value stream, eg: \"x\"", @@ -272,6 +290,7 @@ "control.eventTimestamp": "Gets the timestamp of the last event executed on the bus", "control.eventValue": "Gets the value of the last event executed on the bus", "control.eventValueId": "Returns the value of a C++ runtime constant", + "control.gcStats": "Get various statistics about the garbage collector (GC)", "control.inBackground": "Schedules code that run in the background.", "control.micros": "Gets current time in microseconds. Overflows every ~18 minutes.", "control.millis": "Gets the number of milliseconds elapsed since power on.", @@ -282,12 +301,14 @@ "control.raiseEvent|param|src": "ID of the MicroBit Component that generated the event e.g. MICROBIT_ID_BUTTON_A.", "control.raiseEvent|param|value": "Component specific code indicating the cause of the event.", "control.reset": "Resets the BBC micro:bit.", + "control.runInParallel": "Run other code in the parallel.", "control.runtimeWarning": "Display warning in the simulator.", "control.waitForEvent": "Blocks the calling thread until the specified event is raised.", "control.waitMicros": "Blocks the current fiber for the given microseconds", "control.waitMicros|param|micros": "number of micro-seconds to wait. eg: 4", "convertToText": "Convert any value to text", "convertToText|param|value": "value to be converted to text", + "forever": "Repeats the code forever in the background. On each iteration, allows other codes to run.", "game": "A single-LED sprite game engine", "game.LedSprite": "A game sprite rendered as a single LED", "game.LedSprite.blink": "Reports the ``blink`` duration of a sprite", @@ -439,6 +460,9 @@ "led.plot|param|x": "the horizontal coordinate of the LED starting at 0", "led.plot|param|y": "the vertical coordinate of the LED starting at 0", "led.point": "Get the on/off state of the specified LED using x, y coordinates. (0,0) is upper left.", + "led.pointBrightness": "Get the brightness state of the specified LED using x, y coordinates. (0,0) is upper left.", + "led.pointBrightness|param|x": "the horizontal coordinate of the LED", + "led.pointBrightness|param|y": "the vertical coordinate of the LED", "led.point|param|x": "the horizontal coordinate of the LED", "led.point|param|y": "the vertical coordinate of the LED", "led.screenshot": "Takes a screenshot of the LED screen and returns an image.", @@ -454,6 +478,8 @@ "led.unplot": "Turn off the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left.", "led.unplot|param|x": "the horizontal coordinate of the LED", "led.unplot|param|y": "the vertical coordinate of the LED", + "light.sendWS2812Buffer": "Sends a color buffer to a light strip", + "light.setMode": "Sets the light mode of a pin", "motors": "Blocks to control the onboard motors", "motors.dualMotorPower": "Controls two motors attached to the board. Switches to dual-motor mode!", "motors.motorCommand": "Send break, coast or sleep commands to the motor. Has no effect in dual-motor mode.", @@ -464,15 +490,13 @@ "msgpack.unpackNumberArray": "Unpacks a buffer into a number array.", "music": "Generation of music tones.", "music.beat": "Returns the duration of a beat in milli-seconds", - "music.beginMelody": "Starts playing a melody.\nNotes are expressed as a string of characters with this format: NOTE[octave][:duration]", - "music.beginMelody|param|melodyArray": "the melody array to play", - "music.beginMelody|param|options": "melody options, once / forever, in the foreground / background", + "music.beginMelody": "Use startMelody instead", "music.builtInMelody": "Gets the melody array of a built-in melody.", "music.changeTempoBy": "Change the tempo by the specified amount", "music.changeTempoBy|param|bpm": "The change in beats per minute to the tempo, eg: 20", "music.melodyEditor": "Create a melody with the melody editor.", - "music.noteFrequency": "Get the frequency of a note.", - "music.noteFrequency|param|name": "the note name, eg: Note.C", + "music.noteFrequency": "Gets the frequency of a note.", + "music.noteFrequency|param|name": "the note name", "music.onEvent": "Registers code to run on various melody events", "music.playMelody": "Play a melody from the melody editor.", "music.playMelody|param|melody": "- string of up to eight notes [C D E F G A B C5] or rests [-] separated by spaces, which will be played one at a time, ex: \"E D G F B A C5 B \"", @@ -487,14 +511,24 @@ "music.setPlayTone": "Sets a custom playTone function for playing melodies", "music.setTempo": "Sets the tempo to the specified amount", "music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120", + "music.setVolume": "Set the default output volume of the sound synthesizer.", + "music.setVolume|param|volume": "the volume 0...255", "music.speakerPlayTone": "Plays a tone through ``speaker`` for the given duration.", "music.speakerPlayTone|param|frequency": "pitch of the tone to play in Hertz (Hz)", "music.speakerPlayTone|param|ms": "tone duration in milliseconds (ms)", + "music.startMelody": "Starts playing a melody.\nNotes are expressed as a string of characters with this format: NOTE[octave][:duration]", + "music.startMelody|param|melodyArray": "the melody array to play", + "music.startMelody|param|options": "melody options, once / forever, in the foreground / background", "music.stopMelody": "Stops the melodies", "music.stopMelody|param|options": "which melody to stop", "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.volume": "Returns the current output volume of the sound synthesizer.", "parseFloat": "Convert a string to a number.", - "parseInt": "Convert a string to an integer.", + "parseInt": "Convert a string to an integer.\n\n\nIf this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal.\nAll other strings are considered decimal.", + "parseInt|param|radix": "optional A value between 2 and 36 that specifies the base of the number in text.", + "parseInt|param|text": "A string to convert into an integral number. eg: \"123\"", + "pause": "Pause for the specified time in milliseconds", + "pause|param|ms": "how long to pause for, eg: 100, 200, 500, 1000, 2000", "pins": "Control currents in Pins for analog/digital signals, servos, i2c, ...", "pins.C10": "Pin C10", "pins.C11": "Pin C11", @@ -513,18 +547,21 @@ "pins.P1": "Pin P1", "pins.P2": "Pin P2", "pins.P3": "Pin P3", - "pins.analogPitch": "Emit a pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.", + "pins.analogPitch": "Emit a plse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.", + "pins.analogPitchVolume": "Gets the volume the pitch pin from 0..255", "pins.analogPitch|param|frequency": "frequency to modulate in Hz.", "pins.analogPitch|param|ms": "duration of the pitch in milli seconds.", "pins.analogReadPin": "Read the connector value as analog, that is, as a value comprised between 0 and 1023.", - "pins.analogReadPin|param|name": "of pin to read from, eg: AnalogPin.P1", + "pins.analogReadPin|param|name": "pin to write to, eg: AnalogPin.P0", "pins.analogSetPeriod": "Configure the pulse-width modulation (PWM) period of the analog output in microseconds.\nIf this pin is not configured as an analog output (using `analog write pin`), the operation has no effect.", "pins.analogSetPeriod|param|micros": "period in micro seconds. eg:20000", - "pins.analogSetPeriod|param|name": "analog pin to set period to, eg: AnalogPin.P1", + "pins.analogSetPeriod|param|name": "analog pin to set period to, eg: AnalogPin.P0", "pins.analogSetPitchPin": "Set the pin used when using analog pitch or music.", "pins.analogSetPitchPin|param|name": "pin to modulate pitch from", + "pins.analogSetPitchVolume": "Sets the volume on the pitch pin", + "pins.analogSetPitchVolume|param|volume": "the intensity of the sound from 0..255", "pins.analogWritePin": "Set the connector value as analog. Value must be comprised between 0 and 1023.", - "pins.analogWritePin|param|name": "of pin to write to, eg: AnalogPin.P1", + "pins.analogWritePin|param|name": "pin name to write to, eg: AnalogPin.P0", "pins.analogWritePin|param|value": "value to write to the pin between ``0`` and ``1023``. eg:1023,0", "pins.createBuffer": "Create a new zero-initialized buffer.", "pins.createBuffer|param|size": "number of bytes in the buffer", @@ -550,17 +587,18 @@ "pins.pulseIn": "Return the duration of a pulse at a pin in microseconds.", "pins.pulseIn|param|name": "the pin which measures the pulse, eg: DigitalPin.P0", "pins.pulseIn|param|value": "the value of the pulse, eg: PulseValue.High", + "pins.pushButton": "Mounts a push button on the given pin", "pins.servoSetContinuous": "Specifies that a continuous servo is connected.", "pins.servoSetPulse": "Configure the IO pin as an analog/pwm output and set a pulse width. The period is 20 ms period and the pulse width is set based on the value given in **microseconds** or `1/1000` milliseconds.", "pins.servoSetPulse|param|micros": "pulse duration in micro seconds, eg:1500", "pins.servoSetPulse|param|name": "pin name", "pins.servoWritePin": "Write 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|param|name": "pin to write to, eg: AnalogPin.P1", + "pins.servoWritePin|param|name": "pin to write to, eg: AnalogPin.P0", "pins.servoWritePin|param|value": "angle or rotation speed, eg:180,90,0", "pins.setEvents": "Configure the events emitted by this pin. Events can be subscribed to\nusing ``control.onEvent()``.", "pins.setEvents|param|name": "pin to set the event mode on, eg: DigitalPin.P0", "pins.setEvents|param|type": "the type of events for this pin to emit, eg: PinEventType.Edge", - "pins.setPull": "Configure the pull direction of of a pin.", + "pins.setPull": "Configure the pull directiion of of a pin.", "pins.setPull|param|name": "pin to set the pull mode on, eg: DigitalPin.P0", "pins.setPull|param|pull": "one of the mbed pull configurations, eg: PinPullMode.PullUp", "pins.spiFormat": "Set the SPI bits and mode", @@ -569,8 +607,14 @@ "pins.spiFrequency": "Set the SPI frequency", "pins.spiFrequency|param|frequency": "the clock frequency, eg: 1000000", "pins.spiPins": "Set the MOSI, MISO, SCK pins used by the SPI connection", + "pins.spiTransfer": "Write to and read from the SPI slave at the same time", + "pins.spiTransfer|param|command": "Data to be sent to the SPI slave (can be null)", + "pins.spiTransfer|param|response": "Data received from the SPI slave (can be null)", "pins.spiWrite": "Write to the SPI slave and return the response", "pins.spiWrite|param|value": "Data to be sent to the SPI slave", + "randint": "Returns a pseudorandom number between min and max included.\nIf both numbers are integral, the result is integral.", + "randint|param|max": "the upper inclusive bound, eg: 10", + "randint|param|min": "the lower inclusive bound, eg: 0", "serial": "Reading and writing data over a serial connection.", "serial.NEW_LINE": "The string used to mark a new line, default is \\r\\n", "serial.delimiters": "Return the corresponding delimiter string", @@ -587,6 +631,7 @@ "serial.redirect|param|rate": "the new baud rate. eg: 115200", "serial.redirect|param|rx": "the new reception pin, eg: SerialPin.P1", "serial.redirect|param|tx": "the new transmission pin, eg: SerialPin.P0", + "serial.setBaudRate": "Set the baud rate of the serial port", "serial.setRxBufferSize": "Sets the size of the RX buffer in bytes", "serial.setRxBufferSize|param|size": "length of the rx buffer in bytes, eg: 32", "serial.setTxBufferSize": "Sets the size of the TX buffer in bytes", diff --git a/libs/core/_locales/core-strings.json b/libs/core/_locales/core-strings.json index 801407b1..582d6a69 100644 --- a/libs/core/_locales/core-strings.json +++ b/libs/core/_locales/core-strings.json @@ -7,12 +7,16 @@ "AcceleratorRange.OneG|block": "1g", "AcceleratorRange.TwoG": "The accelerator measures forces up to 2 gravity", "AcceleratorRange.TwoG|block": "2g", + "Array._popStatement|block": "remove last value from %list", + "Array._removeAtStatement|block": "%list| remove value at %index", + "Array._shiftStatement|block": "remove first value from %list", + "Array._unshiftStatement|block": "%list| insert %value| at beginning", "Array.indexOf|block": "%list| find index of %value", "Array.insertAt|block": "%list| insert at %index| value %value", "Array.length|block": "length of %VALUE", "Array.pop|block": "get and remove last value from %list", "Array.push|block": "%list| add value %value| to end", - "Array.removeAt|block": "%list| remove value at %index", + "Array.removeAt|block": "%list| get and remove value at %index", "Array.reverse|block": "reverse %list", "Array.shift|block": "get and remove first value from %list", "Array.unshift|block": "%list| insert %value| at beginning", @@ -55,12 +59,17 @@ "Colors.Violet|block": "violet", "Colors.White|block": "white", "Colors.Yellow|block": "yellow", + "Delimiters.CarriageReturn|block": "carriage return (\r)", "Delimiters.Colon|block": ":", "Delimiters.Comma|block": ",", "Delimiters.Dollar|block": "$", "Delimiters.Fullstop|block": ".", "Delimiters.Hash|block": "#", - "Delimiters.NewLine|block": "new line", + "Delimiters.NewLine|block": "new line (\n)", + "Delimiters.Pipe|block": "|", + "Delimiters.SemiColon|block": ";", + "Delimiters.Space|block": "space", + "Delimiters.Tab|block": "tab (\t)", "Dimension.Strength|block": "strength", "Dimension.X|block": "x", "Dimension.Y|block": "y", @@ -152,7 +161,7 @@ "Melodies.Chase|block": "chase", "Melodies.Dadadadum|block": "dadadum", "Melodies.Entertainer|block": "entertainer", - "Melodies.Funeral|block": "funereal", + "Melodies.Funeral|block": "funeral", "Melodies.Funk|block": "funk", "Melodies.JumpDown|block": "jump down", "Melodies.JumpUp|block": "jump up", @@ -241,6 +250,7 @@ "String.split|block": "split %this=text|at %separator", "String.substr|block": "substring of %this=text|from %start|of length %length", "String|block": "String", + "_py|block": "_py", "basic.clearScreen|block": "clear screen", "basic.color|block": "%c", "basic.forever|block": "forever", @@ -295,7 +305,7 @@ "game.setScore|block": "set score %points", "game.startCountdown|block": "start countdown|(ms) %duration", "game|block": "game", - "images.arrowImage|block": "arrow image %i=device_arrow", + "images.arrowImage|block": "arrow image %i", "images.arrowNumber|block": "%arrow", "images.createBigImage|block": "create big image", "images.createImage|block": "create image", @@ -324,6 +334,7 @@ "led.plotBarGraph|block": "plot bar graph of %value up to %high", "led.plotBrightness|block": "plot|x %x|y %y|brightness %brightness", "led.plot|block": "plot|x %x|y %y", + "led.pointBrightness|block": "point|x %x|y %y brightness", "led.point|block": "point|x %x|y %y", "led.setBrightness|block": "set brightness %value", "led.setDisplayMode|block": "set display mode $mode", @@ -331,13 +342,13 @@ "led.toggle|block": "toggle|x %x|y %y", "led.unplot|block": "unplot|x %x|y %y", "led|block": "led", + "light|block": "light", "motors.dualMotorPower|block": "motor %motor|at %percent \\%", "motors.motorCommand|block": "motor %command", "motors.motorPower|block": "motor on at %percent \\%", "motors|block": "motors", "msgpack|block": "msgpack", "music.beat|block": "%fraction|beat", - "music.beginMelody|block": "start melody %melody=device_builtin_melody| repeating %options", "music.builtInMelody|block": "%melody", "music.changeTempoBy|block": "change tempo by (bpm)|%value", "music.melodyEditor|block": "$melody", @@ -348,15 +359,20 @@ "music.rest|block": "rest(ms)|%duration=device_beat", "music.ringTone|block": "ring tone (Hz)|%note=device_note", "music.setTempo|block": "set tempo to (bpm)|%value", + "music.setVolume|block": "set volume %volume", + "music.startMelody|block": "start melody %melody=device_builtin_melody| repeating %options", "music.stopMelody|block": "stop melody $options", "music.tempo|block": "tempo (bpm)", + "music.volume|block": "volume", "music|block": "music", "parseFloat|block": "parse to number %text", "parseInt|block": "parse to integer %text", + "pins.analogPitchVolume|block": "analog pitch volume", "pins.analogPitch|block": "analog pitch %frequency|for (ms) %ms", "pins.analogReadPin|block": "analog read|pin %name", "pins.analogSetPeriod|block": "analog set period|pin %pin|to (µs)%micros", "pins.analogSetPitchPin|block": "analog set pitch pin %name", + "pins.analogSetPitchVolume|block": "analog set pitch volume $volume", "pins.analogWritePin|block": "analog write|pin %name|to %value", "pins.digitalReadPin|block": "digital read|pin %name", "pins.digitalWritePin|block": "digital write|pin %name|to %value", @@ -375,6 +391,7 @@ "pins.spiPins|block": "spi set pins|MOSI %mosi|MISO %miso|SCK %sck", "pins.spiWrite|block": "spi write %value", "pins|block": "pins", + "randint|block": "pick random %min|to %limit", "serial.delimiters|block": "%del", "serial.onDataReceived|block": "serial|on data received %delimiters=serial_delimiter_conv", "serial.readBuffer|block": "serial|read buffer %length", @@ -383,6 +400,7 @@ "serial.readUntil|block": "serial|read until %delimiter=serial_delimiter_conv", "serial.redirectToUSB|block": "serial|redirect to USB", "serial.redirect|block": "serial|redirect to|TX %tx|RX %rx|at baud rate %rate", + "serial.setBaudRate|block": "serial|set baud rate %rate", "serial.setRxBufferSize|block": "serial set rx buffer size to $size", "serial.setTxBufferSize|block": "serial set tx buffer size to $size", "serial.setWriteLinePadding|block": "serial set write line padding to $length", @@ -411,6 +429,7 @@ "{id:category}Images": "Images", "{id:category}Input": "Input", "{id:category}Led": "Led", + "{id:category}Light": "Light", "{id:category}Math": "Math", "{id:category}MicrobitPin": "MicrobitPin", "{id:category}Motors": "Motors", @@ -422,5 +441,15 @@ "{id:category}PwmOnlyPin": "PwmOnlyPin", "{id:category}Serial": "Serial", "{id:category}String": "String", - "{id:category}Text": "Text" + "{id:category}Text": "Text", + "{id:category}_py": "_py", + "{id:group}Configuration": "Configuration", + "{id:group}Melody": "Melody", + "{id:group}Melody Advanced": "Melody Advanced", + "{id:group}Modify": "Modify", + "{id:group}Operations": "Operations", + "{id:group}Read": "Read", + "{id:group}Tempo": "Tempo", + "{id:group}Tone": "Tone", + "{id:group}Volume": "Volume" } \ No newline at end of file diff --git a/libs/core/basic.cpp b/libs/core/basic.cpp index 47a4341c..ea44b4c9 100644 --- a/libs/core/basic.cpp +++ b/libs/core/basic.cpp @@ -131,4 +131,4 @@ namespace basic { void pause(int ms) { fiber_sleep(ms); } -} +} \ No newline at end of file diff --git a/libs/core/basic.ts b/libs/core/basic.ts index a3d2fdb0..d832e8fd 100644 --- a/libs/core/basic.ts +++ b/libs/core/basic.ts @@ -74,3 +74,19 @@ namespace basic { showString(Math.roundWithPrecision(value, 2).toString(), interval); } } + +/** + * Pause for the specified time in milliseconds + * @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000 + */ +function pause(ms: number): void { + basic.pause(ms); +} + +/** + * Repeats the code forever in the background. On each iteration, allows other codes to run. + * @param body code to execute + */ +function forever(a: () => void): void { + basic.forever(a); +} diff --git a/libs/core/blocks-test/pins.blocks b/libs/core/blocks-test/pins.blocks index 9e01d01c..9f7dc325 100644 --- a/libs/core/blocks-test/pins.blocks +++ b/libs/core/blocks-test/pins.blocks @@ -1,10 +1,10 @@ - DigitalPin.P5 + DigitalPin.C5 PulseValue.Low - AnalogPin.P9 + AnalogPin.C6 5 @@ -12,7 +12,7 @@ - AnalogPin.P10 + AnalogPin.C6 20000 @@ -20,7 +20,7 @@ - DigitalPin.P6 + DigitalPin.C6 5 @@ -28,7 +28,7 @@ - AnalogPin.P13 + AnalogPin.C5 5 @@ -36,7 +36,7 @@ - AnalogPin.P8 + AnalogPin.C6 1500 @@ -65,7 +65,7 @@ 0 - DigitalPin.P9 + DigitalPin.C9 PulseValue.Low @@ -102,7 +102,7 @@ 0 - DigitalPin.P9 + DigitalPin.C9 @@ -110,7 +110,7 @@ 0 - AnalogPin.P9 + AnalogPin.C6 @@ -120,12 +120,12 @@ - DigitalPin.P11 - DigitalPin.P9 - DigitalPin.P10 + DigitalPin.C11 + DigitalPin.C9 + DigitalPin.C10 - DigitalPin.P9 + DigitalPin.C9 PinPullMode.PullDown @@ -141,11 +141,11 @@ - DigitalPin.P8 + DigitalPin.C8 PinEventType.Touch - AnalogPin.P9 + AnalogPin.C6 diff --git a/libs/core/blocks-test/test.blocks b/libs/core/blocks-test/test.blocks index d1e1be1e..9650c840 100644 --- a/libs/core/blocks-test/test.blocks +++ b/libs/core/blocks-test/test.blocks @@ -150,31 +150,31 @@ DisplayMode.Greyscale - AnalogPin.P4 + AnalogPin.C4 1023 - AnalogPin.P13 + AnalogPin.C5 - DigitalPin.P10 + DigitalPin.C10 0 - DigitalPin.P15 + DigitalPin.C15 - AnalogPin.P9 + AnalogPin.C6 1234 @@ -230,7 +230,7 @@ - AnalogPin.P14 + AnalogPin.C4 1500 @@ -510,7 +510,7 @@ - DigitalPin.P10 + DigitalPin.C10 PulseValue.Low @@ -575,8 +575,8 @@ DigitalPin.P9 - DigitalPin.P14 - DigitalPin.P16 + DigitalPin.C14 + DigitalPin.C16 diff --git a/libs/core/codal.cpp b/libs/core/codal.cpp index 65e757dc..7ddb371e 100644 --- a/libs/core/codal.cpp +++ b/libs/core/codal.cpp @@ -9,14 +9,18 @@ PXT_ABI(__aeabi_ddiv) PXT_ABI(__aeabi_dmul) extern "C" void target_panic(int error_code) { +#if !MICROBIT_CODAL // wait for serial to flush - wait_us(300000); + sleep_us(300000); +#endif microbit_panic(error_code); } +#if !MICROBIT_CODAL extern "C" void target_reset() { microbit_reset(); } +#endif uint32_t device_heap_size(uint8_t heap_index); // defined in microbit-dal @@ -27,7 +31,9 @@ MicroBitEvent lastEvent; void platform_init() { microbit_seed_random(); - seedRandom(microbit_random(0x7fffffff)); + int seed = microbit_random(0x7fffffff); + DMESG("random seed: %d", seed); + seedRandom(seed); } void initMicrobitGC() { @@ -43,7 +49,25 @@ struct FreeList { FreeList *next; }; +void dispatchForeground(MicroBitEvent e, void *action) { + lastEvent = e; + auto value = fromInt(e.value); + runAction1((Action)action, value); +} + +void deleteListener(MicroBitListener *l) { + if (l->cb_param == (void (*)(MicroBitEvent, void *))dispatchForeground) { + decr((Action)(l->cb_arg)); + unregisterGCPtr((Action)(l->cb_arg)); + } +} + static void initCodal() { + // TODO!!! +#ifndef MICROBIT_CODAL + uBit.messageBus.setListenerDeletionCallback(deleteListener); +#endif + // repeat error 4 times and restart as needed microbit_panic_timeout(4); } @@ -54,27 +78,11 @@ void dumpDmesg() {} // An adapter for the API expected by the run-time. // --------------------------------------------------------------------------- -// We have the invariant that if [dispatchEvent] is registered against the DAL -// for a given event, then [handlersMap] contains a valid entry for that -// event. -void dispatchEvent(MicroBitEvent e) { - lastEvent = e; - - auto curr = findBinding(e.source, e.value); - auto value = fromInt(e.value); - if (curr) - runAction1(curr->action, value); - - curr = findBinding(e.source, DEVICE_EVT_ANY); - if (curr) - runAction1(curr->action, value); -} - void registerWithDal(int id, int event, Action a, int flags) { - // first time? - if (!findBinding(id, event)) - uBit.messageBus.listen(id, event, dispatchEvent, flags); - setBinding(id, event, a); + uBit.messageBus.ignore(id, event, dispatchForeground); + uBit.messageBus.listen(id, event, dispatchForeground, a); + incr(a); + registerGCPtr(a); } void fiberDone(void *a) { @@ -92,7 +100,11 @@ void sleep_ms(unsigned ms) { } void sleep_us(uint64_t us) { +#if MICROBIT_CODAL + target_wait_us(us); +#else wait_us(us); +#endif } void forever_stub(void *a) { @@ -232,21 +244,43 @@ void setThreadContext(ThreadContext *ctx) { currentFiber->user_data = ctx; } +#if !MICROBIT_CODAL +#define tcb_get_stack_base(tcb) (tcb).stack_base +#endif + static void *threadAddressFor(Fiber *fib, void *sp) { if (fib == currentFiber) return sp; - return (uint8_t *)sp + ((uint8_t *)fib->stack_top - (uint8_t *)fib->tcb.stack_base); + + return (uint8_t *)sp + ((uint8_t *)fib->stack_top - (uint8_t *)tcb_get_stack_base(fib->tcb)); } void gcProcessStacks(int flags) { // check scheduler is initialized if (!currentFiber) { // make sure we allocate something to at least initalize the memory allocator - void * volatile p = xmalloc(1); + void *volatile p = xmalloc(1); xfree(p); return; } +#ifdef MICROBIT_GET_FIBER_LIST_SUPPORTED + for (Fiber *fib = get_fiber_list(); fib; fib = fib->next) { + auto ctx = (ThreadContext *)fib->user_data; + if (!ctx) + continue; + for (auto seg = &ctx->stack; seg; seg = seg->next) { + auto ptr = (TValue *)threadAddressFor(fib, seg->top); + auto end = (TValue *)threadAddressFor(fib, seg->bottom); + if (flags & 2) + DMESG("RS%d:%p/%d", cnt++, ptr, end - ptr); + // VLOG("mark: %p - %p", ptr, end); + while (ptr < end) { + gcProcess(*ptr++); + } + } + } +#else int numFibers = list_fibers(NULL); Fiber **fibers = (Fiber **)xmalloc(sizeof(Fiber *) * numFibers); int num2 = list_fibers(fibers); @@ -262,8 +296,10 @@ void gcProcessStacks(int flags) { for (auto seg = &ctx->stack; seg; seg = seg->next) { auto ptr = (TValue *)threadAddressFor(fib, seg->top); auto end = (TValue *)threadAddressFor(fib, seg->bottom); - if (flags & 2) - DMESG("RS%d:%p/%d", cnt++, ptr, end - ptr); + if (flags & 2) { + DMESG("RS%d:%p/%d", cnt, ptr, end - ptr); + cnt++; + } // VLOG("mark: %p - %p", ptr, end); while (ptr < end) { gcProcess(*ptr++); @@ -271,6 +307,7 @@ void gcProcessStacks(int flags) { } } xfree(fibers); +#endif } } // namespace pxt diff --git a/libs/core/console.ts b/libs/core/console.ts index 87ec98a2..a747dcfc 100644 --- a/libs/core/console.ts +++ b/libs/core/console.ts @@ -17,15 +17,15 @@ namespace console { */ //% weight=90 //% help=console/log blockGap=8 - //% text.shadowOptions.toString=true - export function log(text: string): void { + export function log(text: any): void { + let stringified = inspect(text); // pad text on the 32byte boundar - text += "\r\n"; - control.__log(text); + stringified += "\r\n"; + control.__log(stringified); // send to listeners if (listeners) for (let i = 0; i < listeners.length; ++i) - listeners[i](text); + listeners[i](stringified); } /** @@ -35,8 +35,9 @@ namespace console { */ //% weight=88 blockGap=8 //% help=console/log-value - export function logValue(name: string, value: number): void { - log(name ? `${name}: ${value}` : `${value}`) + export function logValue(name: any, value: number): void { + const nameText = inspect(name); + log(nameText ? `${nameText}: ${value}` : `${value}`) } /** @@ -50,4 +51,44 @@ namespace console { listeners = []; listeners.push(listener); } + + /** + * Convert any object or value to a string representation + * @param obj value to be converted to a string + * @param maxElements [optional] max number values in an object to include in output + */ + export function inspect(obj: any, maxElements = 20): string { + if (typeof obj == "string") { + return obj; + } else if (typeof obj == "number") { + return "" + obj; + } else if (Array.isArray(obj)) { + const asArr = (obj as Array); + if (asArr.length <= maxElements) { + return asArr.join(","); + } else { + return `${asArr.slice(0, maxElements).join(",")}...`; + } + } else { + const asString = obj + ""; + if (asString != "[object Object]" + && asString != "[Object]") { // on arcade at least, default toString is [Object] on hardware instead of standard + return asString; + } + + let keys = Object.keys(obj); + const snipped = keys.length > maxElements; + if (snipped) { + keys = keys.slice(0, maxElements); + } + + return `{${ + keys.reduce( + (prev, currKey) => prev + `\n ${currKey}: ${obj[currKey]}`, + "" + ) + (snipped ? "\n ..." : "") + } +}`; + } + } } \ No newline at end of file diff --git a/libs/core/control.cpp b/libs/core/control.cpp index c40c8bc6..91f04e92 100644 --- a/libs/core/control.cpp +++ b/libs/core/control.cpp @@ -274,7 +274,7 @@ namespace control { //% help=control/wait-micros weight=29 //% blockId="control_wait_us" block="wait (µs)%micros" void waitMicros(int micros) { - wait_us(micros); + sleep_us(micros); } /** @@ -297,7 +297,7 @@ namespace control { //% help=control/on-event //% blockExternalInputs=1 void onEvent(int src, int value, Action handler, int flags = 0) { - if (!flags) flags = EventFlags::QueueIfBusy; + if (!flags) flags = ::EventFlags::QueueIfBusy; registerWithDal(src, value, handler, (int)flags); } @@ -325,6 +325,7 @@ namespace control { * Make a friendly name for the device based on its serial number */ //% blockId="control_device_name" block="device name" weight=10 blockGap=8 + //% help=control/device-name //% advanced=true String deviceName() { return mkString(microbit_friendly_name(), -1); @@ -334,6 +335,7 @@ namespace control { * Derive a unique, consistent serial number of this device from internal data. */ //% blockId="control_device_serial_number" block="device serial number" weight=9 + //% help=control/device-serial-number //% advanced=true int deviceSerialNumber() { return microbit_serial_number(); diff --git a/libs/core/control.ts b/libs/core/control.ts index a6f49206..bfe80818 100644 --- a/libs/core/control.ts +++ b/libs/core/control.ts @@ -4,11 +4,19 @@ //% weight=1 color="#42495F" icon="\uf233" //% advanced=true namespace control { + /** + * Run other code in the parallel. + */ + //% hidden=1 + export function runInParallel(a: () => void) { + control.inBackground(a); + } /** * Returns the value of a C++ runtime constant */ //% weight=2 weight=19 blockId="control_event_source_id" block="%id" blockGap=8 + //% help=control/event-source-id //% shim=TD_ID advanced=true export function eventSourceId(id: EventBusSource): number { return id; @@ -17,6 +25,7 @@ namespace control { * Returns the value of a C++ runtime constant */ //% weight=1 weight=19 blockId="control_event_value_id" block="%id" + //% help=control/event-value-id //% shim=TD_ID advanced=true export function eventValueId(id: EventBusValue): number { return id; @@ -63,4 +72,4 @@ namespace control { //% blockId=variable_to_text blockNamespace="text" function convertToText(value: any): string { return "" + value; -} +} \ No newline at end of file diff --git a/libs/core/dal.d.ts b/libs/core/dal.d.ts index 7156889d..4ce7f8b2 100644 --- a/libs/core/dal.d.ts +++ b/libs/core/dal.d.ts @@ -1,11 +1,741 @@ // Auto-generated. Do not edit. declare const enum DAL { - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/ExternalEvents.h + // /libraries/codal-core/inc/JACDAC/JACDAC.h + JD_STARTED = 2, + JD_SERVICE_ARRAY_SIZE = 20, + // /libraries/codal-core/inc/JACDAC/JDPhysicalLayer.h + JD_VERSION = 0, + JD_BYTE_AT_125KBAUD = 80, + JD_MIN_INTERLODATA_SPACING = 40, + JD_SERIAL_MAX_BUFFERS = 10, + JD_SERIAL_MAX_SERVICE_NUMBER = 15, + JD_SERIAL_RECEIVING = 1, + JD_SERIAL_RECEIVING_HEADER = 2, + JD_SERIAL_TRANSMITTING = 4, + JD_SERIAL_RX_LO_PULSE = 8, + JD_SERIAL_TX_LO_PULSE = 16, + JD_SERIAL_BUS_LO_ERROR = 32, + JD_SERIAL_BUS_TIMEOUT_ERROR = 64, + JD_SERIAL_BUS_UART_ERROR = 128, + JD_SERIAL_ERR_MSK = 224, + JD_SERIAL_BUS_STATE = 256, + JD_SERIAL_BUS_TOGGLED = 512, + JD_SERIAL_DEBUG_BIT = 32768, + JD_SERIAL_EVT_DATA_READY = 1, + JD_SERIAL_EVT_BUS_ERROR = 2, + JD_SERIAL_EVT_CRC_ERROR = 3, + JD_SERIAL_EVT_DRAIN = 4, + JD_SERIAL_EVT_RX_TIMEOUT = 5, + JD_SERIAL_EVT_BUS_CONNECTED = 5, + JD_SERIAL_EVT_BUS_DISCONNECTED = 6, + JD_SERIAL_HEADER_SIZE = 4, + JD_SERIAL_CRC_HEADER_SIZE = 2, + JD_SERIAL_MAX_PAYLOAD_SIZE = 255, + JD_SERIAL_MAXIMUM_BUFFERS = 10, + JD_SERIAL_DMA_TIMEOUT = 2, + JD_SERIAL_MAX_BAUD = 1000000, + JD_SERIAL_TX_MAX_BACKOFF = 1000, + JD_RX_ARRAY_SIZE = 10, + JD_TX_ARRAY_SIZE = 10, + JD_SERIAL_BAUD_1M = 1, + JD_SERIAL_BAUD_500K = 2, + JD_SERIAL_BAUD_250K = 4, + JD_SERIAL_BAUD_125K = 8, + Receiving = 0, + Transmitting = 1, + Unknown = 3, + ListeningForPulse = 0, + ErrorRecovery = 1, + Off = 2, + Baud1M = 1, + Baud500K = 2, + Baud250K = 4, + Baud125K = 8, + Continuation = 0, + BusLoError = 32, + BusTimeoutError = 64, + BusUARTError = 128, + // /libraries/codal-core/inc/JACDAC/JDService.h + JD_MAX_HOST_SERVICES = 16, + JD_SERVICE_EVT_CONNECTED = 65520, + JD_SERVICE_EVT_DISCONNECTED = 65521, + JD_SERVICE_EVT_ERROR = 65526, + JD_SERVICE_NUMBER_UNINITIALISED_VAL = 65535, + JD_SERVICE_STATUS_FLAGS_INITIALISED = 2, + JD_SERVICE_INFO_HEADER_SIZE = 6, + JD_SERVICE_MODE_CLIENT = 1, + JD_SERVICE_MODE_HOST = 2, + JD_SERVICE_MODE_BROADCAST_HOST = 3, + JD_SERVICE_MODE_CONTROL_LAYER = 4, + ClientService = 1, + HostService = 2, + BroadcastHostService = 3, + ControlLayerService = 4, + // /libraries/codal-core/inc/JACDAC/JDServiceClasses.h + STATIC_CLASS_START = 0, + STATIC_CLASS_END = 16777215, + DYNAMIC_CLASS_END = 4294967295, + JD_SERVICE_CLASS_CODAL_START = 0, + JD_SERVICE_CLASS_CODAL_END = 2000, + JD_SERVICE_CLASS_MAKECODE_START = 2000, + JD_SERVICE_CLASS_MAKECODE_END = 4000, + JD_SERVICE_CLASS_CONTROL = 0, + JD_SERVICE_CLASS_CONTROL_RNG = 1, + JD_SERVICE_CLASS_CONTROL_CONFIGURATION = 2, + JD_SERVICE_CLASS_CONTROL_TEST = 3, + JD_SERVICE_CLASS_JOYSTICK = 4, + JD_SERVICE_CLASS_MESSAGE_BUS = 5, + JD_SERVICE_CLASS_BRIDGE = 6, + JD_SERVICE_CLASS_BUTTON = 7, + JD_SERVICE_CLASS_ACCELEROMETER = 8, + JD_SERVICE_CLASS_CONSOLE = 9, + // /libraries/codal-core/inc/JACDAC/control/JDCRC.h + JD_CRC_POLYNOMIAL = 3859, + // /libraries/codal-core/inc/JACDAC/control/JDConfigurationService.h + JD_CONTROL_CONFIGURATION_SERVICE_NUMBER = 1, + JD_CONTROL_CONFIGURATION_SERVICE_REQUEST_TYPE_NAME = 1, + JD_CONTROL_CONFIGURATION_SERVICE_REQUEST_TYPE_IDENTIFY = 2, + JD_CONTROL_CONFIGURATION_SERVICE_PACKET_HEADER_SIZE = 2, + JD_CONTROL_CONFIGURATION_EVT_NAME = 1, + JD_CONTROL_CONFIGURATION_EVT_IDENTIFY = 2, + JD_DEFAULT_INDICATION_TIME = 5, + // /libraries/codal-core/inc/JACDAC/control/JDControlService.h + JD_CONTROL_SERVICE_STATUS_ENUMERATE = 2, + JD_CONTROL_SERVICE_STATUS_ENUMERATING = 4, + JD_CONTROL_SERVICE_STATUS_ENUMERATED = 8, + JD_CONTROL_SERVICE_STATUS_BUS_LO = 16, + JD_CONTROL_SERVICE_EVT_CHANGED = 2, + JD_CONTROL_SERVICE_EVT_TIMER_CALLBACK = 3, + JD_CONTROL_PACKET_HEADER_SIZE = 10, + JD_CONTROL_ROLLING_TIMEOUT_VAL = 3, + // /libraries/codal-core/inc/JACDAC/control/JDDeviceManager.h + JD_DEVICE_FLAGS_NACK = 8, + JD_DEVICE_FLAGS_HAS_NAME = 4, + JD_DEVICE_FLAGS_PROPOSING = 2, + JD_DEVICE_FLAGS_REJECT = 1, + JD_DEVICE_MAX_HOST_SERVICES = 16, + JD_DEVICE_DEFAULT_COMMUNICATION_RATE = 1, + // /libraries/codal-core/inc/JACDAC/control/JDRNGService.h + JD_CONTROL_RNG_SERVICE_NUMBER = 2, + JD_CONTROL_RNG_SERVICE_REQUEST_TYPE_REQ = 1, + JD_CONTROL_RNG_SERVICE_REQUEST_TYPE_RESP = 2, + // /libraries/codal-core/inc/JACDAC/services/JDAccelerometerService.h + JD_ACCEL_EVT_SEND_DATA = 1, + // /libraries/codal-core/inc/JACDAC/services/JDConsoleService.h + JD_CONSOLE_LOG_PRIORITY_LOG = 1, + JD_CONSOLE_LOG_PRIORITY_INFO = 2, + JD_CONSOLE_LOG_PRIORITY_DEBUG = 3, + JD_CONSOLE_LOG_PRIORITY_ERROR = 4, + Log = 1, + Info = 2, + Debug = 3, + // /libraries/codal-core/inc/JACDAC/services/JDMessageBusService.h + JD_MESSAGEBUS_TYPE_EVENT = 1, + JD_MESSAGEBUS_TYPE_LISTEN = 2, + // /libraries/codal-core/inc/core/CodalComponent.h + DEVICE_ID_BUTTON_A = 1, + DEVICE_ID_BUTTON_B = 2, + DEVICE_ID_BUTTON_AB = 3, + DEVICE_ID_BUTTON_RESET = 4, + DEVICE_ID_ACCELEROMETER = 5, + DEVICE_ID_COMPASS = 6, + DEVICE_ID_DISPLAY = 7, + DEVICE_ID_THERMOMETER = 8, + DEVICE_ID_RADIO = 9, + DEVICE_ID_RADIO_DATA_READY = 10, + DEVICE_ID_MULTIBUTTON_ATTACH = 11, + DEVICE_ID_SERIAL = 12, + DEVICE_ID_GESTURE = 13, + DEVICE_ID_SYSTEM_TIMER = 14, + DEVICE_ID_SCHEDULER = 15, + DEVICE_ID_COMPONENT = 16, + DEVICE_ID_LIGHT_SENSOR = 17, + DEVICE_ID_TOUCH_SENSOR = 18, + DEVICE_ID_SYSTEM_DAC = 19, + DEVICE_ID_SYSTEM_MICROPHONE = 20, + DEVICE_ID_SYSTEM_LEVEL_DETECTOR = 21, + DEVICE_ID_SYSTEM_LEVEL_DETECTOR_SPL = 22, + DEVICE_ID_MSC = 23, + DEVICE_ID_SPI = 24, + DEVICE_ID_DISTANCE = 25, + DEVICE_ID_GYROSCOPE = 26, + DEVICE_ID_HUMIDITY = 27, + DEVICE_ID_PRESSURE = 28, + DEVICE_ID_SINGLE_WIRE_SERIAL = 29, + DEVICE_ID_JACDAC = 30, + DEVICE_ID_JACDAC_PHYS = 31, + DEVICE_ID_JACDAC_CONTROL_SERVICE = 32, + DEVICE_ID_JACDAC_CONFIGURATION_SERVICE = 33, + DEVICE_ID_IO_P0 = 100, + DEVICE_ID_MESSAGE_BUS_LISTENER = 1021, + DEVICE_ID_NOTIFY_ONE = 1022, + DEVICE_ID_NOTIFY = 1023, + DEVICE_ID_BUTTON_UP = 2000, + DEVICE_ID_BUTTON_DOWN = 2001, + DEVICE_ID_BUTTON_LEFT = 2002, + DEVICE_ID_BUTTON_RIGHT = 2003, + DEVICE_ID_JD_DYNAMIC_ID = 3000, + DEVICE_COMPONENT_RUNNING = 4096, + DEVICE_COMPONENT_STATUS_SYSTEM_TICK = 8192, + DEVICE_COMPONENT_STATUS_IDLE_TICK = 16384, + DEVICE_COMPONENT_LISTENERS_CONFIGURED = 1, + DEVICE_COMPONENT_EVT_SYSTEM_TICK = 1, + // /libraries/codal-core/inc/core/CodalFiber.h + DEVICE_SCHEDULER_RUNNING = 1, + DEVICE_SCHEDULER_IDLE = 2, + DEVICE_FIBER_FLAG_FOB = 1, + DEVICE_FIBER_FLAG_PARENT = 2, + DEVICE_FIBER_FLAG_CHILD = 4, + DEVICE_FIBER_FLAG_DO_NOT_PAGE = 8, + DEVICE_SCHEDULER_EVT_TICK = 1, + DEVICE_SCHEDULER_EVT_IDLE = 2, + // /libraries/codal-core/inc/core/CodalListener.h + MESSAGE_BUS_LISTENER_PARAMETERISED = 1, + MESSAGE_BUS_LISTENER_METHOD = 2, + MESSAGE_BUS_LISTENER_BUSY = 4, + MESSAGE_BUS_LISTENER_REENTRANT = 8, + MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY = 16, + MESSAGE_BUS_LISTENER_DROP_IF_BUSY = 32, + MESSAGE_BUS_LISTENER_NONBLOCKING = 64, + MESSAGE_BUS_LISTENER_URGENT = 128, + MESSAGE_BUS_LISTENER_DELETING = 32768, + MESSAGE_BUS_LISTENER_IMMEDIATE = 192, + // /libraries/codal-core/inc/core/ErrorNo.h + DEVICE_OK = 0, + DEVICE_INVALID_PARAMETER = -1001, + DEVICE_NOT_SUPPORTED = -1002, + DEVICE_CALIBRATION_IN_PROGRESS = -1003, + DEVICE_CALIBRATION_REQUIRED = -1004, + DEVICE_NO_RESOURCES = -1005, + DEVICE_BUSY = -1006, + DEVICE_CANCELLED = -1007, + DEVICE_I2C_ERROR = -1010, + DEVICE_SERIAL_IN_USE = -1011, + DEVICE_NO_DATA = -1012, + DEVICE_NOT_IMPLEMENTED = -1013, + DEVICE_SPI_ERROR = -1014, + DEVICE_INVALID_STATE = -1015, + DEVICE_OOM = 20, + DEVICE_HEAP_ERROR = 30, + DEVICE_NULL_DEREFERENCE = 40, + DEVICE_USB_ERROR = 50, + DEVICE_JACDAC_ERROR = 60, + DEVICE_HARDWARE_CONFIGURATION_ERROR = 90, + // /libraries/codal-core/inc/core/NotifyEvents.h + DISPLAY_EVT_FREE = 1, + CODAL_SERIAL_EVT_TX_EMPTY = 2, + BLE_EVT_SERIAL_TX_EMPTY = 3, + ARCADE_PLAYER_JOIN_RESULT = 4, + DEVICE_NOTIFY_USER_EVENT_BASE = 1024, + // /libraries/codal-core/inc/driver-models/AbstractButton.h + DEVICE_BUTTON_EVT_DOWN = 1, + DEVICE_BUTTON_EVT_UP = 2, + DEVICE_BUTTON_EVT_CLICK = 3, + DEVICE_BUTTON_EVT_LONG_CLICK = 4, + DEVICE_BUTTON_EVT_HOLD = 5, + DEVICE_BUTTON_EVT_DOUBLE_CLICK = 6, + DEVICE_BUTTON_LONG_CLICK_TIME = 1000, + DEVICE_BUTTON_HOLD_TIME = 1500, + DEVICE_BUTTON_STATE = 1, + DEVICE_BUTTON_STATE_HOLD_TRIGGERED = 2, + DEVICE_BUTTON_STATE_CLICK = 4, + DEVICE_BUTTON_STATE_LONG_CLICK = 8, + DEVICE_BUTTON_SIGMA_MIN = 0, + DEVICE_BUTTON_SIGMA_MAX = 12, + DEVICE_BUTTON_SIGMA_THRESH_HI = 8, + DEVICE_BUTTON_SIGMA_THRESH_LO = 2, + DEVICE_BUTTON_DOUBLE_CLICK_THRESH = 50, + DEVICE_BUTTON_SIMPLE_EVENTS = 0, + DEVICE_BUTTON_ALL_EVENTS = 1, + ACTIVE_LOW = 0, + ACTIVE_HIGH = 1, + // /libraries/codal-core/inc/driver-models/Accelerometer.h + ACCELEROMETER_IMU_DATA_VALID = 2, + ACCELEROMETER_EVT_DATA_UPDATE = 1, + ACCELEROMETER_EVT_NONE = 0, + ACCELEROMETER_EVT_TILT_UP = 1, + ACCELEROMETER_EVT_TILT_DOWN = 2, + ACCELEROMETER_EVT_TILT_LEFT = 3, + ACCELEROMETER_EVT_TILT_RIGHT = 4, + ACCELEROMETER_EVT_FACE_UP = 5, + ACCELEROMETER_EVT_FACE_DOWN = 6, + ACCELEROMETER_EVT_FREEFALL = 7, + ACCELEROMETER_EVT_3G = 8, + ACCELEROMETER_EVT_6G = 9, + ACCELEROMETER_EVT_8G = 10, + ACCELEROMETER_EVT_SHAKE = 11, + ACCELEROMETER_EVT_2G = 12, + ACCELEROMETER_REST_TOLERANCE = 200, + ACCELEROMETER_TILT_TOLERANCE = 200, + ACCELEROMETER_FREEFALL_TOLERANCE = 400, + ACCELEROMETER_SHAKE_TOLERANCE = 400, + ACCELEROMETER_2G_TOLERANCE = 2048, + ACCELEROMETER_3G_TOLERANCE = 3072, + ACCELEROMETER_6G_TOLERANCE = 6144, + ACCELEROMETER_8G_TOLERANCE = 8192, + ACCELEROMETER_GESTURE_DAMPING = 5, + ACCELEROMETER_SHAKE_DAMPING = 10, + ACCELEROMETER_SHAKE_RTX = 30, + ACCELEROMETER_SHAKE_COUNT_THRESHOLD = 4, + // /libraries/codal-core/inc/driver-models/Compass.h + COMPASS_STATUS_RUNNING = 1, + COMPASS_STATUS_CALIBRATED = 2, + COMPASS_STATUS_CALIBRATING = 4, + COMPASS_STATUS_ADDED_TO_IDLE = 8, + COMPASS_EVT_DATA_UPDATE = 1, + COMPASS_EVT_CONFIG_NEEDED = 2, + COMPASS_EVT_CALIBRATE = 3, + COMPASS_EVT_CALIBRATION_NEEDED = 4, + // /libraries/codal-core/inc/driver-models/Gyroscope.h + GYROSCOPE_IMU_DATA_VALID = 2, + GYROSCOPE_EVT_DATA_UPDATE = 1, + // /libraries/codal-core/inc/driver-models/LowLevelTimer.h + TimerModeTimer = 0, + TimerModeCounter = 1, + TimerModeAlternateFunction = 2, + BitMode8 = 0, + BitMode16 = 1, + BitMode24 = 2, + BitMode32 = 3, + // /libraries/codal-core/inc/driver-models/Pin.h + IO_STATUS_DIGITAL_IN = 1, + IO_STATUS_DIGITAL_OUT = 2, + IO_STATUS_ANALOG_IN = 4, + IO_STATUS_ANALOG_OUT = 8, + IO_STATUS_TOUCH_IN = 16, + IO_STATUS_EVENT_ON_EDGE = 32, + IO_STATUS_EVENT_PULSE_ON_EDGE = 64, + IO_STATUS_INTERRUPT_ON_EDGE = 128, + IO_STATUS_ACTIVE_HI = 256, + DEVICE_PIN_MAX_OUTPUT = 1023, + DEVICE_PIN_MAX_SERVO_RANGE = 180, + DEVICE_PIN_DEFAULT_SERVO_RANGE = 2000, + DEVICE_PIN_DEFAULT_SERVO_CENTER = 1500, + DEVICE_PIN_EVENT_NONE = 0, + DEVICE_PIN_INTERRUPT_ON_EDGE = 1, + DEVICE_PIN_EVENT_ON_EDGE = 2, + DEVICE_PIN_EVENT_ON_PULSE = 3, + DEVICE_PIN_EVENT_ON_TOUCH = 4, + DEVICE_PIN_EVT_RISE = 2, + DEVICE_PIN_EVT_FALL = 3, + DEVICE_PIN_EVT_PULSE_HI = 4, + DEVICE_PIN_EVT_PULSE_LO = 5, + PIN_CAPABILITY_DIGITAL = 1, + PIN_CAPABILITY_ANALOG = 2, + PIN_CAPABILITY_AD = 3, + PIN_CAPABILITY_ALL = 3, + None = 0, + Down = 1, + Up = 2, + // /libraries/codal-core/inc/driver-models/Radio.h + RADIO_EVT_DATA_READY = 2, + // /libraries/codal-core/inc/driver-models/SPIFlash.h + SPIFLASH_PAGE_SIZE = 256, + SPIFLASH_SMALL_ROW_PAGES = 16, + SPIFLASH_BIG_ROW_PAGES = 256, + // /libraries/codal-core/inc/driver-models/Sensor.h + SENSOR_THRESHOLD_LOW = 1, + SENSOR_THRESHOLD_HIGH = 2, + SENSOR_UPDATE_NEEDED = 3, + SENSOR_INITIALISED = 1, + SENSOR_HIGH_THRESHOLD_PASSED = 2, + SENSOR_LOW_THRESHOLD_PASSED = 4, + SENSOR_LOW_THRESHOLD_ENABLED = 8, + SENSOR_HIGH_THRESHOLD_ENABLED = 16, + SENSOR_DEFAULT_SENSITIVITY = 868, + SENSOR_DEFAULT_SAMPLE_PERIOD = 500, + // /libraries/codal-core/inc/driver-models/Serial.h + CODAL_SERIAL_DEFAULT_BAUD_RATE = 115200, + CODAL_SERIAL_DEFAULT_BUFFER_SIZE = 20, + CODAL_SERIAL_EVT_DELIM_MATCH = 1, + CODAL_SERIAL_EVT_HEAD_MATCH = 2, + CODAL_SERIAL_EVT_RX_FULL = 3, + CODAL_SERIAL_EVT_DATA_RECEIVED = 4, + CODAL_SERIAL_STATUS_RX_IN_USE = 1, + CODAL_SERIAL_STATUS_TX_IN_USE = 2, + CODAL_SERIAL_STATUS_RX_BUFF_INIT = 4, + CODAL_SERIAL_STATUS_TX_BUFF_INIT = 8, + CODAL_SERIAL_STATUS_RXD = 16, + ASYNC = 0, + SYNC_SPINWAIT = 1, + SYNC_SLEEP = 2, + RxInterrupt = 0, + TxInterrupt = 1, + // /libraries/codal-core/inc/driver-models/SingleWireSerial.h + SWS_EVT_DATA_RECEIVED = 1, + SWS_EVT_DATA_SENT = 2, + SWS_EVT_ERROR = 3, + SWS_EVT_DATA_DROPPED = 4, + SingleWireRx = 0, + SingleWireTx = 1, + SingleWireDisconnected = 2, + // /libraries/codal-core/inc/driver-models/Timer.h + CODAL_TIMER_DEFAULT_EVENT_LIST_SIZE = 10, + // /libraries/codal-core/inc/drivers/AnalogSensor.h + ANALOG_THRESHOLD_LOW = 1, + ANALOG_THRESHOLD_HIGH = 2, + ANALOG_SENSOR_UPDATE_NEEDED = 3, + ANALOG_SENSOR_INITIALISED = 1, + ANALOG_SENSOR_HIGH_THRESHOLD_PASSED = 2, + ANALOG_SENSOR_LOW_THRESHOLD_PASSED = 4, + ANALOG_SENSOR_LOW_THRESHOLD_ENABLED = 8, + ANALOG_SENSOR_HIGH_THRESHOLD_ENABLED = 16, + // /libraries/codal-core/inc/drivers/AnimatedDisplay.h + DISPLAY_EVT_ANIMATION_COMPLETE = 1, + DISPLAY_DEFAULT_AUTOCLEAR = 1, + DISPLAY_SPACING = 1, + DISPLAY_ANIMATE_DEFAULT_POS = -255, + DISPLAY_DEFAULT_SCROLL_SPEED = 120, + DISPLAY_DEFAULT_SCROLL_STRIDE = -1, + DISPLAY_DEFAULT_PRINT_SPEED = 400, + ANIMATION_MODE_NONE = 0, + ANIMATION_MODE_STOPPED = 1, + ANIMATION_MODE_SCROLL_TEXT = 2, + ANIMATION_MODE_PRINT_TEXT = 3, + ANIMATION_MODE_SCROLL_IMAGE = 4, + ANIMATION_MODE_ANIMATE_IMAGE = 5, + ANIMATION_MODE_ANIMATE_IMAGE_WITH_CLEAR = 6, + ANIMATION_MODE_PRINT_CHARACTER = 7, + // /libraries/codal-core/inc/drivers/FAT.h + FAT_RESERVED_SECTORS = 1, + FAT_ROOT_DIR_SECTORS = 4, + // /libraries/codal-core/inc/drivers/HID.h + HID_REQUEST_GET_REPORT = 1, + HID_REQUEST_GET_IDLE = 2, + HID_REQUEST_GET_PROTOCOL = 3, + HID_REQUEST_SET_REPORT = 9, + HID_REQUEST_SET_IDLE = 10, + HID_REQUEST_SET_PROTOCOL = 11, + // /libraries/codal-core/inc/drivers/HIDKeyboard.h + HID_KEYBOARD_NUM_REPORTS = 3, + HID_KEYBOARD_REPORT_GENERIC = 1, + HID_KEYBOARD_REPORT_CONSUMER = 2, + HID_KEYBOARD_KEYSTATE_SIZE_GENERIC = 8, + HID_KEYBOARD_KEYSTATE_SIZE_CONSUMER = 2, + HID_KEYBOARD_MODIFIER_OFFSET = 2, + HID_KEYBOARD_DELAY_DEFAULT = 10, + PressKey = 0, + ReleaseKey = 1, + // /libraries/codal-core/inc/drivers/KeyMap.h + KEYMAP_ALL_KEYS_UP_Val = 1, + KEYMAP_ALL_KEYS_UP_POS = 28, + KEYMAP_NORMAL_KEY_Val = 0, + KEYMAP_MODIFIER_KEY_Val = 1, + KEYMAP_MODIFIER_POS = 29, + KEYMAP_MEDIA_KEY_Val = 1, + KEYMAP_MEDIA_POS = 30, + KEYMAP_KEY_UP_Val = 0, + KEYMAP_KEY_DOWN_Val = 1, + KEYMAP_KEY_DOWN_POS = 31, + // /libraries/codal-core/inc/drivers/KeyValueStorage.h + DEVICE_KEY_VALUE_STORE_OFFSET = 4, + KEY_VALUE_STORAGE_MAGIC = 49370, + KEY_VALUE_STORAGE_BLOCK_SIZE = 48, + KEY_VALUE_STORAGE_KEY_SIZE = 16, + KEY_VALUE_STORAGE_SCRATCH_WORD_SIZE = 64, + KEY_VALUE_STORAGE_MAX_PAIRS = 5, + // /libraries/codal-core/inc/drivers/LEDMatrix.h + LED_MATRIX_GREYSCALE_BIT_DEPTH = 8, + LED_MATRIX_EVT_LIGHT_SENSE = 2, + LED_MATRIX_EVT_FRAME_TIMEOUT = 3, + LED_MATRIX_MINIMUM_BRIGHTNESS = 1, + LED_MATRIX_MAXIMUM_BRIGHTNESS = 255, + LED_MATRIX_DEFAULT_BRIGHTNESS = 255, + DISPLAY_MODE_BLACK_AND_WHITE = 0, + DISPLAY_MODE_GREYSCALE = 1, + DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE = 2, + MATRIX_DISPLAY_ROTATION_0 = 0, + MATRIX_DISPLAY_ROTATION_90 = 1, + MATRIX_DISPLAY_ROTATION_180 = 2, + MATRIX_DISPLAY_ROTATION_270 = 3, + NO_CONN = 0, + // /libraries/codal-core/inc/drivers/MAG3110.h + MAG3110_DEFAULT_ADDR = 29, + MAG3110_SAMPLE_RATES = 11, + MAG3110_WHOAMI_VAL = 196, + // /libraries/codal-core/inc/drivers/MMA8653.h + MICROBIT_ACCEL_PITCH_ROLL_VALID = 2, + // /libraries/codal-core/inc/drivers/MultiButton.h + MULTI_BUTTON_STATE_1 = 1, + MULTI_BUTTON_STATE_2 = 2, + MULTI_BUTTON_HOLD_TRIGGERED_1 = 4, + MULTI_BUTTON_HOLD_TRIGGERED_2 = 8, + MULTI_BUTTON_SUPRESSED_1 = 16, + MULTI_BUTTON_SUPRESSED_2 = 32, + MULTI_BUTTON_ATTACHED = 64, + // /libraries/codal-core/inc/drivers/ST7735.h + MADCTL_MY = 128, + MADCTL_MX = 64, + MADCTL_MV = 32, + MADCTL_ML = 16, + MADCTL_RGB = 0, + MADCTL_BGR = 8, + MADCTL_MH = 4, + // /libraries/codal-core/inc/drivers/TouchButton.h + TOUCH_BUTTON_CALIBRATION_PERIOD = 10, + TOUCH_BUTTON_CALIBRATION_LINEAR_OFFSET = 2, + TOUCH_BUTTON_CALIBRATION_PERCENTAGE_OFFSET = 5, + TOUCH_BUTTON_CALIBRATING = 16, + // /libraries/codal-core/inc/drivers/TouchSensor.h + TOUCH_SENSOR_MAX_BUTTONS = 10, + TOUCH_SENSOR_SAMPLE_PERIOD = 50, + TOUCH_SENSE_SAMPLE_MAX = 1000, + TOUCH_SENSOR_UPDATE_NEEDED = 1, + // /libraries/codal-core/inc/drivers/USBJACDAC.h + JACDAC_USB_STATUS_CLEAR_TO_SEND = 2, + // /libraries/codal-core/inc/drivers/USB_HID_Keys.h + KEY_MOD_LCTRL = 1, + KEY_MOD_LSHIFT = 2, + KEY_MOD_LALT = 4, + KEY_MOD_LMETA = 8, + KEY_MOD_RCTRL = 16, + KEY_MOD_RSHIFT = 32, + KEY_MOD_RALT = 64, + KEY_MOD_RMETA = 128, + KEY_NONE = 0, + KEY_ERR_OVF = 1, + KEY_A = 4, + KEY_B = 5, + KEY_C = 6, + KEY_D = 7, + KEY_E = 8, + KEY_F = 9, + KEY_G = 10, + KEY_H = 11, + KEY_I = 12, + KEY_J = 13, + KEY_K = 14, + KEY_L = 15, + KEY_M = 16, + KEY_N = 17, + KEY_O = 18, + KEY_P = 19, + KEY_Q = 20, + KEY_R = 21, + KEY_S = 22, + KEY_T = 23, + KEY_U = 24, + KEY_V = 25, + KEY_W = 26, + KEY_X = 27, + KEY_Y = 28, + KEY_Z = 29, + KEY_1 = 30, + KEY_2 = 31, + KEY_3 = 32, + KEY_4 = 33, + KEY_5 = 34, + KEY_6 = 35, + KEY_7 = 36, + KEY_8 = 37, + KEY_9 = 38, + KEY_0 = 39, + KEY_ENTER = 40, + KEY_ESC = 41, + KEY_BACKSPACE = 42, + KEY_TAB = 43, + KEY_SPACE = 44, + KEY_MINUS = 45, + KEY_EQUAL = 46, + KEY_LEFTBRACE = 47, + KEY_RIGHTBRACE = 48, + KEY_BACKSLASH = 49, + KEY_HASHTILDE = 50, + KEY_SEMICOLON = 51, + KEY_APOSTROPHE = 52, + KEY_GRAVE = 53, + KEY_COMMA = 54, + KEY_DOT = 55, + KEY_SLASH = 56, + KEY_CAPSLOCK = 57, + KEY_F1 = 58, + KEY_F2 = 59, + KEY_F3 = 60, + KEY_F4 = 61, + KEY_F5 = 62, + KEY_F6 = 63, + KEY_F7 = 64, + KEY_F8 = 65, + KEY_F9 = 66, + KEY_F10 = 67, + KEY_F11 = 68, + KEY_F12 = 69, + KEY_SYSRQ = 70, + KEY_SCROLLLOCK = 71, + KEY_PAUSE = 72, + KEY_INSERT = 73, + KEY_HOME = 74, + KEY_PAGEUP = 75, + KEY_DELETE = 76, + KEY_END = 77, + KEY_PAGEDOWN = 78, + KEY_RIGHT = 79, + KEY_LEFT = 80, + KEY_DOWN = 81, + KEY_UP = 82, + KEY_NUMLOCK = 83, + KEY_KPSLASH = 84, + KEY_KPASTERISK = 85, + KEY_KPMINUS = 86, + KEY_KPPLUS = 87, + KEY_KPENTER = 88, + KEY_KP1 = 89, + KEY_KP2 = 90, + KEY_KP3 = 91, + KEY_KP4 = 92, + KEY_KP5 = 93, + KEY_KP6 = 94, + KEY_KP7 = 95, + KEY_KP8 = 96, + KEY_KP9 = 97, + KEY_KP0 = 98, + KEY_KPDOT = 99, + KEY_102ND = 100, + KEY_COMPOSE = 101, + KEY_POWER = 102, + KEY_KPEQUAL = 103, + KEY_F13 = 104, + KEY_F14 = 105, + KEY_F15 = 106, + KEY_F16 = 107, + KEY_F17 = 108, + KEY_F18 = 109, + KEY_F19 = 110, + KEY_F20 = 111, + KEY_F21 = 112, + KEY_F22 = 113, + KEY_F23 = 114, + KEY_F24 = 115, + KEY_OPEN = 116, + KEY_HELP = 117, + KEY_PROPS = 118, + KEY_FRONT = 119, + KEY_STOP = 120, + KEY_AGAIN = 121, + KEY_UNDO = 122, + KEY_CUT = 123, + KEY_COPY = 124, + KEY_PASTE = 125, + KEY_FIND = 126, + KEY_MUTE = 127, + KEY_VOLUMEUP = 128, + KEY_VOLUMEDOWN = 129, + KEY_KPCOMMA = 133, + KEY_RO = 135, + KEY_KATAKANAHIRAGANA = 136, + KEY_YEN = 137, + KEY_HENKAN = 138, + KEY_MUHENKAN = 139, + KEY_KPJPCOMMA = 140, + KEY_HANGEUL = 144, + KEY_HANJA = 145, + KEY_KATAKANA = 146, + KEY_HIRAGANA = 147, + KEY_ZENKAKUHANKAKU = 148, + KEY_KPLEFTPAREN = 182, + KEY_KPRIGHTPAREN = 183, + KEY_LEFTCTRL = 224, + KEY_LEFTSHIFT = 225, + KEY_LEFTALT = 226, + KEY_LEFTMETA = 227, + KEY_RIGHTCTRL = 228, + KEY_RIGHTSHIFT = 229, + KEY_RIGHTALT = 230, + KEY_RIGHTMETA = 231, + KEY_MEDIA_PLAYPAUSE = 232, + KEY_MEDIA_STOPCD = 233, + KEY_MEDIA_PREVIOUSSONG = 234, + KEY_MEDIA_NEXTSONG = 235, + KEY_MEDIA_EJECTCD = 236, + KEY_MEDIA_VOLUMEUP = 237, + KEY_MEDIA_VOLUMEDOWN = 238, + KEY_MEDIA_MUTE = 239, + KEY_MEDIA_WWW = 240, + KEY_MEDIA_BACK = 241, + KEY_MEDIA_FORWARD = 242, + KEY_MEDIA_STOP = 243, + KEY_MEDIA_FIND = 244, + KEY_MEDIA_SCROLLUP = 245, + KEY_MEDIA_SCROLLDOWN = 246, + KEY_MEDIA_EDIT = 247, + KEY_MEDIA_SLEEP = 248, + KEY_MEDIA_COFFEE = 249, + KEY_MEDIA_REFRESH = 250, + KEY_MEDIA_CALC = 251, + // /libraries/codal-core/inc/drivers/uf2format.h + UF2FORMAT_H = 1, + APP_START_ADDRESS = 8192, + UF2_FLAG_NOFLASH = 1, + // /libraries/codal-core/inc/streams/DataStream.h + DATASTREAM_MAXIMUM_BUFFERS = 1, + // /libraries/codal-core/inc/streams/LevelDetector.h + LEVEL_THRESHOLD_LOW = 1, + LEVEL_THRESHOLD_HIGH = 2, + LEVEL_DETECTOR_INITIALISED = 1, + LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED = 2, + LEVEL_DETECTOR_LOW_THRESHOLD_PASSED = 4, + LEVEL_DETECTOR_DEFAULT_WINDOW_SIZE = 128, + // /libraries/codal-core/inc/streams/LevelDetectorSPL.h + LEVEL_DETECTOR_SPL_INITIALISED = 1, + LEVEL_DETECTOR_SPL_HIGH_THRESHOLD_PASSED = 2, + LEVEL_DETECTOR_SPL_LOW_THRESHOLD_PASSED = 4, + LEVEL_DETECTOR_SPL_DEFAULT_WINDOW_SIZE = 128, + // /libraries/codal-core/inc/streams/MemorySource.h + MEMORY_SOURCE_MAX_BUFFER = 256, + // /libraries/codal-core/inc/streams/Synthesizer.h + SYNTHESIZER_SAMPLE_RATE = 44100, + TONE_WIDTH = 1024, + // /libraries/codal-core/inc/types/BitmapFont.h + BITMAP_FONT_WIDTH = 5, + BITMAP_FONT_HEIGHT = 5, + BITMAP_FONT_ASCII_START = 32, + BITMAP_FONT_ASCII_END = 126, + // /libraries/codal-core/inc/types/CoordinateSystem.h + COORDINATE_SPACE_ROTATED_0 = 0, + COORDINATE_SPACE_ROTATED_90 = 1, + COORDINATE_SPACE_ROTATED_180 = 2, + COORDINATE_SPACE_ROTATED_270 = 3, + RAW = 0, + SIMPLE_CARTESIAN = 1, + NORTH_EAST_DOWN = 2, + EAST_NORTH_UP = 3, + // /libraries/codal-core/inc/types/Event.h + DEVICE_ID_ANY = 0, + DEVICE_EVT_ANY = 0, + CREATE_ONLY = 0, + CREATE_AND_FIRE = 1, + DEVICE_EVENT_DEFAULT_LAUNCH_MODE = 1, + // /libraries/codal-microbit/inc/MicroBitDevice.h + MICROBIT_NAME_LENGTH = 5, + MICROBIT_NAME_CODE_LETTERS = 5, + // /libraries/codal-microbit/inc/MicroBitRadio.h + MICROBIT_RADIO_STATUS_INITIALISED = 1, + MICROBIT_RADIO_BASE_ADDRESS = 1969383796, + MICROBIT_RADIO_DEFAULT_GROUP = 0, + MICROBIT_RADIO_DEFAULT_TX_POWER = 7, + MICROBIT_RADIO_DEFAULT_FREQUENCY = 7, + MICROBIT_RADIO_MAX_PACKET_SIZE = 32, + MICROBIT_RADIO_HEADER_SIZE = 4, + MICROBIT_RADIO_MAXIMUM_RX_BUFFERS = 4, + MICROBIT_RADIO_POWER_LEVELS = 10, + MICROBIT_RADIO_PROTOCOL_DATAGRAM = 1, + MICROBIT_RADIO_PROTOCOL_EVENTBUS = 2, + MICROBIT_RADIO_EVT_DATAGRAM = 1, + // /libraries/codal-microbit/inc/MicroBitStorage.h + MICROBIT_STORAGE_MAGIC = 51966, + MICROBIT_STORAGE_BLOCK_SIZE = 48, + MICROBIT_STORAGE_KEY_SIZE = 16, + MICROBIT_STORAGE_STORE_PAGE_OFFSET = 17, + MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET = 19, + // /libraries/codal-microbit/inc/MicroBitThermometer.h + MICROBIT_THERMOMETER_PERIOD = 1000, + MICROBIT_THERMOMETER_EVT_UPDATE = 1, + // /libraries/codal-microbit/inc/bluetooth/ExternalEvents.h MICROBIT_ID_BLE = 1000, MICROBIT_ID_BLE_UART = 1200, MICROBIT_BLE_EVT_CONNECTED = 1, MICROBIT_BLE_EVT_DISCONNECTED = 2, - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MESEvents.h + // /libraries/codal-microbit/inc/bluetooth/MESEvents.h MES_REMOTE_CONTROL_ID = 1001, MES_REMOTE_CONTROL_EVT_PLAY = 1, MES_REMOTE_CONTROL_EVT_PAUSE = 2, @@ -70,575 +800,628 @@ declare const enum DAL { MES_DPAD_BUTTON_4_DOWN = 15, MES_DPAD_BUTTON_4_UP = 16, MES_BROADCAST_GENERAL_ID = 2000, - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitAccelerometerService.h - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitBLEManager.h - MICROBIT_BLE_PAIR_REQUEST = 0x01, - MICROBIT_BLE_PAIR_COMPLETE = 0x02, - MICROBIT_BLE_PAIR_PASSCODE = 0x04, - MICROBIT_BLE_PAIR_SUCCESSFUL = 0x08, + // /libraries/codal-microbit/inc/bluetooth/MicroBitBLEManager.h + MICROBIT_BLE_PAIR_REQUEST = 1, + MICROBIT_BLE_PAIR_COMPLETE = 2, + MICROBIT_BLE_PAIR_PASSCODE = 4, + MICROBIT_BLE_PAIR_SUCCESSFUL = 8, MICROBIT_BLE_PAIRING_TIMEOUT = 90, MICROBIT_BLE_POWER_LEVELS = 8, MICROBIT_BLE_MAXIMUM_BONDS = 4, MICROBIT_BLE_EDDYSTONE_ADV_INTERVAL = 400, - MICROBIT_BLE_EDDYSTONE_DEFAULT_POWER = 0xF0, - MICROBIT_BLE_STATUS_STORE_SYSATTR = 0x02, - MICROBIT_BLE_STATUS_DISCONNECT = 0x04, + MICROBIT_BLE_EDDYSTONE_DEFAULT_POWER = 240, + MICROBIT_BLE_STATUS_STORE_SYSATTR = 2, + MICROBIT_BLE_STATUS_DISCONNECT = 4, MICROBIT_BLE_DISCONNECT_AFTER_PAIRING_DELAY = 500, - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitButtonService.h - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitDFUService.h + // /libraries/codal-microbit/inc/bluetooth/MicroBitDFUService.h MICROBIT_DFU_OPCODE_START_DFU = 1, MICROBIT_DFU_HISTOGRAM_WIDTH = 5, MICROBIT_DFU_HISTOGRAM_HEIGHT = 5, - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitEddystone.h - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitEventService.h - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitIOPinService.h - MICROBIT_IO_PIN_SERVICE_PINCOUNT = 19, + // /libraries/codal-microbit/inc/bluetooth/MicroBitIOPinService.h + MICROBIT_IO_PIN_SERVICE_PINCOUNT = 20, MICROBIT_IO_PIN_SERVICE_DATA_SIZE = 10, MICROBIT_PWM_PIN_SERVICE_DATA_SIZE = 2, - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitLEDService.h + // /libraries/codal-microbit/inc/bluetooth/MicroBitLEDService.h MICROBIT_BLE_MAXIMUM_SCROLLTEXT = 20, - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitMagnetometerService.h - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitTemperatureService.h - // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitUARTService.h + // /libraries/codal-microbit/inc/bluetooth/MicroBitMagnetometerService.h + COMPASS_CALIBRATION_STATUS_UNKNOWN = 0, + COMPASS_CALIBRATION_REQUESTED = 1, + COMPASS_CALIBRATION_COMPLETED_OK = 2, + COMPASS_CALIBRATION_COMPLETED_ERR = 3, + // /libraries/codal-microbit/inc/bluetooth/MicroBitUARTService.h MICROBIT_UART_S_DEFAULT_BUF_SIZE = 20, MICROBIT_UART_S_EVT_DELIM_MATCH = 1, MICROBIT_UART_S_EVT_HEAD_MATCH = 2, MICROBIT_UART_S_EVT_RX_FULL = 3, - // built/yt/yotta_modules/microbit-dal/inc/core/ErrorNo.h - MICROBIT_OK = 0, - MICROBIT_INVALID_PARAMETER = -1001, - MICROBIT_NOT_SUPPORTED = -1002, - MICROBIT_CALIBRATION_IN_PROGRESS = -1003, - MICROBIT_CALIBRATION_REQUIRED = -1004, - MICROBIT_NO_RESOURCES = -1005, + // /libraries/codal-microbit/inc/compat/MicroBitCompat.h MICROBIT_BUSY = -1006, MICROBIT_CANCELLED = -1007, - MICROBIT_I2C_ERROR = -1010, - MICROBIT_SERIAL_IN_USE = -1011, - MICROBIT_NO_DATA = -1012, - MICROBIT_OOM = 20, + MICROBIT_CALIBRATION_IN_PROGRESS = -1003, + MICROBIT_CALIBRATION_REQUIRED = -1004, MICROBIT_HEAP_ERROR = 30, + MICROBIT_I2C_ERROR = -1010, + MICROBIT_INVALID_PARAMETER = -1001, + MICROBIT_NO_DATA = -1012, + MICROBIT_NO_RESOURCES = -1005, + MICROBIT_NOT_SUPPORTED = -1002, MICROBIT_NULL_DEREFERENCE = 40, - // built/yt/yotta_modules/microbit-dal/inc/core/EventModel.h - // built/yt/yotta_modules/microbit-dal/inc/core/MemberFunctionCallback.h - // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitCompat.h - // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitComponent.h - MICROBIT_ID_BUTTON_A = 1, - MICROBIT_ID_BUTTON_B = 2, - MICROBIT_ID_BUTTON_RESET = 3, - MICROBIT_ID_ACCELEROMETER = 4, - MICROBIT_ID_COMPASS = 5, - MICROBIT_ID_DISPLAY = 6, - MICROBIT_ID_IO_P0 = 7, - MICROBIT_ID_IO_P1 = 8, - MICROBIT_ID_IO_P2 = 9, - MICROBIT_ID_IO_P3 = 10, - MICROBIT_ID_IO_P4 = 11, - MICROBIT_ID_IO_P5 = 12, - MICROBIT_ID_IO_P6 = 13, - MICROBIT_ID_IO_P7 = 14, - MICROBIT_ID_IO_P8 = 15, - MICROBIT_ID_IO_P9 = 16, - MICROBIT_ID_IO_P10 = 17, - MICROBIT_ID_IO_P11 = 18, - MICROBIT_ID_IO_P12 = 19, - MICROBIT_ID_IO_P13 = 20, - MICROBIT_ID_IO_P14 = 21, - MICROBIT_ID_IO_P15 = 22, - MICROBIT_ID_IO_P16 = 23, - MICROBIT_ID_IO_P19 = 24, - MICROBIT_ID_IO_P20 = 25, - MICROBIT_ID_IO_P21 = 50, - MICROBIT_ID_BUTTON_AB = 26, - MICROBIT_ID_GESTURE = 27, - MICROBIT_ID_THERMOMETER = 28, - MICROBIT_ID_RADIO = 29, - MICROBIT_ID_RADIO_DATA_READY = 30, - MICROBIT_ID_MULTIBUTTON_ATTACH = 31, - MICROBIT_ID_SERIAL = 32, - MICROBIT_ID_MESSAGE_BUS_LISTENER = 1021, - MICROBIT_ID_NOTIFY_ONE = 1022, - MICROBIT_ID_NOTIFY = 1023, - MICROBIT_COMPONENT_RUNNING = 0x01, - // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitDevice.h - MICROBIT_NAME_LENGTH = 5, - MICROBIT_NAME_CODE_LETTERS = 5, - MICROBIT_PANIC_ERROR_CHARS = 4, - // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitFiber.h - MICROBIT_SCHEDULER_RUNNING = 0x01, - MICROBIT_FIBER_FLAG_FOB = 0x01, - MICROBIT_FIBER_FLAG_PARENT = 0x02, - MICROBIT_FIBER_FLAG_CHILD = 0x04, - MICROBIT_FIBER_FLAG_DO_NOT_PAGE = 0x08, - // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitFont.h - MICROBIT_FONT_WIDTH = 5, - MICROBIT_FONT_HEIGHT = 5, - MICROBIT_FONT_ASCII_START = 32, - MICROBIT_FONT_ASCII_END = 126, - // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitHeapAllocator.h - MICROBIT_MAXIMUM_HEAPS = 2, - MICROBIT_HEAP_BLOCK_FREE = 0x80000000, - // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitListener.h - MESSAGE_BUS_LISTENER_PARAMETERISED = 0x0001, - MESSAGE_BUS_LISTENER_METHOD = 0x0002, - MESSAGE_BUS_LISTENER_BUSY = 0x0004, - MESSAGE_BUS_LISTENER_REENTRANT = 0x0008, - MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY = 0x0010, - MESSAGE_BUS_LISTENER_DROP_IF_BUSY = 0x0020, - MESSAGE_BUS_LISTENER_NONBLOCKING = 0x0040, - MESSAGE_BUS_LISTENER_URGENT = 0x0080, - MESSAGE_BUS_LISTENER_DELETING = 0x8000, - // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitSystemTimer.h - // built/yt/yotta_modules/microbit-dal/inc/core/NotifyEvents.h - MICROBIT_DISPLAY_EVT_FREE = 1, - MICROBIT_SERIAL_EVT_TX_EMPTY = 2, - MICROBIT_UART_S_EVT_TX_EMPTY = 3, - // built/yt/yotta_modules/microbit-dal/inc/drivers/CalliopeRGB.h - RGB_LED_MAX_INTENSITY = 40, - // built/yt/yotta_modules/microbit-dal/inc/drivers/CalliopeSoundMotor.h - CALLIOPE_SM_DEFAULT_DUTY_M = 50, - CALLIOPE_SM_DEFAULT_DUTY_S = 100, - CALLIOPE_SM_DEFAULT_FREQUENCY_S = 4000, - CALLIOPE_SM_DEFAULT_SILENT_MODE = 1, - CALLIOPE_SM_PRESCALER_M = 2, - CALLIOPE_SM_PRESCALER_S = 0, - CALLIOPE_SM_PRESCALER_S_LF = 4, - CALLIOPE_SM_PERIOD_M = 100, - CALLIOPE_MIN_FREQUENCY_HZ_S_NP = 245, - CALLIOPE_MIN_FREQUENCY_HZ_S = 20, - CALLIOPE_MAX_FREQUENCY_HZ_S = 20000, - CALLIOPE_BOARD_FREQUENCY = 16000000, - // built/yt/yotta_modules/microbit-dal/inc/drivers/DynamicPwm.h - MICROBIT_DEFAULT_PWM_PERIOD = 20000, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitAccelerometer-bmx.h - BMX055_ACC_WHOAMI = 0x00, - BMX055_ACC_D_X_LSB = 0x02, - BMX055_ACC_D_X_MSB = 0x03, - BMX055_ACC_D_Y_LSB = 0x04, - BMX055_ACC_D_Y_MSB = 0x05, - BMX055_ACC_D_Z_LSB = 0x06, - BMX055_ACC_D_Z_MSB = 0x07, - BMX055_ACC_D_TEMP = 0x08, - BMX055_ACC_INT_STATUS_0 = 0x09, - BMX055_ACC_INT_STATUS_1 = 0x0A, - BMX055_ACC_INT_STATUS_2 = 0x0B, - BMX055_ACC_INT_STATUS_3 = 0x0C, - BMX055_ACC_FIFO_STATUS = 0x0E, - BMX055_ACC_PMU_RANGE = 0x0F, - BMX055_ACC_PMU_BW = 0x10, - BMX055_ACC_PMU_LPW = 0x11, - BMX055_ACC_PMU_LOW_POWER = 0x12, - BMX055_ACC_D_HBW = 0x13, - BMX055_ACC_BGW_SOFTRESET = 0x14, - BMX055_ACC_INT_EN_0 = 0x16, - BMX055_ACC_INT_EN_1 = 0x17, - BMX055_ACC_INT_EN_2 = 0x18, - BMX055_ACC_INT_MAP_0 = 0x19, - BMX055_ACC_INT_MAP_1 = 0x1A, - BMX055_ACC_INT_MAP_2 = 0x1B, - BMX055_ACC_INT_SRC = 0x1E, - BMX055_ACC_INT_OUT_CTRL = 0x20, - BMX055_ACC_INT_RST_LATCH = 0x21, - BMX055_ACC_INT_0 = 0x22, - BMX055_ACC_INT_1 = 0x23, - BMX055_ACC_INT_2 = 0x24, - BMX055_ACC_INT_3 = 0x25, - BMX055_ACC_INT_4 = 0x26, - BMX055_ACC_INT_5 = 0x27, - BMX055_ACC_INT_6 = 0x28, - BMX055_ACC_INT_7 = 0x29, - BMX055_ACC_INT_8 = 0x2A, - BMX055_ACC_INT_9 = 0x2B, - BMX055_ACC_INT_A = 0x2C, - BMX055_ACC_INT_B = 0x2D, - BMX055_ACC_INT_C = 0x2E, - BMX055_ACC_INT_D = 0x2F, - BMX055_ACC_FIFO_CONFIG_0 = 0x30, - BMX055_ACC_PMU_SELF_TEST = 0x32, - BMX055_ACC_TRIM_NVM_CTRL = 0x33, - BMX055_ACC_BGW_SPI3_WDT = 0x34, - BMX055_ACC_OFC_CTRL = 0x36, - BMX055_ACC_OFC_SETTING = 0x37, - BMX055_ACC_OFC_OFFSET_X = 0x38, - BMX055_ACC_OFC_OFFSET_Y = 0x39, - BMX055_ACC_OFC_OFFSET_Z = 0x3A, - BMX055_ACC_TRIM_GPO = 0x3B, - BMX055_ACC_TRIM_GP1 = 0x3C, - BMX055_ACC_FIFO_CONFIG_1 = 0x3E, - BMX055_ACC_FIFO_DATA = 0x3F, - BMX055_GYRO_WHOAMI = 0x00, - BMX055_GYRO_RATE_X_LSB = 0x02, - BMX055_GYRO_RATE_X_MSB = 0x03, - BMX055_GYRO_RATE_Y_LSB = 0x04, - BMX055_GYRO_RATE_Y_MSB = 0x05, - BMX055_GYRO_RATE_Z_LSB = 0x06, - BMX055_GYRO_RATE_Z_MSB = 0x07, - BMX055_GYRO_INT_STATUS_0 = 0x09, - BMX055_GYRO_INT_STATUS_1 = 0x0A, - BMX055_GYRO_INT_STATUS_2 = 0x0B, - BMX055_GYRO_INT_STATUS_3 = 0x0C, - BMX055_GYRO_FIFO_STATUS = 0x0E, - BMX055_GYRO_RANGE = 0x0F, - BMX055_GYRO_BW = 0x10, - BMX055_GYRO_LPM1 = 0x11, - BMX055_GYRO_LPM2 = 0x12, - BMX055_GYRO_RATE_HBW = 0x13, - BMX055_GYRO_BGW_SOFTRESET = 0x14, - BMX055_GYRO_INT_EN_0 = 0x15, - BMX055_GYRO_INT_EN_1 = 0x16, - BMX055_GYRO_INT_MAP_0 = 0x17, - BMX055_GYRO_INT_MAP_1 = 0x18, - BMX055_GYRO_INT_MAP_2 = 0x19, - BMX055_GYRO_INT_SRC_1 = 0x1A, - BMX055_GYRO_INT_SRC_2 = 0x1B, - BMX055_GYRO_INT_SRC_3 = 0x1C, - BMX055_GYRO_FIFO_EN = 0x1E, - BMX055_GYRO_INT_RST_LATCH = 0x21, - BMX055_GYRO_HIGH_TH_X = 0x22, - BMX055_GYRO_HIGH_DUR_X = 0x23, - BMX055_GYRO_HIGH_TH_Y = 0x24, - BMX055_GYRO_HIGH_DUR_Y = 0x25, - BMX055_GYRO_HIGH_TH_Z = 0x26, - BMX055_GYRO_HIGH_DUR_Z = 0x27, - BMX055_GYRO_SOC = 0x31, - BMX055_GYRO_A_FOC = 0x32, - BMX055_GYRO_TRIM_NVM_CTRL = 0x33, - BMX055_GYRO_BGW_SPI3_WDT = 0x34, - BMX055_GYRO_OFC1 = 0x36, - BMX055_GYRO_OFC2 = 0x37, - BMX055_GYRO_OFC3 = 0x38, - BMX055_GYRO_OFC4 = 0x39, - BMX055_GYRO_TRIM_GP0 = 0x3A, - BMX055_GYRO_TRIM_GP1 = 0x3B, - BMX055_GYRO_BIST = 0x3C, - BMX055_GYRO_FIFO_CONFIG_0 = 0x3D, - BMX055_GYRO_FIFO_CONFIG_1 = 0x3E, - BMX055_MAG_WHOAMI = 0x40, - BMX055_MAG_Reserved = 0x41, - BMX055_MAG_XOUT_LSB = 0x42, - BMX055_MAG_XOUT_MSB = 0x43, - BMX055_MAG_YOUT_LSB = 0x44, - BMX055_MAG_YOUT_MSB = 0x45, - BMX055_MAG_ZOUT_LSB = 0x46, - BMX055_MAG_ZOUT_MSB = 0x47, - BMX055_MAG_ROUT_LSB = 0x48, - BMX055_MAG_ROUT_MSB = 0x49, - BMX055_MAG_INT_STATUS = 0x4A, - BMX055_MAG_PWR_CNTL1 = 0x4B, - BMX055_MAG_PWR_CNTL2 = 0x4C, - BMX055_MAG_INT_EN_1 = 0x4D, - BMX055_MAG_INT_EN_2 = 0x4E, - BMX055_MAG_LOW_THS = 0x4F, - BMX055_MAG_HIGH_THS = 0x50, - BMX055_MAG_REP_XY = 0x51, - BMX055_MAG_REP_Z = 0x52, - BMM050_DIG_X1 = 0x5D, - BMM050_DIG_Y1 = 0x5E, - BMM050_DIG_Z4_LSB = 0x62, - BMM050_DIG_Z4_MSB = 0x63, - BMM050_DIG_X2 = 0x64, - BMM050_DIG_Y2 = 0x65, - BMM050_DIG_Z2_LSB = 0x68, - BMM050_DIG_Z2_MSB = 0x69, - BMM050_DIG_Z1_LSB = 0x6A, - BMM050_DIG_Z1_MSB = 0x6B, - BMM050_DIG_XYZ1_LSB = 0x6C, - BMM050_DIG_XYZ1_MSB = 0x6D, - BMM050_DIG_Z3_LSB = 0x6E, - BMM050_DIG_Z3_MSB = 0x6F, - BMM050_DIG_XY2 = 0x70, - BMM050_DIG_XY1 = 0x71, - BMX055_ACC_ADDRESS = 0x18, - BMX055_GYRO_ADDRESS = 0x68, - BMX055_MAG_ADDRESS = 0x10, - MS5637_ADDRESS = 0x76, - AFS_2G = 0x03, - AFS_4G = 0x05, - AFS_8G = 0x08, - AFS_16G = 0x0C, - ABW_8Hz = 0, - ABW_16Hz = 1, - ABW_31Hz = 2, - ABW_63Hz = 3, - ABW_125Hz = 4, - ABW_250Hz = 5, - ABW_500Hz = 6, - ABW_100Hz = 7, - GFS_2000DPS = 0, - GFS_1000DPS = 1, - GFS_500DPS = 2, - GFS_250DPS = 3, - GFS_125DPS = 4, - G_2000Hz523Hz = 0, - G_2000Hz230Hz = 1, - G_1000Hz116Hz = 2, - G_400Hz47Hz = 3, - G_200Hz23Hz = 4, - G_100Hz12Hz = 5, - G_200Hz64Hz = 6, - G_100Hz32Hz = 7, - MODR_10Hz = 0, - MODR_2Hz = 1, - MODR_6Hz = 2, - MODR_8Hz = 3, - MODR_15Hz = 4, - MODR_20Hz = 5, - MODR_25Hz = 6, - MODR_30Hz = 7, - lowPower = 0, - Regular = 1, - enhancedRegular = 2, - highAccuracy = 3, - ADC_256 = 0x00, - ADC_512 = 0x02, - ADC_1024 = 0x04, - ADC_2048 = 0x06, - ADC_4096 = 0x08, - ADC_8192 = 0x0A, - ADC_D1 = 0x40, - ADC_D2 = 0x50, - MICROBIT_ACCEL_PITCH_ROLL_VALID = 0x02, - MICROBIT_ACCEL_ADDED_TO_IDLE = 0x04, - MMA8653_STATUS = 0x00, - MMA8653_OUT_X_MSB = 0x01, - MMA8653_WHOAMI = 0x0D, - MMA8653_XYZ_DATA_CFG = 0x0E, - MMA8653_CTRL_REG1 = 0x2A, - MMA8653_CTRL_REG2 = 0x2B, - MMA8653_CTRL_REG3 = 0x2C, - MMA8653_CTRL_REG4 = 0x2D, - MMA8653_CTRL_REG5 = 0x2E, - MMA8653_WHOAMI_VAL = 0x5A, - MMA8653_SAMPLE_RANGES = 3, - MMA8653_SAMPLE_RATES = 8, - MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE = 1, - MICROBIT_ACCELEROMETER_EVT_NONE = 0, - MICROBIT_ACCELEROMETER_EVT_TILT_UP = 1, - MICROBIT_ACCELEROMETER_EVT_TILT_DOWN = 2, - MICROBIT_ACCELEROMETER_EVT_TILT_LEFT = 3, - MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT = 4, - MICROBIT_ACCELEROMETER_EVT_FACE_UP = 5, - MICROBIT_ACCELEROMETER_EVT_FACE_DOWN = 6, - MICROBIT_ACCELEROMETER_EVT_FREEFALL = 7, - // MICROBIT_ACCELEROMETER_EVT_2G = 8, - MICROBIT_ACCELEROMETER_EVT_3G = 8, - MICROBIT_ACCELEROMETER_EVT_6G = 9, - MICROBIT_ACCELEROMETER_EVT_8G = 10, - MICROBIT_ACCELEROMETER_EVT_SHAKE = 11, - MICROBIT_ACCELEROMETER_REST_TOLERANCE = 200, - MICROBIT_ACCELEROMETER_TILT_TOLERANCE = 200, - MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE = 400, - MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE = 400, - MICROBIT_ACCELEROMETER_2G_TOLERANCE = 2048, + MICROBIT_OK = 0, + MICROBIT_OOM = 20, + MICROBIT_SERIAL_IN_USE = -1011, MICROBIT_ACCELEROMETER_3G_TOLERANCE = 3072, MICROBIT_ACCELEROMETER_6G_TOLERANCE = 6144, MICROBIT_ACCELEROMETER_8G_TOLERANCE = 8192, + MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE = 400, MICROBIT_ACCELEROMETER_GESTURE_DAMPING = 5, + MICROBIT_ACCELEROMETER_REST_TOLERANCE = 200, + MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD = 4, MICROBIT_ACCELEROMETER_SHAKE_DAMPING = 10, MICROBIT_ACCELEROMETER_SHAKE_RTX = 30, - MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD = 4, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitAccelerometer.h - MMA8653_DEFAULT_ADDR = 0x3A, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitButton.h - MICROBIT_BUTTON_EVT_DOWN = 1, - MICROBIT_BUTTON_EVT_UP = 2, - MICROBIT_BUTTON_EVT_CLICK = 3, - MICROBIT_BUTTON_EVT_LONG_CLICK = 4, - MICROBIT_BUTTON_EVT_HOLD = 5, - MICROBIT_BUTTON_EVT_DOUBLE_CLICK = 6, - MICROBIT_BUTTON_LONG_CLICK_TIME = 1000, - MICROBIT_BUTTON_HOLD_TIME = 1500, - MICROBIT_BUTTON_STATE = 1, - MICROBIT_BUTTON_STATE_HOLD_TRIGGERED = 2, - MICROBIT_BUTTON_STATE_CLICK = 4, - MICROBIT_BUTTON_STATE_LONG_CLICK = 8, - MICROBIT_BUTTON_SIGMA_MIN = 0, - MICROBIT_BUTTON_SIGMA_MAX = 12, - MICROBIT_BUTTON_SIGMA_THRESH_HI = 8, - MICROBIT_BUTTON_SIGMA_THRESH_LO = 2, - MICROBIT_BUTTON_DOUBLE_CLICK_THRESH = 50, - MICROBIT_BUTTON_SIMPLE_EVENTS = 0, - MICROBIT_BUTTON_ALL_EVENTS = 1, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitCompass-bmx.h - MAG3110_DEFAULT_ADDR = 0x1D, - MAG_DR_STATUS = 0x00, - MAG_OUT_X_MSB = 0x01, - MAG_OUT_X_LSB = 0x02, - MAG_OUT_Y_MSB = 0x03, - MAG_OUT_Y_LSB = 0x04, - MAG_OUT_Z_MSB = 0x05, - MAG_OUT_Z_LSB = 0x06, - MAG_WHOAMI = 0x07, - MAG_SYSMOD = 0x08, - MAG_OFF_X_MSB = 0x09, - MAG_OFF_X_LSB = 0x0A, - MAG_OFF_Y_MSB = 0x0B, - MAG_OFF_Y_LSB = 0x0C, - MAG_OFF_Z_MSB = 0x0D, - MAG_OFF_Z_LSB = 0x0E, - MAG_DIE_TEMP = 0x0F, - MAG_CTRL_REG1 = 0x10, - MAG_CTRL_REG2 = 0x11, - MAG3110_SAMPLE_RATES = 11, - MICROBIT_COMPASS_EVT_CAL_REQUIRED = 1, - MICROBIT_COMPASS_EVT_CAL_START = 2, - MICROBIT_COMPASS_EVT_CAL_END = 3, - MICROBIT_COMPASS_EVT_DATA_UPDATE = 4, - MICROBIT_COMPASS_EVT_CONFIG_NEEDED = 5, - MICROBIT_COMPASS_EVT_CALIBRATE = 6, - MICROBIT_COMPASS_STATUS_CALIBRATED = 2, - MICROBIT_COMPASS_STATUS_CALIBRATING = 4, - MICROBIT_COMPASS_STATUS_ADDED_TO_IDLE = 8, - MAG3110_WHOAMI_VAL = 0xC4, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitCompass.h - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitCompassCalibrator.h - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitDisplay.h - MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE = 1, - MICROBIT_DISPLAY_EVT_LIGHT_SENSE = 2, + MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE = 400, + MICROBIT_ACCELEROMETER_TILT_TOLERANCE = 200, + MICROBIT_COMPONENT_RUNNING = 4096, + MICROBIT_DEFAULT_PRINT_SPEED = 400, + MICROBIT_DEFAULT_SCROLL_SPEED = 120, + MICROBIT_DEFAULT_SCROLL_STRIDE = -1, MICROBIT_DISPLAY_DEFAULT_AUTOCLEAR = 1, - MICROBIT_DISPLAY_SPACING = 1, + MICROBIT_DISPLAY_DEFAULT_BRIGHTNESS = 255, MICROBIT_DISPLAY_GREYSCALE_BIT_DEPTH = 8, - MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS = -255, - ANIMATION_MODE_NONE = 0, - ANIMATION_MODE_STOPPED = 1, - ANIMATION_MODE_SCROLL_TEXT = 2, - ANIMATION_MODE_PRINT_TEXT = 3, - ANIMATION_MODE_SCROLL_IMAGE = 4, - ANIMATION_MODE_ANIMATE_IMAGE = 5, - ANIMATION_MODE_ANIMATE_IMAGE_WITH_CLEAR = 6, - ANIMATION_MODE_PRINT_CHARACTER = 7, - DISPLAY_MODE_BLACK_AND_WHITE = 0, - DISPLAY_MODE_GREYSCALE = 1, - DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE = 2, + MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS = 255, + MICROBIT_DISPLAY_MINIMUM_BRIGHTNESS = 1, MICROBIT_DISPLAY_ROTATION_0 = 0, - MICROBIT_DISPLAY_ROTATION_90 = 1, MICROBIT_DISPLAY_ROTATION_180 = 2, MICROBIT_DISPLAY_ROTATION_270 = 3, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitFile.h - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitFileSystem.h - MBFS_FILENAME_LENGTH = 16, - MB_READ = 0x01, - MB_WRITE = 0x02, - MB_CREAT = 0x04, - MB_APPEND = 0x08, - MB_SEEK_SET = 0x01, - MB_SEEK_END = 0x02, - MB_SEEK_CUR = 0x04, - MBFS_STATUS_INITIALISED = 0x01, - MBFS_UNUSED = 0xFFFF, - MBFS_EOF = 0xEFFF, - MBFS_DELETED = 0x0000, - MBFS_DIRECTORY_ENTRY_FREE = 0x8000, - MBFS_DIRECTORY_ENTRY_VALID = 0x4000, - MBFS_DIRECTORY_ENTRY_DIRECTORY = 0x2000, - MBFS_DIRECTORY_ENTRY_NEW = 0xffff, - MBFS_DIRECTORY_ENTRY_DELETED = 0x0000, - MBFS_BLOCK_TYPE_FILE = 1, - MBFS_BLOCK_TYPE_DIRECTORY = 2, - MBFS_BLOCK_TYPE_FILETABLE = 3, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitFlash.h - PAGE_SIZE = 1024, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitI2C.h - MICROBIT_I2C_MAX_RETRIES = 9, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitIO.h - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitLightSensor.h - MICROBIT_LIGHT_SENSOR_CHAN_NUM = 3, - MICROBIT_LIGHT_SENSOR_AN_SET_TIME = 4000, - MICROBIT_LIGHT_SENSOR_TICK_PERIOD = 5, - MICROBIT_LIGHT_SENSOR_MAX_VALUE = 338, - MICROBIT_LIGHT_SENSOR_MIN_VALUE = 75, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitMatrixMaps.h - NO_CONN = 0, - MICROBIT_DISPLAY_WIDTH = 5, - MICROBIT_DISPLAY_HEIGHT = 5, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitMessageBus.h - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitMultiButton.h - MICROBIT_MULTI_BUTTON_STATE_1 = 0x01, - MICROBIT_MULTI_BUTTON_STATE_2 = 0x02, - MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_1 = 0x04, - MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_2 = 0x08, - MICROBIT_MULTI_BUTTON_SUPRESSED_1 = 0X10, - MICROBIT_MULTI_BUTTON_SUPRESSED_2 = 0x20, - MICROBIT_MULTI_BUTTON_ATTACHED = 0x40, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitPin.h - IO_STATUS_DIGITAL_IN = 0x01, - IO_STATUS_DIGITAL_OUT = 0x02, - IO_STATUS_ANALOG_IN = 0x04, - IO_STATUS_ANALOG_OUT = 0x08, - IO_STATUS_TOUCH_IN = 0x10, - IO_STATUS_EVENT_ON_EDGE = 0x20, - IO_STATUS_EVENT_PULSE_ON_EDGE = 0x40, - IO_STATUS_EVENTBUS_ENABLED = 0x80, - MICROBIT_PIN_MAX_OUTPUT = 1023, - MICROBIT_PIN_MAX_SERVO_RANGE = 180, - MICROBIT_PIN_DEFAULT_SERVO_RANGE = 2000, + MICROBIT_DISPLAY_ROTATION_90 = 1, + MICROBIT_EVENT_DEFAULT_LAUNCH_MODE = 1, + MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS = -255, + MICROBIT_FONT_ASCII_END = 126, + MICROBIT_FONT_ASCII_START = 32, + MICROBIT_FONT_HEIGHT = 5, + MICROBIT_FONT_WIDTH = 5, + MICROBIT_I2C_MAX_RETRIES = 1, MICROBIT_PIN_DEFAULT_SERVO_CENTER = 1500, + MICROBIT_PIN_DEFAULT_SERVO_RANGE = 2000, MICROBIT_PIN_EVENT_NONE = 0, - MICROBIT_PIN_EVENT_ON_EDGE = 1, - MICROBIT_PIN_EVENT_ON_PULSE = 2, - MICROBIT_PIN_EVENT_ON_TOUCH = 3, - MICROBIT_PIN_EVT_RISE = 2, + MICROBIT_PIN_EVENT_ON_EDGE = 2, + MICROBIT_PIN_EVENT_ON_PULSE = 3, + MICROBIT_PIN_EVENT_ON_TOUCH = 4, MICROBIT_PIN_EVT_FALL = 3, MICROBIT_PIN_EVT_PULSE_HI = 4, MICROBIT_PIN_EVT_PULSE_LO = 5, - PIN_CAPABILITY_DIGITAL_IN = 0x01, - PIN_CAPABILITY_DIGITAL_OUT = 0x02, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitQuadratureDecoder.h - QDEC_USE_SYSTEM_TICK = 0x01, - QDEC_USE_DEBOUNCE = 0x02, - QDEC_LED_ACTIVE_LOW = 0x04, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitRadio.h - MICROBIT_RADIO_STATUS_INITIALISED = 0x0001, - MICROBIT_RADIO_BASE_ADDRESS = 0x75626974, - MICROBIT_RADIO_DEFAULT_GROUP = 0, - MICROBIT_RADIO_DEFAULT_TX_POWER = 6, - MICROBIT_RADIO_DEFAULT_FREQUENCY = 7, - MICROBIT_RADIO_MAX_PACKET_SIZE = 32, - MICROBIT_RADIO_HEADER_SIZE = 4, - MICROBIT_RADIO_MAXIMUM_RX_BUFFERS = 4, - MICROBIT_RADIO_PROTOCOL_DATAGRAM = 1, - MICROBIT_RADIO_PROTOCOL_EVENTBUS = 2, - MICROBIT_RADIO_EVT_DATAGRAM = 1, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitRadioDatagram.h - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitRadioEvent.h - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitSerial.h - MICROBIT_SERIAL_DEFAULT_BAUD_RATE = 115200, - MICROBIT_SERIAL_DEFAULT_BUFFER_SIZE = 20, + MICROBIT_PIN_EVT_RISE = 2, + MICROBIT_PIN_MAX_OUTPUT = 1023, + MICROBIT_PIN_MAX_SERVO_RANGE = 180, + MICROBIT_UART_S_EVT_TX_EMPTY = 3, + MICROBIT_ACCELEROMETER_EVT_3G = 8, + MICROBIT_ACCELEROMETER_EVT_6G = 9, + MICROBIT_ACCELEROMETER_EVT_8G = 10, + MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE = 1, + MICROBIT_ACCELEROMETER_EVT_FACE_DOWN = 6, + MICROBIT_ACCELEROMETER_EVT_FACE_UP = 5, + MICROBIT_ACCELEROMETER_EVT_FREEFALL = 7, + MICROBIT_ACCELEROMETER_EVT_NONE = 0, + MICROBIT_ACCELEROMETER_EVT_SHAKE = 11, + MICROBIT_ACCELEROMETER_EVT_TILT_DOWN = 2, + MICROBIT_ACCELEROMETER_EVT_TILT_LEFT = 3, + MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT = 4, + MICROBIT_ACCELEROMETER_EVT_TILT_UP = 1, + MICROBIT_BUTTON_ALL_EVENTS = 1, + MICROBIT_BUTTON_SIMPLE_EVENTS = 0, + MICROBIT_BUTTON_EVT_CLICK = 3, + MICROBIT_BUTTON_EVT_DOUBLE_CLICK = 6, + MICROBIT_BUTTON_EVT_DOWN = 1, + MICROBIT_BUTTON_EVT_HOLD = 5, + MICROBIT_BUTTON_EVT_LONG_CLICK = 4, + MICROBIT_BUTTON_EVT_UP = 2, + MICROBIT_COMPASS_EVT_CALIBRATE = 3, + MICROBIT_COMPASS_EVT_CONFIG_NEEDED = 2, + MICROBIT_COMPASS_EVT_DATA_UPDATE = 1, + MICROBIT_COMPASS_EVT_CALIBRATION_NEEDED = 4, + MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE = 1, + MICROBIT_DISPLAY_EVT_FREE = 1, MICROBIT_SERIAL_EVT_DELIM_MATCH = 1, MICROBIT_SERIAL_EVT_HEAD_MATCH = 2, MICROBIT_SERIAL_EVT_RX_FULL = 3, - MICROBIT_SERIAL_RX_IN_USE = 1, - MICROBIT_SERIAL_TX_IN_USE = 2, - MICROBIT_SERIAL_RX_BUFF_INIT = 4, - MICROBIT_SERIAL_TX_BUFF_INIT = 8, - ASYNC = 0, - SYNC_SPINWAIT = 1, - SYNC_SLEEP = 2, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitStorage.h - MICROBIT_STORAGE_MAGIC = 0xCAFE, - MICROBIT_STORAGE_BLOCK_SIZE = 48, - MICROBIT_STORAGE_KEY_SIZE = 16, - MICROBIT_STORAGE_STORE_PAGE_OFFSET = 17, - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET = 19, - // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitThermometer.h - MICROBIT_THERMOMETER_PERIOD = 1000, - MICROBIT_THERMOMETER_EVT_UPDATE = 1, - MICROBIT_THERMOMETER_ADDED_TO_IDLE = 2, - // built/yt/yotta_modules/microbit-dal/inc/drivers/TimedInterruptIn.h - // built/yt/yotta_modules/microbit-dal/inc/platform/yotta_cfg_mappings.h - // built/yt/yotta_modules/microbit-dal/inc/types/ManagedString.h - // built/yt/yotta_modules/microbit-dal/inc/types/ManagedType.h - // built/yt/yotta_modules/microbit-dal/inc/types/Matrix4.h - // built/yt/yotta_modules/microbit-dal/inc/types/MicroBitCoordinateSystem.h - RAW = 0, - SIMPLE_CARTESIAN = 1, - NORTH_EAST_DOWN = 2, - // built/yt/yotta_modules/microbit-dal/inc/types/MicroBitEvent.h + MICROBIT_SERIAL_EVT_TX_EMPTY = 2, MICROBIT_ID_ANY = 0, MICROBIT_EVT_ANY = 0, - CREATE_ONLY = 0, - CREATE_AND_FIRE = 1, - // built/yt/yotta_modules/microbit-dal/inc/types/MicroBitImage.h - // built/yt/yotta_modules/microbit-dal/inc/types/PacketBuffer.h - // built/yt/yotta_modules/microbit-dal/inc/types/RefCounted.h -} \ No newline at end of file + MICROBIT_ID_ACCELEROMETER = 5, + MICROBIT_ID_BUTTON_A = 1, + MICROBIT_ID_BUTTON_B = 2, + MICROBIT_ID_BUTTON_AB = 3, + MICROBIT_ID_BUTTON_RESET = 4, + MICROBIT_ID_COMPASS = 6, + MICROBIT_ID_DISPLAY = 7, + MICROBIT_ID_GESTURE = 13, + MICROBIT_ID_IO_P0 = 100, + MICROBIT_ID_IO_P1 = 101, + MICROBIT_ID_IO_P2 = 102, + MICROBIT_ID_IO_P3 = 103, + MICROBIT_ID_IO_P4 = 104, + MICROBIT_ID_IO_P5 = 105, + MICROBIT_ID_IO_P6 = 106, + MICROBIT_ID_IO_P7 = 107, + MICROBIT_ID_IO_P8 = 108, + MICROBIT_ID_IO_P9 = 109, + MICROBIT_ID_IO_P10 = 110, + MICROBIT_ID_IO_P11 = 111, + MICROBIT_ID_IO_P12 = 112, + MICROBIT_ID_IO_P13 = 113, + MICROBIT_ID_IO_P14 = 114, + MICROBIT_ID_IO_P15 = 115, + MICROBIT_ID_IO_P16 = 116, + MICROBIT_ID_IO_P19 = 119, + MICROBIT_ID_IO_P20 = 120, + MICROBIT_ID_IO_P21 = 121, + MICROBIT_ID_MESSAGE_BUS_LISTENER = 1021, + MICROBIT_ID_MULTIBUTTON_ATTACH = 11, + MICROBIT_ID_NOTIFY = 1023, + MICROBIT_ID_NOTIFY_ONE = 1022, + MICROBIT_ID_RADIO = 9, + MICROBIT_ID_RADIO_DATA_READY = 10, + MICROBIT_ID_SERIAL = 12, + MICROBIT_ID_THERMOMETER = 8, + MICROBIT_NESTED_HEAP_SIZE = 0, + MICROBIT_SCHEDULER_RUNNING = 1, + MICROBIT_SERIAL_DEFAULT_BAUD_RATE = 115200, + MICROBIT_SERIAL_DEFAULT_BUFFER_SIZE = 20, + MICROBIT_COMPASS_STATUS_ADDED_TO_IDLE = 8, + // /libraries/codal-microbit/model/MicroBit.h + DEVICE_INITIALIZED = 1, + // /libraries/codal-microbit/model/MicroBitCompass.h + //CALLIOPE_PIN_ACCEL_INT = 21, + // /libraries/codal-microbit/model/MicroBitIO.h + MICROBIT_PIN_BUTTON_RESET = -1, + ID_PIN_P0 = 100, + ID_PIN_P1 = 101, + ID_PIN_P2 = 102, + ID_PIN_P3 = 103, + ID_PIN_P4 = 104, + ID_PIN_P5 = 105, + ID_PIN_P6 = 106, + ID_PIN_P7 = 107, + ID_PIN_P8 = 108, + ID_PIN_P9 = 109, + ID_PIN_P10 = 110, + ID_PIN_P11 = 111, + ID_PIN_P12 = 112, + ID_PIN_P13 = 113, + ID_PIN_P14 = 114, + ID_PIN_P15 = 115, + ID_PIN_P16 = 116, + ID_PIN_P17 = 117, + ID_PIN_P18 = 118, + ID_PIN_P19 = 119, + ID_PIN_P20 = 120, + ID_PIN_P21 = 121, + ID_PIN_P22 = 122, + ID_PIN_P23 = 123, + ID_PIN_P24 = 124, + ID_PIN_P25 = 125, + ID_PIN_P26 = 126, + ID_PIN_P27 = 127, + ID_PIN_P28 = 128, + ID_PIN_P29 = 129, + ID_PIN_P30 = 130, + ID_PIN_P31 = 131, + ID_PIN_P32 = 132, + ID_PIN_P33 = 133, + ID_PIN_P34 = 134, + ID_PIN_P35 = 135, + ID_PIN_P36 = 136, + ID_PIN_P37 = 137, + ID_PIN_P38 = 138, + ID_PIN_P39 = 139, + ID_PIN_P40 = 140, + ID_PIN_P41 = 141, + ID_PIN_P42 = 142, + ID_PIN_P43 = 143, + ID_PIN_P44 = 144, + ID_PIN_P45 = 145, + ID_PIN_P46 = 146, + ID_PIN_P47 = 147, + // /pxtapp/configkeys.h + CFG_PIN_NAME_MSK = 65535, + CFG_PIN_CONFIG_MSK = 4294901760, + CFG_PIN_CONFIG_ACTIVE_LO = 65536, + CFG_MAGIC0 = 513675505, + CFG_MAGIC1 = 539130489, + CFG_PIN_ACCELEROMETER_INT = 1, + CFG_PIN_ACCELEROMETER_SCL = 2, + CFG_PIN_ACCELEROMETER_SDA = 3, + CFG_PIN_BTN_A = 4, + CFG_PIN_BTN_B = 5, + CFG_PIN_BTN_SLIDE = 6, + CFG_PIN_DOTSTAR_CLOCK = 7, + CFG_PIN_DOTSTAR_DATA = 8, + CFG_PIN_FLASH_CS = 9, + CFG_PIN_FLASH_MISO = 10, + CFG_PIN_FLASH_MOSI = 11, + CFG_PIN_FLASH_SCK = 12, + CFG_PIN_LED = 13, + CFG_PIN_LIGHT = 14, + CFG_PIN_MICROPHONE = 15, + CFG_PIN_MIC_CLOCK = 16, + CFG_PIN_MIC_DATA = 17, + CFG_PIN_MISO = 18, + CFG_PIN_MOSI = 19, + CFG_PIN_NEOPIXEL = 20, + CFG_PIN_RX = 21, + CFG_PIN_RXLED = 22, + CFG_PIN_SCK = 23, + CFG_PIN_SCL = 24, + CFG_PIN_SDA = 25, + CFG_PIN_SPEAKER_AMP = 26, + CFG_PIN_TEMPERATURE = 27, + CFG_PIN_TX = 28, + CFG_PIN_TXLED = 29, + CFG_PIN_IR_OUT = 30, + CFG_PIN_IR_IN = 31, + CFG_PIN_DISPLAY_SCK = 32, + CFG_PIN_DISPLAY_MISO = 33, + CFG_PIN_DISPLAY_MOSI = 34, + CFG_PIN_DISPLAY_CS = 35, + CFG_PIN_DISPLAY_DC = 36, + CFG_DISPLAY_WIDTH = 37, + CFG_DISPLAY_HEIGHT = 38, + CFG_DISPLAY_CFG0 = 39, + CFG_DISPLAY_CFG1 = 40, + CFG_DISPLAY_CFG2 = 41, + CFG_DISPLAY_CFG3 = 42, + CFG_PIN_DISPLAY_RST = 43, + CFG_PIN_DISPLAY_BL = 44, + CFG_PIN_SERVO_1 = 45, + CFG_PIN_SERVO_2 = 46, + CFG_PIN_BTN_LEFT = 47, + CFG_PIN_BTN_RIGHT = 48, + CFG_PIN_BTN_UP = 49, + CFG_PIN_BTN_DOWN = 50, + CFG_PIN_BTN_MENU = 51, + CFG_PIN_LED_R = 52, + CFG_PIN_LED_G = 53, + CFG_PIN_LED_B = 54, + CFG_PIN_LED1 = 55, + CFG_PIN_LED2 = 56, + CFG_PIN_LED3 = 57, + CFG_PIN_LED4 = 58, + CFG_SPEAKER_VOLUME = 59, + CFG_PIN_JACK_TX = 60, + CFG_PIN_JACK_SENSE = 61, + CFG_PIN_JACK_HPEN = 62, + CFG_PIN_JACK_BZEN = 63, + CFG_PIN_JACK_PWREN = 64, + CFG_PIN_JACK_SND = 65, + CFG_PIN_JACK_BUSLED = 66, + CFG_PIN_JACK_COMMLED = 67, + CFG_PIN_BTN_SOFT_RESET = 69, + CFG_ACCELEROMETER_TYPE = 70, + CFG_PIN_BTNMX_LATCH = 71, + CFG_PIN_BTNMX_CLOCK = 72, + CFG_PIN_BTNMX_DATA = 73, + CFG_PIN_BTN_MENU2 = 74, + CFG_PIN_BATTSENSE = 75, + CFG_PIN_VIBRATION = 76, + CFG_PIN_PWREN = 77, + CFG_DISPLAY_TYPE = 78, + CFG_PIN_ROTARY_ENCODER_A = 79, + CFG_PIN_ROTARY_ENCODER_B = 80, + CFG_ACCELEROMETER_SPACE = 81, + CFG_PIN_WIFI_MOSI = 82, + CFG_PIN_WIFI_MISO = 83, + CFG_PIN_WIFI_SCK = 84, + CFG_PIN_WIFI_TX = 85, + CFG_PIN_WIFI_RX = 86, + CFG_PIN_WIFI_CS = 87, + CFG_PIN_WIFI_BUSY = 88, + CFG_PIN_WIFI_RESET = 89, + CFG_PIN_WIFI_GPIO0 = 90, + CFG_PIN_WIFI_AT_TX = 91, + CFG_PIN_WIFI_AT_RX = 92, + CFG_PIN_USB_POWER = 93, + ACCELEROMETER_TYPE_LIS3DH = 50, + ACCELEROMETER_TYPE_LIS3DH_ALT = 48, + ACCELEROMETER_TYPE_MMA8453 = 56, + ACCELEROMETER_TYPE_FXOS8700 = 60, + ACCELEROMETER_TYPE_MMA8653 = 58, + ACCELEROMETER_TYPE_MSA300 = 76, + ACCELEROMETER_TYPE_MPU6050 = 104, + DISPLAY_TYPE_ST7735 = 7735, + DISPLAY_TYPE_ILI9341 = 9341, + DISPLAY_TYPE_SMART = 4242, + CFG_PIN_A0 = 100, + CFG_PIN_A1 = 101, + CFG_PIN_A2 = 102, + CFG_PIN_A3 = 103, + CFG_PIN_A4 = 104, + CFG_PIN_A5 = 105, + CFG_PIN_A6 = 106, + CFG_PIN_A7 = 107, + CFG_PIN_A8 = 108, + CFG_PIN_A9 = 109, + CFG_PIN_A10 = 110, + CFG_PIN_A11 = 111, + CFG_PIN_A12 = 112, + CFG_PIN_A13 = 113, + CFG_PIN_A14 = 114, + CFG_PIN_A15 = 115, + CFG_PIN_A16 = 116, + CFG_PIN_A17 = 117, + CFG_PIN_A18 = 118, + CFG_PIN_A19 = 119, + CFG_PIN_A20 = 120, + CFG_PIN_A21 = 121, + CFG_PIN_A22 = 122, + CFG_PIN_A23 = 123, + CFG_PIN_A24 = 124, + CFG_PIN_A25 = 125, + CFG_PIN_A26 = 126, + CFG_PIN_A27 = 127, + CFG_PIN_A28 = 128, + CFG_PIN_A29 = 129, + CFG_PIN_A30 = 130, + CFG_PIN_A31 = 131, + CFG_PIN_D0 = 150, + CFG_PIN_D1 = 151, + CFG_PIN_D2 = 152, + CFG_PIN_D3 = 153, + CFG_PIN_D4 = 154, + CFG_PIN_D5 = 155, + CFG_PIN_D6 = 156, + CFG_PIN_D7 = 157, + CFG_PIN_D8 = 158, + CFG_PIN_D9 = 159, + CFG_PIN_D10 = 160, + CFG_PIN_D11 = 161, + CFG_PIN_D12 = 162, + CFG_PIN_D13 = 163, + CFG_PIN_D14 = 164, + CFG_PIN_D15 = 165, + CFG_PIN_D16 = 166, + CFG_PIN_D17 = 167, + CFG_PIN_D18 = 168, + CFG_PIN_D19 = 169, + CFG_PIN_D20 = 170, + CFG_PIN_D21 = 171, + CFG_PIN_D22 = 172, + CFG_PIN_D23 = 173, + CFG_PIN_D24 = 174, + CFG_PIN_D25 = 175, + CFG_PIN_D26 = 176, + CFG_PIN_D27 = 177, + CFG_PIN_D28 = 178, + CFG_PIN_D29 = 179, + CFG_PIN_D30 = 180, + CFG_PIN_D31 = 181, + CFG_NUM_NEOPIXELS = 200, + CFG_NUM_DOTSTARS = 201, + CFG_DEFAULT_BUTTON_MODE = 202, + CFG_SWD_ENABLED = 203, + CFG_FLASH_BYTES = 204, + CFG_RAM_BYTES = 205, + CFG_SYSTEM_HEAP_BYTES = 206, + CFG_LOW_MEM_SIMULATION_KB = 207, + CFG_BOOTLOADER_BOARD_ID = 208, + CFG_UF2_FAMILY = 209, + CFG_PINS_PORT_SIZE = 210, + CFG_BOOTLOADER_PROTECTION = 211, + CFG_POWER_DEEPSLEEP_TIMEOUT = 212, + CFG_ANALOG_BUTTON_THRESHOLD = 213, + CFG_CPU_MHZ = 214, + CFG_CONTROLLER_LIGHT_MAX_BRIGHTNESS = 215, + CFG_ANALOG_JOYSTICK_MIN = 216, + CFG_ANALOG_JOYSTICK_MAX = 217, + CFG_TIMERS_TO_USE = 218, + CFG_PIN_ONBOARD_DOTSTAR_CLOCK = 219, + CFG_PIN_ONBOARD_DOTSTAR_DATA = 220, + CFG_NUM_ONBOARD_DOTSTARS = 221, + CFG_PIN_ONBOARD_NEOPIXEL = 222, + CFG_NUM_ONBOARD_NEOPIXELS = 223, + CFG_MATRIX_KEYPAD_MESSAGE_ID = 239, + CFG_NUM_MATRIX_KEYPAD_ROWS = 240, + CFG_PIN_MATRIX_KEYPAD_ROW0 = 241, + CFG_PIN_MATRIX_KEYPAD_ROW1 = 242, + CFG_PIN_MATRIX_KEYPAD_ROW2 = 243, + CFG_PIN_MATRIX_KEYPAD_ROW3 = 244, + CFG_PIN_MATRIX_KEYPAD_ROW4 = 245, + CFG_PIN_MATRIX_KEYPAD_ROW5 = 246, + CFG_PIN_MATRIX_KEYPAD_ROW6 = 247, + CFG_PIN_MATRIX_KEYPAD_ROW7 = 248, + CFG_NUM_MATRIX_KEYPAD_COLS = 250, + CFG_PIN_MATRIX_KEYPAD_COL0 = 251, + CFG_PIN_MATRIX_KEYPAD_COL1 = 252, + CFG_PIN_MATRIX_KEYPAD_COL2 = 253, + CFG_PIN_MATRIX_KEYPAD_COL3 = 254, + CFG_PIN_MATRIX_KEYPAD_COL4 = 255, + CFG_PIN_MATRIX_KEYPAD_COL5 = 256, + CFG_PIN_MATRIX_KEYPAD_COL6 = 257, + CFG_PIN_MATRIX_KEYPAD_COL7 = 258, + CFG_PIN_B0 = 300, + CFG_PIN_B1 = 301, + CFG_PIN_B2 = 302, + CFG_PIN_B3 = 303, + CFG_PIN_B4 = 304, + CFG_PIN_B5 = 305, + CFG_PIN_B6 = 306, + CFG_PIN_B7 = 307, + CFG_PIN_B8 = 308, + CFG_PIN_B9 = 309, + CFG_PIN_B10 = 310, + CFG_PIN_B11 = 311, + CFG_PIN_B12 = 312, + CFG_PIN_B13 = 313, + CFG_PIN_B14 = 314, + CFG_PIN_B15 = 315, + CFG_PIN_B16 = 316, + CFG_PIN_B17 = 317, + CFG_PIN_B18 = 318, + CFG_PIN_B19 = 319, + CFG_PIN_B20 = 320, + CFG_PIN_B21 = 321, + CFG_PIN_B22 = 322, + CFG_PIN_B23 = 323, + CFG_PIN_B24 = 324, + CFG_PIN_B25 = 325, + CFG_PIN_B26 = 326, + CFG_PIN_B27 = 327, + CFG_PIN_B28 = 328, + CFG_PIN_B29 = 329, + CFG_PIN_B30 = 330, + CFG_PIN_B31 = 331, + CFG_PIN_C0 = 350, + CFG_PIN_C1 = 351, + CFG_PIN_C2 = 352, + CFG_PIN_C3 = 353, + CFG_PIN_C4 = 354, + CFG_PIN_C5 = 355, + CFG_PIN_C6 = 356, + CFG_PIN_C7 = 357, + CFG_PIN_C8 = 358, + CFG_PIN_C9 = 359, + CFG_PIN_C10 = 360, + CFG_PIN_C11 = 361, + CFG_PIN_C12 = 362, + CFG_PIN_C13 = 363, + CFG_PIN_C14 = 364, + CFG_PIN_C15 = 365, + CFG_PIN_C16 = 366, + CFG_PIN_C17 = 367, + CFG_PIN_C18 = 368, + CFG_PIN_C19 = 369, + CFG_PIN_C20 = 370, + CFG_PIN_C21 = 371, + CFG_PIN_C22 = 372, + CFG_PIN_C23 = 373, + CFG_PIN_C24 = 374, + CFG_PIN_C25 = 375, + CFG_PIN_C26 = 376, + CFG_PIN_C27 = 377, + CFG_PIN_C28 = 378, + CFG_PIN_C29 = 379, + CFG_PIN_C30 = 380, + CFG_PIN_C31 = 381, + CFG_PIN_P0 = 400, + CFG_PIN_P1 = 401, + CFG_PIN_P2 = 402, + CFG_PIN_P3 = 403, + CFG_PIN_P4 = 404, + CFG_PIN_P5 = 405, + CFG_PIN_P6 = 406, + CFG_PIN_P7 = 407, + CFG_PIN_P8 = 408, + CFG_PIN_P9 = 409, + CFG_PIN_P10 = 410, + CFG_PIN_P11 = 411, + CFG_PIN_P12 = 412, + CFG_PIN_P13 = 413, + CFG_PIN_P14 = 414, + CFG_PIN_P15 = 415, + CFG_PIN_P16 = 416, + CFG_PIN_P17 = 417, + CFG_PIN_P18 = 418, + CFG_PIN_P19 = 419, + CFG_PIN_P20 = 420, + CFG_PIN_P21 = 421, + CFG_PIN_P22 = 422, + CFG_PIN_P23 = 423, + CFG_PIN_P24 = 424, + CFG_PIN_P25 = 425, + CFG_PIN_P26 = 426, + CFG_PIN_P27 = 427, + CFG_PIN_P28 = 428, + CFG_PIN_P29 = 429, + CFG_PIN_P30 = 430, + CFG_PIN_P31 = 431, + CFG_PIN_LORA_MISO = 1001, + CFG_PIN_LORA_MOSI = 1002, + CFG_PIN_LORA_SCK = 1003, + CFG_PIN_LORA_CS = 1004, + CFG_PIN_LORA_BOOT = 1005, + CFG_PIN_LORA_RESET = 1006, + CFG_PIN_IRRXLED = 1007, + CFG_PIN_IRTXLED = 1008, + CFG_PIN_LCD_RESET = 1009, + CFG_PIN_LCD_ENABLE = 1010, + CFG_PIN_LCD_DATALINE4 = 1011, + CFG_PIN_LCD_DATALINE5 = 1012, + CFG_PIN_LCD_DATALINE6 = 1013, + CFG_PIN_LCD_DATALINE7 = 1014, + CFG_NUM_LCD_COLUMNS = 1015, + CFG_NUM_LCD_ROWS = 1016, + CFG_PIN_RCC0 = 1017, + CFG_PIN_RCC1 = 1018, + CFG_PIN_RCC2 = 1019, + CFG_PIN_RCC3 = 1020, + CFG_PIN_RCC4 = 1021, + CFG_PIN_RCC5 = 1022, + CFG_PIN_RCC6 = 1023, + CFG_PIN_RCC7 = 1024, + CFG_PIN_SERVO0 = 1025, + CFG_PIN_SERVO1 = 1026, + CFG_PIN_SERVO2 = 1027, + CFG_PIN_SERVO3 = 1028, + CFG_PIN_SERVO4 = 1029, + CFG_PIN_SERVO5 = 1030, + CFG_PIN_SERVO6 = 1031, + CFG_PIN_SERVO7 = 1032, + CFG_PIN_SERVO8 = 1033, + CFG_PIN_PI_TX = 1034, + CFG_PIN_PI_RX = 1035, + CFG_PIN_GPS_SDA = 1036, + CFG_PIN_GPS_SCL = 1037, + CFG_PIN_GPS_TX = 1038, + CFG_PIN_GPS_RX = 1039, + CFG_PIN_GROVE0 = 1040, + CFG_PIN_GROVE1 = 1041, + CFG_PIN_SS = 1042, + // /pxtapp/platform.h + PXT_MICROBIT_TAGGED_INT = 1, + PXT_POWI = 1, + // /pxtapp/pxtbase.h + PXT_UTF8 = 0, + PXT32 = 1, + PXT64 = 1, + PXT_REFCNT_FLASH = 65534, + VTABLE_MAGIC = 249, + Undefined = 0, + Boolean = 1, + Number = 2, + String = 3, + Object = 4, + Function = 5, + BoxedString = 1, + BoxedNumber = 2, + BoxedBuffer = 3, + RefAction = 4, + RefImage = 5, + RefCollection = 6, + RefRefLocal = 7, + RefMap = 8, + RefMImage = 9, + MMap = 10, + User0 = 16, + PXT_IOS_HEAP_ALLOC_BITS = 20, + IMAGE_HEADER_MAGIC = 135, + Int8LE = 1, + UInt8LE = 2, + Int16LE = 3, + UInt16LE = 4, + Int32LE = 5, + Int8BE = 6, + UInt8BE = 7, + Int16BE = 8, + UInt16BE = 9, + Int32BE = 10, + UInt32LE = 11, + UInt32BE = 12, + Float32LE = 13, + Float64LE = 14, + Float32BE = 15, + Float64BE = 16, + NUM_TRY_FRAME_REGS = 3, + GC = 0, + // /pxtapp/pxtcore.h + GC_MAX_ALLOC_SIZE = 9000, + GC_BLOCK_SIZE = 256, + NON_GC_HEAP_RESERVATION = 1024, +} +// \ No newline at end of file diff --git a/libs/core/enums.d.ts b/libs/core/enums.d.ts index 34620484..089ea4e8 100644 --- a/libs/core/enums.d.ts +++ b/libs/core/enums.d.ts @@ -35,7 +35,7 @@ declare namespace basic { A = 1, // MICROBIT_ID_BUTTON_A B = 2, // MICROBIT_ID_BUTTON_B //% block="A+B" - AB = 26, // MICROBIT_ID_BUTTON_AB + AB = 3, // MICROBIT_ID_BUTTON_AB } @@ -60,10 +60,10 @@ declare namespace basic { declare const enum TouchPin { - P0 = 19, // MICROBIT_ID_IO_P12 - P1 = 7, // MICROBIT_ID_IO_P0 - P2 = 8, // MICROBIT_ID_IO_P1 - P3 = 23, // MICROBIT_ID_IO_P16 + P0 = 112, // MICROBIT_ID_IO_P12 + P1 = 100, // MICROBIT_ID_IO_P0 + P2 = 101, // MICROBIT_ID_IO_P1 + P3 = 116, // MICROBIT_ID_IO_P16 } @@ -221,51 +221,51 @@ declare namespace input { //% blockIdentity="control.eventSourceId" MICROBIT_ID_BUTTON_B = 2, // MICROBIT_ID_BUTTON_B //% blockIdentity="control.eventSourceId" - MICROBIT_ID_BUTTON_AB = 26, // MICROBIT_ID_BUTTON_AB + MICROBIT_ID_BUTTON_AB = 3, // MICROBIT_ID_BUTTON_AB //% blockIdentity="control.eventSourceId" - MICROBIT_ID_RADIO = 29, // MICROBIT_ID_RADIO + MICROBIT_ID_RADIO = 9, // MICROBIT_ID_RADIO //% blockIdentity="control.eventSourceId" - MICROBIT_ID_GESTURE = 27, // MICROBIT_ID_GESTURE + MICROBIT_ID_GESTURE = 13, // MICROBIT_ID_GESTURE //% blockIdentity="control.eventSourceId" - MICROBIT_ID_ACCELEROMETER = 4, // MICROBIT_ID_ACCELEROMETER + MICROBIT_ID_ACCELEROMETER = 5, // MICROBIT_ID_ACCELEROMETER //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P0 = 7, // MICROBIT_ID_IO_P0 + MICROBIT_ID_IO_P0 = 100, // MICROBIT_ID_IO_P0 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P1 = 8, // MICROBIT_ID_IO_P1 + MICROBIT_ID_IO_P1 = 101, // MICROBIT_ID_IO_P1 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P2 = 9, // MICROBIT_ID_IO_P2 + MICROBIT_ID_IO_P2 = 102, // MICROBIT_ID_IO_P2 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P3 = 10, // MICROBIT_ID_IO_P3 + MICROBIT_ID_IO_P3 = 103, // MICROBIT_ID_IO_P3 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P4 = 11, // MICROBIT_ID_IO_P4 + MICROBIT_ID_IO_P4 = 104, // MICROBIT_ID_IO_P4 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P5 = 12, // MICROBIT_ID_IO_P5 + MICROBIT_ID_IO_P5 = 105, // MICROBIT_ID_IO_P5 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P6 = 13, // MICROBIT_ID_IO_P6 + MICROBIT_ID_IO_P6 = 106, // MICROBIT_ID_IO_P6 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P7 = 14, // MICROBIT_ID_IO_P7 + MICROBIT_ID_IO_P7 = 107, // MICROBIT_ID_IO_P7 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P8 = 15, // MICROBIT_ID_IO_P8 + MICROBIT_ID_IO_P8 = 108, // MICROBIT_ID_IO_P8 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P9 = 16, // MICROBIT_ID_IO_P9 + MICROBIT_ID_IO_P9 = 109, // MICROBIT_ID_IO_P9 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P10 = 17, // MICROBIT_ID_IO_P10 + MICROBIT_ID_IO_P10 = 110, // MICROBIT_ID_IO_P10 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P11 = 18, // MICROBIT_ID_IO_P11 + MICROBIT_ID_IO_P11 = 111, // MICROBIT_ID_IO_P11 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P12 = 19, // MICROBIT_ID_IO_P12 + MICROBIT_ID_IO_P12 = 112, // MICROBIT_ID_IO_P12 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P13 = 20, // MICROBIT_ID_IO_P13 + MICROBIT_ID_IO_P13 = 113, // MICROBIT_ID_IO_P13 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P14 = 21, // MICROBIT_ID_IO_P14 + MICROBIT_ID_IO_P14 = 114, // MICROBIT_ID_IO_P14 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P15 = 22, // MICROBIT_ID_IO_P15 + MICROBIT_ID_IO_P15 = 115, // MICROBIT_ID_IO_P15 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P16 = 23, // MICROBIT_ID_IO_P16 + MICROBIT_ID_IO_P16 = 116, // MICROBIT_ID_IO_P16 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P19 = 24, // MICROBIT_ID_IO_P19 + MICROBIT_ID_IO_P19 = 119, // MICROBIT_ID_IO_P19 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P20 = 25, // MICROBIT_ID_IO_P20 + MICROBIT_ID_IO_P20 = 120, // MICROBIT_ID_IO_P20 //% blockIdentity="control.eventSourceId" MES_DEVICE_INFO_ID = 1103, // MES_DEVICE_INFO_ID //% blockIdentity="control.eventSourceId" @@ -405,11 +405,11 @@ declare namespace input { declare const enum EventFlags { //% - QueueIfBusy = 0x0010, // MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY + QueueIfBusy = 16, // MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY //% - DropIfBusy = 0x0020, // MESSAGE_BUS_LISTENER_DROP_IF_BUSY + DropIfBusy = 32, // MESSAGE_BUS_LISTENER_DROP_IF_BUSY //% - Reentrant = 0x0008, // MESSAGE_BUS_LISTENER_REENTRANT + Reentrant = 8, // MESSAGE_BUS_LISTENER_REENTRANT } declare namespace control { } @@ -449,35 +449,37 @@ declare namespace motors { declare const enum DigitalPin { - P0 = 19, // MICROBIT_ID_IO_P12 - P1 = 7, // MICROBIT_ID_IO_P0 - P2 = 8, // MICROBIT_ID_IO_P1 - P3 = 23, // MICROBIT_ID_IO_P16 - C4 = 10, // MICROBIT_ID_IO_P3 - C5 = 11, // MICROBIT_ID_IO_P4 - C6 = 17, // MICROBIT_ID_IO_P10 - C7 = 20, // MICROBIT_ID_IO_P13 - C8 = 21, // MICROBIT_ID_IO_P14 - C9 = 22, // MICROBIT_ID_IO_P15 - C10 = 16, // MICROBIT_ID_IO_P9 - C11 = 14, // MICROBIT_ID_IO_P7 - C12 = 13, // MICROBIT_ID_IO_P6 - C16 = 9, // MICROBIT_ID_IO_P2 - C17 = 15, // MICROBIT_ID_IO_P8 - C18 = 25, // MICROBIT_ID_IO_P20 - C19 = 24, // MICROBIT_ID_IO_P19 + P0 = 112, // MICROBIT_ID_IO_P12 + P1 = 100, // MICROBIT_ID_IO_P0 + P2 = 101, // MICROBIT_ID_IO_P1 + P3 = 116, // MICROBIT_ID_IO_P16 + C4 = 103, // MICROBIT_ID_IO_P3 + C5 = 104, // MICROBIT_ID_IO_P4 + C6 = 110, // MICROBIT_ID_IO_P10 + C7 = 113, // MICROBIT_ID_IO_P13 + C8 = 114, // MICROBIT_ID_IO_P14 + C9 = 115, // MICROBIT_ID_IO_P15 + C10 = 109, // MICROBIT_ID_IO_P9 + C11 = 107, // MICROBIT_ID_IO_P7 + C12 = 106, // MICROBIT_ID_IO_P6 + C16 = 102, // MICROBIT_ID_IO_P2 + C17 = 108, // MICROBIT_ID_IO_P8 + C18 = 120, // MICROBIT_ID_IO_P20 + C19 = 119, // MICROBIT_ID_IO_P19 } declare const enum AnalogPin { - P1 = 7, // MICROBIT_ID_IO_P0 - P2 = 8, // MICROBIT_ID_IO_P1 - C4 = 10, // MICROBIT_ID_IO_P3 - C5 = 11, // MICROBIT_ID_IO_P4 - C6 = 17, // MICROBIT_ID_IO_P10 - C16 = 9, // MICROBIT_ID_IO_P2 - C17 = 15, // MICROBIT_ID_IO_P8 - MIC = 50, // MICROBIT_ID_IO_P21 + P0 = 112, // MICROBIT_ID_IO_P12 + P1 = 100, // MICROBIT_ID_IO_P0 + P2 = 101, // MICROBIT_ID_IO_P1 + P3 = 116, // MICROBIT_ID_IO_P16 + C4 = 103, // MICROBIT_ID_IO_P3 + C5 = 104, // MICROBIT_ID_IO_P4 + C6 = 110, // MICROBIT_ID_IO_P10 + C16 = 102, // MICROBIT_ID_IO_P2 + C17 = 108, // MICROBIT_ID_IO_P8 + MIC = 121, // MICROBIT_ID_IO_P21 } @@ -501,23 +503,23 @@ declare namespace motors { declare const enum PinEventType { //% block="edge" - Edge = 1, // MICROBIT_PIN_EVENT_ON_EDGE + Edge = 2, // MICROBIT_PIN_EVENT_ON_EDGE //% block="pulse" - Pulse = 2, // MICROBIT_PIN_EVENT_ON_PULSE + Pulse = 3, // MICROBIT_PIN_EVENT_ON_PULSE //% block="touch" - Touch = 3, // MICROBIT_PIN_EVENT_ON_TOUCH + Touch = 4, // MICROBIT_PIN_EVENT_ON_TOUCH //% block="none" None = 0, // MICROBIT_PIN_EVENT_NONE } declare const enum SerialPin { - P0 = 19, // MICROBIT_ID_IO_P12 - P1 = 7, // MICROBIT_ID_IO_P0 - P2 = 8, // MICROBIT_ID_IO_P1 - P3 = 23, // MICROBIT_ID_IO_P16 - C16 = 9, // MICROBIT_ID_IO_P2 - C17 = 15, // MICROBIT_ID_IO_P8 + P0 = 112, // MICROBIT_ID_IO_P12 + P1 = 100, // MICROBIT_ID_IO_P0 + P2 = 101, // MICROBIT_ID_IO_P1 + P3 = 116, // MICROBIT_ID_IO_P16 + C16 = 102, // MICROBIT_ID_IO_P2 + C17 = 108, // MICROBIT_ID_IO_P8 USB_TX = 1001, USB_RX = 1002, } @@ -547,22 +549,6 @@ declare namespace motors { //% block=1200 BaudRate1200 = 1200, } - - - declare const enum Delimiters { - //% block="new line" - NewLine = 1, - //% block="," - Comma = 2, - //% block="$" - Dollar = 3, - //% block=":" - Colon = 4, - //% block="." - Fullstop = 5, - //% block="#" - Hash = 6, - } declare namespace serial { } diff --git a/libs/core/helpers.ts b/libs/core/helpers.ts index b5a3cc7f..ca012080 100644 --- a/libs/core/helpers.ts +++ b/libs/core/helpers.ts @@ -7,4 +7,4 @@ namespace Math { export function randomBoolean(): boolean { return Math.randomRange(0, 1) === 1; } -} +} \ No newline at end of file diff --git a/libs/core/icons.ts b/libs/core/icons.ts index c250a23d..00d82d33 100644 --- a/libs/core/icons.ts +++ b/libs/core/icons.ts @@ -210,7 +210,7 @@ namespace images { //% weight=50 blockGap=8 //% help=images/arrow-image - //% blockId=builtin_arrow_image block="arrow image %i=device_arrow" + //% blockId=builtin_arrow_image block="arrow image %i" export function arrowImage(i: ArrowNames): Image { switch (i) { // compass directions diff --git a/libs/core/images.cpp b/libs/core/images.cpp index 941b9b05..a1ebc96f 100644 --- a/libs/core/images.cpp +++ b/libs/core/images.cpp @@ -11,7 +11,7 @@ void RefMImage::destroy(RefMImage *t) { } void RefMImage::print(RefMImage *t) { - DMESG("RefMImage %p r=%d size=%d x %d", t, t->refcnt, img->width, img->height); + DMESG("RefMImage %p size=%d x %d", t, t->img->width, t->img->height); } void RefMImage::makeWritable() { @@ -52,6 +52,22 @@ Image createImage(ImageLiteral_ leds) { Image createBigImage(ImageLiteral_ leds) { return createImage(leds); } + +//% +Buffer charCodeBuffer(int charCode) { + if(charCode < MICROBIT_FONT_ASCII_START || charCode > MICROBIT_FONT_ASCII_END) + return NULL; +#if MICROBIT_CODAL + auto font = codal::BitmapFont::getSystemFont(); +#else + auto font = MicroBitFont::getSystemFont(); +#endif + const int offset = (charCode - MICROBIT_FONT_ASCII_START) * 5;; + const uint8_t* charBuffer = font.characters + offset; + + return PXT_CREATE_BUFFER(charBuffer, 5); +} + } // namespace images namespace ImageMethods { @@ -83,7 +99,7 @@ void showImage(Image sprite, int xOffset, int interval = 400) { //% parts="ledmatrix" void plotFrame(Image i, int xOffset) { // TODO showImage() used in original implementation - plotImage(i, xOffset * 5); + plotImage(i, xOffset * i->img->height); } /** @@ -178,6 +194,6 @@ bool pixel(Image i, int x, int y) { //% weight=70 help=images/show-frame //% parts="ledmatrix" void showFrame(Image i, int frame, int interval = 400) { - showImage(i, frame * 5, interval); + showImage(i, frame * i->img->height, interval); } } // namespace ImageMethods \ No newline at end of file diff --git a/libs/core/input.cpp b/libs/core/input.cpp index d268df2a..80df05a5 100644 --- a/libs/core/input.cpp +++ b/libs/core/input.cpp @@ -350,17 +350,17 @@ namespace input { //% blockId=device_get_magnetic_force block="magnetic force (µT)|%NAME" blockGap=8 //% parts="compass" //% advanced=true - int magneticForce(Dimension dimension) { - if (!uBit.compass.isCalibrated()) - uBit.compass.calibrate(); - - switch (dimension) { - case Dimension::X: return uBit.compass.getX() / 1000; - case Dimension::Y: return uBit.compass.getY() / 1000; - case Dimension::Z: return uBit.compass.getZ() / 1000; - case Dimension::Strength: return uBit.compass.getFieldStrength() / 1000; - } - return 0; + TNumber magneticForce(Dimension dimension) { + if (!uBit.compass.isCalibrated()) + uBit.compass.calibrate(); + double d = 0; + switch (dimension) { + case Dimension::X: d = uBit.compass.getX(); break; + case Dimension::Y: d = uBit.compass.getY(); break; + case Dimension::Z: d = uBit.compass.getZ(); break; + case Dimension::Strength: d = uBit.compass.getFieldStrength() ; break; + } + return fromDouble(d / 1000.0); } /** diff --git a/libs/core/input.ts b/libs/core/input.ts index c6d0a487..8f4d5529 100644 --- a/libs/core/input.ts +++ b/libs/core/input.ts @@ -25,6 +25,7 @@ namespace input { * Attaches code to run when the device is shaken. * @param body TODO */ + //% deprecated=true //% help=input/on-shake export function onShake(body: () => void): void { onGesture(Gesture.Shake, body); @@ -76,4 +77,27 @@ namespace input { export function runningTimeMicros() { return control.micros(); } + + /** + * gets the level of loudness in 0-100% + */ + //% blockId="loudness" + //% block="Loudness" + + export function soundLevel(): number { + let value = 0 + let max = 0 + let min = 1023 + for (let index = 0; index < 32; index++) { + value = pins.analogReadPin(AnalogPin.MIC) + if (value > max) { + max = value + } else if (value < min) { + min = value + } + } + value = (max - min) * 977 / 10000 + return value + } + } diff --git a/libs/core/led.cpp b/libs/core/led.cpp index ccb0d2ac..c2f7a563 100644 --- a/libs/core/led.cpp +++ b/libs/core/led.cpp @@ -62,18 +62,18 @@ namespace led { } /** - * Get the on/off state of the specified LED using x, y coordinates. (0,0) is upper left. + * Get the brightness state of the specified LED using x, y coordinates. (0,0) is upper left. * @param x the horizontal coordinate of the LED * @param y the vertical coordinate of the LED */ - //% help=led/point weight=76 - //% blockId=device_point block="point|x %x|y %y" + //% help=led/point-brightness weight=76 + //% blockId=device_point_brightness block="point|x %x|y %y brightness" //% parts="ledmatrix" //% x.min=0 x.max=4 y.min=0 y.max=4 //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 - bool point(int x, int y) { - int pix = uBit.display.image.getPixelValue(x, y); - return pix > 0; + //% advanced=true + int pointBrightness(int x, int y) { + return uBit.display.image.getPixelValue(x, y); } /** diff --git a/libs/core/led.ts b/libs/core/led.ts index 18bf83c4..2771d281 100644 --- a/libs/core/led.ts +++ b/libs/core/led.ts @@ -2,7 +2,20 @@ * Control of the LED screen. */ //% color=#8169E6 weight=97 - namespace led { +namespace led { + /** + * Get the on/off state of the specified LED using x, y coordinates. (0,0) is upper left. + * @param x the horizontal coordinate of the LED + * @param y the vertical coordinate of the LED + */ + //% help=led/point weight=76 + //% blockId=device_point block="point|x %x|y %y" + //% parts="ledmatrix" + //% x.min=0 x.max=4 y.min=0 y.max=4 + //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 + export function point(x: number, y: number): boolean { + return led.pointBrightness(x, y) > 0; + } // what's the current high value let barGraphHigh = 0; @@ -142,6 +155,4 @@ } led.setBrightness(0); } - - } diff --git a/libs/core/light.cpp b/libs/core/light.cpp new file mode 100644 index 00000000..d47fbe22 --- /dev/null +++ b/libs/core/light.cpp @@ -0,0 +1,40 @@ +#include "pxt.h" + +#if MICROBIT_CODAL +#include "neopixel.h" +#else +extern "C" void neopixel_send_buffer_core(DevicePin *pin, const uint8_t *ptr, int numBytes); +__attribute__((noinline)) static void neopixel_send_buffer(DevicePin &pin, const uint8_t *ptr, + int numBytes) { + + // setup pin as digital + pin.setDigitalValue(0); + __disable_irq(); + neopixel_send_buffer_core(&pin, ptr, numBytes); + __enable_irq(); +} +#endif + +namespace light { + +/** +* Sends a color buffer to a light strip +**/ +//% advanced=true +//% +void sendWS2812Buffer(Buffer buf, int pin) { + if (!buf || !buf->length) + return; + neopixel_send_buffer(*pxt::getPin(pin), buf->data, buf->length); +} + +/** +* Sets the light mode of a pin +**/ +//% advanced=true +//% +void setMode(int pin, int mode) { + +} + +} // namespace light diff --git a/libs/core/melodies.ts b/libs/core/melodies.ts index bbeed368..e8663463 100644 --- a/libs/core/melodies.ts +++ b/libs/core/melodies.ts @@ -46,7 +46,7 @@ enum Melodies { Birthday, //% block="wedding" blockIdentity=music.builtInMelody Wedding, - //% block="funereal" blockIdentity=music.builtInMelody + //% block="funeral" blockIdentity=music.builtInMelody Funeral, //% block="punchline" blockIdentity=music.builtInMelody Punchline, diff --git a/libs/core/music.ts b/libs/core/music.ts index 70c30a8f..7a330b90 100644 --- a/libs/core/music.ts +++ b/libs/core/music.ts @@ -173,12 +173,13 @@ enum MusicEvent { * Generation of music tones. */ //% color=#DF4600 weight=98 icon="\uf025" +//% groups='["Melody", "Tone", "Volume", "Tempo", "Melody Advanced"]' namespace music { const INTERNAL_MELODY_ENDED = 5; let beatsPerMinute: number = 120; - //% whenUsed - const freqs = hex` + //% whenUsed + const freqs = hex` 1f00210023002500270029002c002e003100340037003a003e004100450049004e00520057005c00620068006e00 75007b0083008b0093009c00a500af00b900c400d000dc00e900f70006011501260137014a015d01720188019f01 b801d201ee010b022a024b026e029302ba02e40210033f037003a403dc03170455049704dd0427057505c8052006 @@ -194,11 +195,12 @@ namespace music { */ //% help=music/play-tone weight=90 //% blockId=device_play_note block="play|tone %note=device_note|for %duration=device_beat" blockGap=8 - //% parts="headphone" + //% parts="speaker" //% useEnumVal=1 + //% group="Tone" export function playTone(frequency: number, ms: number): void { if (_playTone) _playTone(frequency, ms); - else speakerPlayTone(frequency, ms); + else pins.analogPitch(frequency, ms); } /** @@ -207,8 +209,9 @@ namespace music { */ //% help=music/ring-tone weight=80 //% blockId=device_ring block="ring tone (Hz)|%note=device_note" blockGap=8 - //% parts="headphone" + //% parts="speaker" //% useEnumVal=1 + //% group="Tone" export function ringTone(frequency: number): void { playTone(frequency, 0); } @@ -219,29 +222,29 @@ namespace music { */ //% help=music/rest weight=79 //% blockId=device_rest block="rest(ms)|%duration=device_beat" - //% parts="headphone" + //% parts="speaker" + //% group="Tone" export function rest(ms: number): void { playTone(0, ms); } /** - * Get the frequency of a note. - * @param name the note name, eg: Note.C + * Gets the frequency of a note. + * @param name the note name */ - //% weight=1 help=music/note-frequency + //% weight=50 help=music/note-frequency //% blockId=device_note block="%name" - //% shim=TD_ID - //% color="#FFFFFF" colorSecondary="#FFFFFF" + //% shim=TD_ID color="#FFFFFF" colorSecondary="#FFFFFF" //% name.fieldEditor="note" name.defl="262" //% name.fieldOptions.decompileLiterals=true //% useEnumVal=1 - //% weight=10 blockGap=8 + //% group="Tone" + //% blockGap=8 export function noteFrequency(name: Note): number { return name; } - function init() { if (beatsPerMinute <= 0) beatsPerMinute = 120; } @@ -251,6 +254,8 @@ namespace music { */ //% help=music/beat weight=49 //% blockId=device_beat block="%fraction|beat" + //% group="Tempo" + //% blockGap=8 export function beat(fraction?: BeatFraction): number { init(); if (fraction == null) fraction = BeatFraction.Whole; @@ -271,6 +276,7 @@ namespace music { */ //% help=music/tempo weight=40 //% blockId=device_tempo block="tempo (bpm)" blockGap=8 + //% group="Tempo" export function tempo(): number { init(); return beatsPerMinute; @@ -282,6 +288,7 @@ namespace music { */ //% help=music/change-tempo-by weight=39 //% blockId=device_change_tempo block="change tempo by (bpm)|%value" blockGap=8 + //% group="Tempo" export function changeTempoBy(bpm: number): void { init(); setTempo(beatsPerMinute + bpm); @@ -294,6 +301,7 @@ namespace music { //% help=music/set-tempo weight=38 //% blockId=device_set_tempo block="set tempo to (bpm)|%value" //% bpm.min=4 bpm.max=400 + //% group="Tempo" export function setTempo(bpm: number): void { init(); if (bpm > 0) { @@ -311,6 +319,7 @@ namespace music { //% weight=50 help=music/builtin-melody //% blockId=device_builtin_melody block="%melody" //% blockHidden=true + //% group="Melody Advanced" export function builtInMelody(melody: Melodies): string[] { return getMelody(melody); } @@ -320,10 +329,21 @@ namespace music { */ //% blockId=melody_on_event block="music on %value" //% help=music/on-event weight=59 blockGap=32 + //% group="Melody Advanced" export function onEvent(value: MusicEvent, handler: () => void) { control.onEvent(MICROBIT_MELODY_ID, value, handler); } + /** + * Use startMelody instead + */ + //% hidden=1 deprecated=1 + //% parts="speaker" + //% group="Melody Advanced" + export function beginMelody(melodyArray: string[], options: MelodyOptions = 1) { + return startMelody(melodyArray, options); + } + /** * Starts playing a melody. * Notes are expressed as a string of characters with this format: NOTE[octave][:duration] @@ -332,8 +352,9 @@ namespace music { */ //% help=music/begin-melody weight=60 blockGap=16 //% blockId=device_start_melody block="start melody %melody=device_builtin_melody| repeating %options" - //% parts="headphone" - export function beginMelody(melodyArray: string[], options: MelodyOptions = 1) { + //% parts="speaker" + //% group="Melody Advanced" + export function startMelody(melodyArray: string[], options: MelodyOptions = 1) { init(); if (currentMelody != undefined) { if (((options & MelodyOptions.OnceInBackground) == 0) @@ -382,7 +403,8 @@ namespace music { //% melody.shadow="melody_editor" //% tempo.min=40 tempo.max=500 //% tempo.defl=120 - //% parts=headphone + //% parts=speaker + //% group="Melody" export function playMelody(melody: string, tempo: number) { melody = melody || ""; setTempo(tempo); @@ -402,7 +424,7 @@ namespace music { } } - music.beginMelody(notes, MelodyOptions.Once) + music.startMelody(notes, MelodyOptions.Once) control.waitForEvent(MICROBIT_MELODY_ID, INTERNAL_MELODY_ENDED); } @@ -419,6 +441,7 @@ namespace music { //% melody.fieldOptions.decompileIndirectFixedInstances="true" //% melody.fieldOptions.onParentBlock="true" //% shim=TD_ID + //% group="Melody" export function melodyEditor(melody: string): string { return melody; } @@ -429,12 +452,13 @@ namespace music { */ //% help=music/stop-melody weight=59 blockGap=16 //% blockId=device_stop_melody block="stop melody $options" - //% parts="headphone" + //% parts="speaker" + //% group="Melody Advanced" export function stopMelody(options: MelodyStopOptions) { if (options & MelodyStopOptions.Background) - beginMelody([], MelodyOptions.OnceInBackground); + startMelody([], MelodyOptions.OnceInBackground); if (options & MelodyStopOptions.Foreground) - beginMelody([], MelodyOptions.Once); + startMelody([], MelodyOptions.Once); } /** @@ -442,10 +466,38 @@ namespace music { */ //% help=music/set-play-tone //% advanced=true + //% group="Tone" export function setPlayTone(f: (frequency: number, duration: number) => void) { _playTone = f; } + /** + * Set the default output volume of the sound synthesizer. + * @param volume the volume 0...255 + */ + //% blockId=synth_set_volume block="set volume %volume" + //% parts="speaker" + //% volume.min=0 volume.max=255 + //% volume.defl=127 + //% help=music/set-volume + //% weight=70 + //% group="Volume" + export function setVolume(volume: number): void { + pins.analogSetPitchVolume(volume); + } + + /** + * Returns the current output volume of the sound synthesizer. + */ + //% blockId=synth_get_volume block="volume" + //% parts="speaker" + //% help=music/volume + //% weight=69 + //% group="Volume" + export function volume(): number { + return pins.analogPitchVolume(); + } + function playNextNote(melody: Melody): void { // cache elements let currNote = melody.nextNote(); diff --git a/libs/core/pins.cpp b/libs/core/pins.cpp index 744fbeaf..f2fc4103 100644 --- a/libs/core/pins.cpp +++ b/libs/core/pins.cpp @@ -21,8 +21,8 @@ enum class DigitalPin { }; enum class AnalogPin { - P1 = MICROBIT_ID_IO_P0, // edge connector 1 - P2 = MICROBIT_ID_IO_P1, // edge connector 2 + P1 = MICROBIT_ID_IO_P0, // edge connector 1 + P2 = MICROBIT_ID_IO_P1, // edge connector 2 C4 = MICROBIT_ID_IO_P3, // LED matrix C1 C5 = MICROBIT_ID_IO_P4, // LED matrix C2 C6 = MICROBIT_ID_IO_P10, // LED matrix C3 @@ -83,6 +83,10 @@ MicroBitPin *getPin(int id) { case MICROBIT_ID_IO_P19: return &uBit.io.P19; case MICROBIT_ID_IO_P20: return &uBit.io.P20; case MICROBIT_ID_IO_P21: return &uBit.io.P21; +#if MICROBIT_CODAL + case 1001: return &uBit.io.usbTx; + case 1002: return &uBit.io.usbRx; +#endif default: return NULL; } } @@ -113,7 +117,7 @@ namespace pins { //% help=pins/digital-read-pin weight=30 //% blockId=device_get_digital_pin block="digital read|pin %name" blockGap=8 //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" name.fieldOptions.width="300" + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" int digitalReadPin(DigitalPin name) { PINREAD(getDigitalValue()); } @@ -127,14 +131,14 @@ namespace pins { //% blockId=device_set_digital_pin block="digital write|pin %name|to %value" //% value.min=0 value.max=1 //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" name.fieldOptions.width="300" + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" void digitalWritePin(DigitalPin name, int value) { PINOP(setDigitalValue(value)); } /** * Read the connector value as analog, that is, as a value comprised between 0 and 1023. - * @param name of pin to read from, eg: AnalogPin.P1 + * @param name pin to write to, eg: AnalogPin.P0 */ //% help=pins/analog-read-pin weight=25 //% blockId=device_get_analog_pin block="analog read|pin %name" blockGap="8" @@ -146,7 +150,7 @@ namespace pins { /** * Set the connector value as analog. Value must be comprised between 0 and 1023. - * @param name of pin to write to, eg: AnalogPin.P1 + * @param name pin name to write to, eg: AnalogPin.P0 * @param value value to write to the pin between ``0`` and ``1023``. eg:1023,0 */ //% help=pins/analog-write-pin weight=24 @@ -161,7 +165,7 @@ namespace pins { /** * Configure the pulse-width modulation (PWM) period of the analog output in microseconds. * If this pin is not configured as an analog output (using `analog write pin`), the operation has no effect. - * @param name analog pin to set period to, eg: AnalogPin.P1 + * @param name analog pin to set period to, eg: AnalogPin.P0 * @param micros period in micro seconds. eg:20000 */ //% help=pins/analog-set-period weight=23 blockGap=8 @@ -180,7 +184,7 @@ namespace pins { //% help=pins/on-pulsed weight=22 blockGap=16 advanced=true //% blockId=pins_on_pulsed block="on|pin %pin|pulsed %pulse" //% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4 - //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="300" + //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="250" void onPulsed(DigitalPin name, PulseValue pulse, Action body) { MicroBitPin* pin = getPin((int)name); if (!pin) return; @@ -209,7 +213,7 @@ namespace pins { //% weight=20 advanced=true //% help=pins/pulse-in //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" name.fieldOptions.width="300" + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" int pulseIn(DigitalPin name, PulseValue value, int maxDuration = 2000000) { MicroBitPin* pin = getPin((int)name); if (!pin) return 0; @@ -244,7 +248,7 @@ namespace pins { /** * Write 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). - * @param name pin to write to, eg: AnalogPin.P1 + * @param name pin to write to, eg: AnalogPin.P0 * @param value angle or rotation speed, eg:180,90,0 */ //% help=pins/servo-write-pin weight=20 @@ -282,6 +286,8 @@ namespace pins { MicroBitPin* pitchPin = NULL; + MicroBitPin* pitchPin2 = NULL; + uint8_t pitchVolume = 0xff; /** * Set the pin used when using analog pitch or music. @@ -292,50 +298,95 @@ namespace pins { //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" void analogSetPitchPin(AnalogPin name) { - pitchPin = getPin((int)name); + pitchPin = getPin((int)name); + pitchPin2 = NULL; + } + + void pinAnalogSetPitch(MicroBitPin* pin, int frequency, int ms) { + if (frequency <= 0 || pitchVolume == 0) { + pin->setAnalogValue(0); + } else { + int v = 1 << (pitchVolume >> 5); + pin->setAnalogValue(v); + pin->setAnalogPeriodUs(1000000/frequency); + } } /** - * Emit a pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin. + * Sets the volume on the pitch pin + * @param volume the intensity of the sound from 0..255 + */ + //% blockId=device_analog_set_pitch_volume block="analog set pitch volume $volume" + //% help=pins/analog-set-pitch-volume weight=3 advanced=true + //% volume.min=0 volume.max=255 + void analogSetPitchVolume(int volume) { + pitchVolume = max(0, min(0xff, volume)); + } + + /** + * Gets the volume the pitch pin from 0..255 + */ + //% blockId=device_analog_pitch_volume block="analog pitch volume" + //% help=pins/analog-pitch-volume weight=3 advanced=true + int analogPitchVolume() { + return pitchVolume; + } + + /** + * Emit a plse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin. * @param frequency frequency to modulate in Hz. * @param ms duration of the pitch in milli seconds. */ //% blockId=device_analog_pitch block="analog pitch %frequency|for (ms) %ms" //% help=pins/analog-pitch weight=4 async advanced=true blockGap=8 void analogPitch(int frequency, int ms) { - if (pitchPin == NULL) - analogSetPitchPin(AnalogPin::P1); - if (frequency <= 0) { - pitchPin->setAnalogValue(0); - } else { - pitchPin->setAnalogValue(512); - pitchPin->setAnalogPeriodUs(1000000/frequency); - } - - if (ms > 0) { - fiber_sleep(ms); - pitchPin->setAnalogValue(0); - // TODO why do we use wait_ms() here? it's a busy wait I think - wait_ms(5); + // init pins if needed + if (NULL == pitchPin) { + pitchPin = getPin((int)AnalogPin::P0); +#ifdef SOUND_MIRROR_EXTENSION + pitchPin2 = &SOUND_MIRROR_EXTENSION; +#endif + } + // set pitch + if (NULL != pitchPin) + pinAnalogSetPitch(pitchPin, frequency, ms); + if (NULL != pitchPin2) + pinAnalogSetPitch(pitchPin2, frequency, ms); + // clear pitch + if (ms > 0) { + fiber_sleep(ms); + if (NULL != pitchPin) + pitchPin->setAnalogValue(0); + if (NULL != pitchPin2) + pitchPin2->setAnalogValue(0); + fiber_sleep(5); } } /** - * Configure the pull direction of of a pin. + * Configure the pull directiion of of a pin. * @param name pin to set the pull mode on, eg: DigitalPin.P0 * @param pull one of the mbed pull configurations, eg: PinPullMode.PullUp */ //% help=pins/set-pull weight=3 advanced=true //% blockId=device_set_pull block="set pull|pin %pin|to %pull" //% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4 - //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="300" + //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="250" void setPull(DigitalPin name, PinPullMode pull) { +#if MICROBIT_CODAL + codal::PullMode m = pull == PinPullMode::PullDown + ? codal::PullMode::Down + : pull == PinPullMode::PullUp ? codal::PullMode::Up + : codal::PullMode::None; + PINOP(setPull(m)); +#else PinMode m = pull == PinPullMode::PullDown ? PinMode::PullDown : pull == PinPullMode::PullUp ? PinMode::PullUp : PinMode::PullNone; PINOP(setPull(m)); +#endif } /** @@ -347,7 +398,7 @@ namespace pins { //% help=pins/set-events weight=4 advanced=true //% blockId=device_set_pin_events block="set pin %pin|to emit %type|events" //% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4 - //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="300" + //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="250" void setEvents(DigitalPin name, PinEventType type) { getPin((int)name)->eventOn((int)type); } @@ -362,6 +413,12 @@ namespace pins { return mkBuffer(NULL, size); } +#if MICROBIT_CODAL +#define BUFFER_TYPE uint8_t* +#else +#define BUFFER_TYPE char* +#endif + /** * Read `size` bytes from a 7-bit I2C `address`. */ @@ -369,7 +426,7 @@ namespace pins { Buffer i2cReadBuffer(int address, int size, bool repeat = false) { Buffer buf = createBuffer(size); - uBit.i2c.read(address << 1, (char*)buf->data, size, repeat); + uBit.i2c.read(address << 1, (BUFFER_TYPE)buf->data, size, repeat); return buf; } @@ -379,7 +436,7 @@ namespace pins { //% int i2cWriteBuffer(int address, Buffer buf, bool repeat = false) { - return uBit.i2c.write(address << 1, (char*)buf->data, buf->length, repeat); + return uBit.i2c.write(address << 1, (BUFFER_TYPE)buf->data, buf->length, repeat); } SPI* spi = NULL; @@ -400,6 +457,30 @@ namespace pins { return p->write(value); } + /** + * Write to and read from the SPI slave at the same time + * @param command Data to be sent to the SPI slave (can be null) + * @param response Data received from the SPI slave (can be null) + */ + //% help=pins/spi-transfer argsNullable + void spiTransfer(Buffer command, Buffer response) { + if (!command && !response) + target_panic(PANIC_INVALID_ARGUMENT); + if (command && response && command->length != response->length) + target_panic(PANIC_INVALID_ARGUMENT); + auto p = allocSPI(); + unsigned len = command ? command->length : response->length; +#if MICROBIT_CODAL + p->transfer(command ? command->data : NULL, command ? len : 0, + response ? response->data : NULL, response ? len : 0); +#else + for (unsigned i = 0; i < len; ++i) { + int v = p->write(command ? command->data[i] : 0); + if (response) response->data[i] = v; + } +#endif + } + /** * Set the SPI frequency * @param frequency the clock frequency, eg: 1000000 @@ -423,6 +504,12 @@ namespace pins { p->format(bits, mode); } +#if MICROBIT_CODAL +#define PIN_ARG(pin) *(getPin((int)(pin))) +#else +#define PIN_ARG(pin) (getPin((int)(pin)))->name +#endif + /** * Set the MOSI, MISO, SCK pins used by the SPI connection * @@ -440,7 +527,18 @@ namespace pins { delete spi; spi = NULL; } + spi = new SPI(PIN_ARG(mosi), PIN_ARG(miso), PIN_ARG(sck)); + } - spi = new SPI(getPin((int)mosi)->name, getPin((int)miso)->name, getPin((int)sck)->name); + /** + * Mounts a push button on the given pin + */ + //% help=pins/push-button advanced=true + void pushButton(DigitalPin pin) { +#if MICROBIT_CODAL + new MicroBitButton(PIN_ARG(pin), (int)pin, DEVICE_BUTTON_ALL_EVENTS, ACTIVE_LOW, codal::PullMode::Up); +#else + new MicroBitButton(PIN_ARG(pin), PinMode::PullUp); +#endif } } diff --git a/libs/core/pinscompat.ts b/libs/core/pinscompat.ts index ed29ed21..22ad2e7e 100644 --- a/libs/core/pinscompat.ts +++ b/libs/core/pinscompat.ts @@ -1,4 +1,4 @@ -const enum PinEvent { +enum PinEvent { //% block="pulse high" PulseHigh = DAL.MICROBIT_PIN_EVT_PULSE_HI, // DEVICE_PIN_EVT_PULSE_HI //% block="pulse low" diff --git a/libs/core/platform.h b/libs/core/platform.h index 785d7341..55c754ef 100644 --- a/libs/core/platform.h +++ b/libs/core/platform.h @@ -1,3 +1,5 @@ +#include "nrf.h" + // helpful define to handle C++ differences in package #define PXT_MICROBIT_TAGGED_INT 1 #define PXT_POWI 1 diff --git a/libs/core/pxt.h b/libs/core/pxt.h index 76677b84..c2627984 100644 --- a/libs/core/pxt.h +++ b/libs/core/pxt.h @@ -33,6 +33,14 @@ static inline ImageData *imageBytes(ImageLiteral_ lit) { return (ImageData *)lit; } +#if MICROBIT_CODAL +// avoid clashes with codal-defined classes +#define Image MImage +#define Button MButton +#endif + +typedef MicroBitPin DevicePin; + typedef RefMImage *Image; extern MicroBit uBit; diff --git a/libs/core/pxt.json b/libs/core/pxt.json index f70f43c2..fd1e9439 100644 --- a/libs/core/pxt.json +++ b/libs/core/pxt.json @@ -17,6 +17,8 @@ "core.cpp", "pxt-helpers.ts", "helpers.ts", + "pxt-python.d.ts", + "pxt-python-helpers.ts", "pinscompat.ts", "configkeys.h", "gc.cpp", @@ -31,6 +33,8 @@ "gestures.jres", "control.ts", "control.cpp", + "interval.ts", + "gcstats.ts", "console.ts", "game.ts", "led.cpp", @@ -50,18 +54,50 @@ "trig.cpp", "fixed.ts", "templates.ts", + "sendbuffer.s", + "light.cpp", "parts/speaker.svg", "parts/headphone.svg", "parts/dcmotor.svg", "_locales/de/core-jsdoc-strings.json", "_locales/de/core-strings.json" ], + "testFiles": [], "public": true, "dependencies": {}, + "dalDTS": { + "compileServiceVariant": "mbcodal", + "includeDirs": [ + "libraries/codal-core/inc", + "libraries/codal-microbit/inc", + "libraries/codal-microbit/model", + "libraries/codal-microbit/inc/compat", + "pxtapp" + ], + "excludePrefix": [ + "USB_", + "REQUEST_", + "LIS3DH_", + "FXOS8700_", + "MMA8", + "LSM303_", + "MAG_", + "MPU6050_", + "REF_TAG_", + "HF2_", + "PXT_REF_TAG_", + "MS_", + "SCSI_" + ] + }, "yotta": { + "config": { + "microbit-dal": { + "fiber_user_data": 1 + } + }, "optionalConfig": { "microbit-dal": { - "fiber_user_data": 1, "bluetooth": { "private_addressing": 0, "advertising_timeout": 0, diff --git a/libs/core/pxtcore.h b/libs/core/pxtcore.h index 154171da..3f7047f4 100644 --- a/libs/core/pxtcore.h +++ b/libs/core/pxtcore.h @@ -19,6 +19,18 @@ void debuglog(const char *format, ...); #define GC_BLOCK_SIZE 256 #define NON_GC_HEAP_RESERVATION 1024 + +#ifdef CODAL_CONFIG_H +#define MICROBIT_CODAL 1 +#else +#define MICROBIT_CODAL 0 +#endif + +#if !MICROBIT_CODAL +#undef DMESG #define DMESG NOLOG +#endif + +#undef BYTES_TO_WORDS #endif diff --git a/libs/core/pxtparts.json b/libs/core/pxtparts.json index 470c7e2a..7254bfdc 100644 --- a/libs/core/pxtparts.json +++ b/libs/core/pxtparts.json @@ -166,17 +166,17 @@ "target": { "pinInstantiationIdx": 0 }, - "style": "solder", + "style": "croc", "orientation": "+Z" }, { "target": "threeVolt", - "style": "solder", + "style": "croc", "orientation": "+Z" }, { "target": "ground", - "style": "solder", + "style": "croc", "orientation": "+Z" } ], diff --git a/libs/core/sendbuffer.s b/libs/core/sendbuffer.s new file mode 100644 index 00000000..34299ae5 --- /dev/null +++ b/libs/core/sendbuffer.s @@ -0,0 +1,48 @@ +.syntax unified +.section .text.neopixel_send_buffer_core +.global neopixel_send_buffer_core + +neopixel_send_buffer_core: + push {r4,r5,r6,r7,lr} + + mov r4, r1 // ptr + mov r5, r2 // len + + ldr r0, [r0, #8] // get mbed DigitalOut from MicroBitPin + ldr r1, [r0, #4] // r1-mask for this pin + ldr r2, [r0, #16] // r2-clraddr + ldr r3, [r0, #12] // r3-setaddr + + b .start + +.nextbit: // C0 + str r1, [r3, #0] // pin := hi C2 + tst r6, r0 // C3 + bne .islate // C4 + str r1, [r2, #0] // pin := lo C6 +.islate: + lsrs r6, r6, #1 // r6 >>= 1 C7 + bne .justbit // C8 + + // not just a bit - need new byte + adds r4, #1 // r4++ C9 + subs r5, #1 // r5-- C10 + bcc .stop // if (r5<0) goto .stop C11 +.start: + movs r6, #0x80 // reset mask C12 + nop // C13 + +.common: // C13 + str r1, [r2, #0] // pin := lo C15 + // always re-load byte - it just fits with the cycles better this way + ldrb r0, [r4, #0] // r0 := *r4 C17 + b .nextbit // C20 + +.justbit: // C10 + // no nops, branch taken is already 3 cycles + b .common // C13 + +.stop: + str r1, [r2, #0] // pin := lo + + pop {r4,r5,r6,r7,pc} diff --git a/libs/core/serial.cpp b/libs/core/serial.cpp index b0219d30..150c149e 100644 --- a/libs/core/serial.cpp +++ b/libs/core/serial.cpp @@ -3,6 +3,7 @@ #define MICROBIT_SERIAL_READ_BUFFER_LENGTH 64 // make sure USB_TX and USB_RX don't overlap with other pin ids +// also, 1001,1002 need to be kept in sync with getPin() function enum SerialPin { P0 = MICROBIT_ID_IO_P12, P1 = MICROBIT_ID_IO_P0, @@ -39,21 +40,6 @@ enum BaudRate { BaudRate1200 = 1200 }; -enum Delimiters { - //% block="new line" - NewLine = 1, - //% block="," - Comma = 2, - //% block="$" - Dollar = 3, - //% block=":" - Colon = 4, - //% block="." - Fullstop = 5, - //% block="#" - Hash = 6, -}; - //% weight=2 color=#002050 icon="\uf287" //% advanced=true namespace serial { @@ -142,12 +128,14 @@ namespace serial { bool tryResolvePin(SerialPin p, PinName& name) { switch(p) { +#if !MICROBIT_CODAL case SerialPin::USB_TX: name = USBTX; return true; case SerialPin::USB_RX: name = USBRX; return true; +#endif default: auto pin = getPin(p); if (NULL != pin) { - name = pin->name; + name = (PinName)pin->name; return true; } } @@ -170,21 +158,49 @@ namespace serial { //% rx.fieldOptions.tooltips="false" //% blockGap=8 void redirect(SerialPin tx, SerialPin rx, BaudRate rate) { +#if MICROBIT_CODAL + if (getPin(tx) && getPin(rx)) + uBit.serial.redirect(*getPin(tx), *getPin(rx)); + uBit.serial.setBaud(rate); +#else PinName txn; PinName rxn; if (tryResolvePin(tx, txn) && tryResolvePin(rx, rxn)) uBit.serial.redirect(txn, rxn); uBit.serial.baud((int)rate); +#endif } + /** + Set the baud rate of the serial port + */ + //% weight=10 + //% blockId=serial_setbaudrate block="serial|set baud rate %rate" + //% blockGap=8 inlineInputMode=inline + //% help=serial/set-baud-rate + //% group="Configuration" advanced=true + void setBaudRate(BaudRate rate) { +#if MICROBIT_CODAL + uBit.serial.setBaud(rate); +#else + uBit.serial.baud((int)rate); +#endif + } + + /** * Direct the serial input and output to use the USB connection. */ //% weight=9 help=serial/redirect-to-usb //% blockId=serial_redirect_to_usb block="serial|redirect to USB" void redirectToUSB() { +#if MICROBIT_CODAL + uBit.serial.redirect(uBit.io.usbTx, uBit.io.usbRx); + uBit.serial.setBaud(115200); +#else uBit.serial.redirect(USBTX, USBRX); uBit.serial.baud(115200); +#endif } /** diff --git a/libs/core/serial.ts b/libs/core/serial.ts index c98944d1..8121a5ca 100644 --- a/libs/core/serial.ts +++ b/libs/core/serial.ts @@ -1,3 +1,28 @@ +const enum Delimiters { + //% block="new line (\n)" + NewLine = 10, + //% block="," + Comma = 44, + //% block="$" + Dollar = 36, + //% block=":" + Colon = 58, + //% block="." + Fullstop = 46, + //% block="#" + Hash = 35, + //% block="carriage return (\r)" + CarriageReturn = 13, + //% block="space" + Space = 32, + //% block="tab (\t)" + Tab = 9, + //% block="|" + Pipe = 124, + //% block=";" + SemiColon = 59, +} + /** * Reading and writing data over a serial connection. */ @@ -8,6 +33,7 @@ namespace serial { * The string used to mark a new line, default is \r\n */ export let NEW_LINE = "\r\n"; + export let NEW_LINE_DELIMITER: Delimiters = Delimiters.NewLine; let writeLinePadding = 32; /** @@ -89,7 +115,7 @@ namespace serial { //% blockId=serial_read_line block="serial|read line" //% weight=20 blockGap=8 export function readLine(): string { - return serial.readUntil(delimiters(Delimiters.NewLine)); + return serial.readUntil(delimiters(NEW_LINE_DELIMITER)); } /** @@ -98,17 +124,6 @@ namespace serial { //% blockId="serial_delimiter_conv" block="%del" //% weight=1 blockHidden=true export function delimiters(del: Delimiters): string { - // even though it might not look like, this is more - // (memory) efficient than the C++ implementation, because the - // strings are statically allocated and take no RAM - 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" - } + return String.fromCharCode(del as number); } } diff --git a/libs/core/shims.d.ts b/libs/core/shims.d.ts index 9d21058b..4c30e6c1 100644 --- a/libs/core/shims.d.ts +++ b/libs/core/shims.d.ts @@ -344,7 +344,7 @@ declare namespace input { //% blockId=device_get_magnetic_force block="magnetic force (µT)|%NAME" blockGap=8 //% parts="compass" //% advanced=true shim=input::magneticForce - function magneticForce(dimension: Dimension): int32; + function magneticForce(dimension: Dimension): number; /** * Obsolete, compass calibration is automatic. @@ -453,6 +453,7 @@ declare namespace control { * Make a friendly name for the device based on its serial number */ //% blockId="control_device_name" block="device name" weight=10 blockGap=8 + //% help=control/device-name //% advanced=true shim=control::deviceName function deviceName(): string; @@ -460,6 +461,7 @@ declare namespace control { * Derive a unique, consistent serial number of this device from internal data. */ //% blockId="control_device_serial_number" block="device serial number" weight=9 + //% help=control/device-serial-number //% advanced=true shim=control::deviceSerialNumber function deviceSerialNumber(): int32; @@ -521,16 +523,17 @@ declare namespace led { function unplot(x: int32, y: int32): void; /** - * Get the on/off state of the specified LED using x, y coordinates. (0,0) is upper left. + * Get the brightness state of the specified LED using x, y coordinates. (0,0) is upper left. * @param x the horizontal coordinate of the LED * @param y the vertical coordinate of the LED */ - //% help=led/point weight=76 - //% blockId=device_point block="point|x %x|y %y" + //% help=led/point-brightness weight=76 + //% blockId=device_point_brightness block="point|x %x|y %y brightness" //% parts="ledmatrix" //% x.min=0 x.max=4 y.min=0 y.max=4 - //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 shim=led::point - function point(x: int32, y: int32): boolean; + //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 + //% advanced=true shim=led::pointBrightness + function pointBrightness(x: int32, y: int32): int32; /** * Get the screen brightness from 0 (off) to 255 (full bright). @@ -642,7 +645,7 @@ declare namespace pins { //% help=pins/digital-read-pin weight=30 //% blockId=device_get_digital_pin block="digital read|pin %name" blockGap=8 //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" name.fieldOptions.width="300" shim=pins::digitalReadPin + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" shim=pins::digitalReadPin function digitalReadPin(name: DigitalPin): int32; /** @@ -654,12 +657,12 @@ declare namespace pins { //% blockId=device_set_digital_pin block="digital write|pin %name|to %value" //% value.min=0 value.max=1 //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" name.fieldOptions.width="300" shim=pins::digitalWritePin + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" shim=pins::digitalWritePin function digitalWritePin(name: DigitalPin, value: int32): void; /** * Read the connector value as analog, that is, as a value comprised between 0 and 1023. - * @param name of pin to read from, eg: AnalogPin.P1 + * @param name pin to write to, eg: AnalogPin.P0 */ //% help=pins/analog-read-pin weight=25 //% blockId=device_get_analog_pin block="analog read|pin %name" blockGap="8" @@ -669,7 +672,7 @@ declare namespace pins { /** * Set the connector value as analog. Value must be comprised between 0 and 1023. - * @param name of pin to write to, eg: AnalogPin.P1 + * @param name pin name to write to, eg: AnalogPin.P0 * @param value value to write to the pin between ``0`` and ``1023``. eg:1023,0 */ //% help=pins/analog-write-pin weight=24 @@ -682,7 +685,7 @@ declare namespace pins { /** * Configure the pulse-width modulation (PWM) period of the analog output in microseconds. * If this pin is not configured as an analog output (using `analog write pin`), the operation has no effect. - * @param name analog pin to set period to, eg: AnalogPin.P1 + * @param name analog pin to set period to, eg: AnalogPin.P0 * @param micros period in micro seconds. eg:20000 */ //% help=pins/analog-set-period weight=23 blockGap=8 @@ -699,7 +702,7 @@ declare namespace pins { //% help=pins/on-pulsed weight=22 blockGap=16 advanced=true //% blockId=pins_on_pulsed block="on|pin %pin|pulsed %pulse" //% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4 - //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="300" shim=pins::onPulsed + //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="250" shim=pins::onPulsed function onPulsed(name: DigitalPin, pulse: PulseValue, body: () => void): void; /** @@ -720,12 +723,12 @@ declare namespace pins { //% weight=20 advanced=true //% help=pins/pulse-in //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" name.fieldOptions.width="300" maxDuration.defl=2000000 shim=pins::pulseIn + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" maxDuration.defl=2000000 shim=pins::pulseIn function pulseIn(name: DigitalPin, value: PulseValue, maxDuration?: int32): int32; /** * Write 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). - * @param name pin to write to, eg: AnalogPin.P1 + * @param name pin to write to, eg: AnalogPin.P0 * @param value angle or rotation speed, eg:180,90,0 */ //% help=pins/servo-write-pin weight=20 @@ -764,7 +767,23 @@ declare namespace pins { function analogSetPitchPin(name: AnalogPin): void; /** - * Emit a pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin. + * Sets the volume on the pitch pin + * @param volume the intensity of the sound from 0..255 + */ + //% blockId=device_analog_set_pitch_volume block="analog set pitch volume $volume" + //% help=pins/analog-set-pitch-volume weight=3 advanced=true + //% volume.min=0 volume.max=255 shim=pins::analogSetPitchVolume + function analogSetPitchVolume(volume: int32): void; + + /** + * Gets the volume the pitch pin from 0..255 + */ + //% blockId=device_analog_pitch_volume block="analog pitch volume" + //% help=pins/analog-pitch-volume weight=3 advanced=true shim=pins::analogPitchVolume + function analogPitchVolume(): int32; + + /** + * Emit a plse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin. * @param frequency frequency to modulate in Hz. * @param ms duration of the pitch in milli seconds. */ @@ -773,14 +792,14 @@ declare namespace pins { function analogPitch(frequency: int32, ms: int32): void; /** - * Configure the pull direction of of a pin. + * Configure the pull directiion of of a pin. * @param name pin to set the pull mode on, eg: DigitalPin.P0 * @param pull one of the mbed pull configurations, eg: PinPullMode.PullUp */ //% help=pins/set-pull weight=3 advanced=true //% blockId=device_set_pull block="set pull|pin %pin|to %pull" //% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4 - //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="300" shim=pins::setPull + //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="250" shim=pins::setPull function setPull(name: DigitalPin, pull: PinPullMode): void; /** @@ -792,7 +811,7 @@ declare namespace pins { //% help=pins/set-events weight=4 advanced=true //% blockId=device_set_pin_events block="set pin %pin|to emit %type|events" //% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4 - //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="300" shim=pins::setEvents + //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="250" shim=pins::setEvents function setEvents(name: DigitalPin, type: PinEventType): void; /** @@ -822,6 +841,14 @@ declare namespace pins { //% blockId=spi_write block="spi write %value" shim=pins::spiWrite function spiWrite(value: int32): int32; + /** + * Write to and read from the SPI slave at the same time + * @param command Data to be sent to the SPI slave (can be null) + * @param response Data received from the SPI slave (can be null) + */ + //% help=pins/spi-transfer argsNullable shim=pins::spiTransfer + function spiTransfer(command: Buffer, response: Buffer): void; + /** * Set the SPI frequency * @param frequency the clock frequency, eg: 1000000 @@ -852,6 +879,12 @@ declare namespace pins { //% sck.fieldEditor="gridpicker" sck.fieldOptions.columns=4 //% sck.fieldOptions.tooltips="false" sck.fieldOptions.width="250" shim=pins::spiPins function spiPins(mosi: DigitalPin, miso: DigitalPin, sck: DigitalPin): void; + + /** + * Mounts a push button on the given pin + */ + //% help=pins/push-button advanced=true shim=pins::pushButton + function pushButton(pin: DigitalPin): void; } @@ -926,6 +959,16 @@ declare namespace serial { //% blockGap=8 shim=serial::redirect function redirect(tx: SerialPin, rx: SerialPin, rate: BaudRate): void; + /** + Set the baud rate of the serial port + */ + //% weight=10 + //% blockId=serial_setbaudrate block="serial|set baud rate %rate" + //% blockGap=8 inlineInputMode=inline + //% help=serial/set-baud-rate + //% group="Configuration" advanced=true shim=serial::setBaudRate + function setBaudRate(rate: BaudRate): void; + /** * Direct the serial input and output to use the USB connection. */ @@ -1039,6 +1082,12 @@ declare interface Buffer { */ //% shim=BufferMethods::write write(dstOffset: int32, src: Buffer): void; + + /** + * Compute k-bit FNV-1 non-cryptographic hash of the buffer. + */ + //% shim=BufferMethods::hash + hash(bits: int32): uint32; } declare namespace control { @@ -1056,5 +1105,21 @@ declare namespace control { //% deprecated=1 shim=control::createBufferFromUTF8 function createBufferFromUTF8(str: string): Buffer; } +declare namespace light { + + /** + * Sends a color buffer to a light strip + **/ + //% advanced=true + //% shim=light::sendWS2812Buffer + function sendWS2812Buffer(buf: Buffer, pin: int32): void; + + /** + * Sets the light mode of a pin + **/ + //% advanced=true + //% shim=light::setMode + function setMode(pin: int32, mode: int32): void; +} // Auto-generated. Do not edit. Really. diff --git a/libs/microphone/_locales/microphone-jsdoc-strings.json b/libs/microphone/_locales/microphone-jsdoc-strings.json new file mode 100644 index 00000000..8f875aee --- /dev/null +++ b/libs/microphone/_locales/microphone-jsdoc-strings.json @@ -0,0 +1,6 @@ +{ + "input": "Events and data from sensors", + "input.onLoudSound": "Registers an event that runs when a loud sound is detected", + "input.setLoudSoundThreshold": "Sets the minimum threshold for a loud sound", + "input.soundLevel": "Reads the loudness through the microphone from 0 (silent) to 255 (loud)" +} \ No newline at end of file diff --git a/libs/microphone/_locales/microphone-strings.json b/libs/microphone/_locales/microphone-strings.json new file mode 100644 index 00000000..d472f108 --- /dev/null +++ b/libs/microphone/_locales/microphone-strings.json @@ -0,0 +1,10 @@ +{ + "LoudnessCondition.Loud|block": "loud", + "LoudnessCondition.Quiet|block": "quiet", + "input.onLoudSound|block": "on loud sound", + "input.setLoudSoundThreshold|block": "set loud sound threshold %value", + "input.soundLevel|block": "sound level", + "input|block": "input", + "{id:category}Input": "Input", + "{id:group}More": "More" +} \ No newline at end of file diff --git a/libs/microphone/pxt.json b/libs/microphone/pxt.json new file mode 100644 index 00000000..0769e2fc --- /dev/null +++ b/libs/microphone/pxt.json @@ -0,0 +1,14 @@ +{ + "additionalFilePath": "../../node_modules/pxt-common-packages/libs/microphone", + "files": [ + "README.md", + "microphone.cpp", + "microphonehw.cpp", + "enums.d.ts", + "shims.d.ts" + ], + "hidden": true, + "dependencies": { + "core": "file:../core" + } +} diff --git a/libs/microphone/shims.d.ts b/libs/microphone/shims.d.ts new file mode 100644 index 00000000..c8f276d9 --- /dev/null +++ b/libs/microphone/shims.d.ts @@ -0,0 +1,33 @@ +// Auto-generated. Do not edit. +declare namespace input { + + /** + * Registers an event that runs when a loud sound is detected + */ + //% help=input/on-loud-sound + //% blockId=input_on_loud_sound block="on loud sound" + //% parts="microphone" + //% weight=88 blockGap=12 shim=input::onLoudSound + function onLoudSound(handler: () => void): void; + + /** + * Reads the loudness through the microphone from 0 (silent) to 255 (loud) + */ + //% help=input/sound-level + //% blockId=device_get_sound_level block="sound level" + //% parts="microphone" + //% weight=34 blockGap=8 shim=input::soundLevel + function soundLevel(): int32; + + /** + * Sets the minimum threshold for a loud sound + */ + //% help=input/set-loud-sound-threshold + //% blockId=input_set_loud_sound_threshold block="set loud sound threshold %value" + //% parts="microphone" + //% value.min=1 value.max=255 + //% group="More" weight=14 blockGap=8 shim=input::setLoudSoundThreshold + function setLoudSoundThreshold(value: int32): void; +} + +// Auto-generated. Do not edit. Really. diff --git a/libs/radio/_locales/radio-jsdoc-strings.json b/libs/radio/_locales/radio-jsdoc-strings.json index a8018f54..3c1c15c5 100644 --- a/libs/radio/_locales/radio-jsdoc-strings.json +++ b/libs/radio/_locales/radio-jsdoc-strings.json @@ -19,7 +19,7 @@ "radio.onReceivedValue": "Registers code to run when the radio receives a key value pair.", "radio.onReceivedValueDeprecated": "Registers code to run when the radio receives a key value pair. Deprecated, use\nonReceivedValue instead.", "radio.raiseEvent": "Sends an event over radio to neigboring devices", - "radio.readRawPacket": "Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer", + "radio.readRawPacket": "Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer.\n@returns NULL if no packet available", "radio.receiveNumber": "Reads the next packet from the radio queue and returns the packet's number\npayload or 0 if the packet did not contain a number.", "radio.receiveString": "Reads the next packet from the radio queue and returns the packet's string\npayload or the empty string if the packet did not contain a string.", "radio.receivedBuffer": "Returns the buffer payload from the last packet taken from the radio queue\n(via ``receiveNumber``, ``receiveString``, etc) or the empty string if that\npacket did not contain a string.", diff --git a/libs/radio/shims.d.ts b/libs/radio/shims.d.ts index e7f3d06f..ebda995f 100644 --- a/libs/radio/shims.d.ts +++ b/libs/radio/shims.d.ts @@ -16,7 +16,8 @@ declare namespace radio { function raiseEvent(src: int32, value: int32): void; /** - * Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer + * Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer. + * @returns NULL if no packet available */ //% shim=radio::readRawPacket function readRawPacket(): Buffer; diff --git a/libs/radio/targetoverrides.ts b/libs/radio/targetoverrides.ts index 1dab5c14..5303f0be 100644 --- a/libs/radio/targetoverrides.ts +++ b/libs/radio/targetoverrides.ts @@ -195,7 +195,8 @@ namespace radio { //% deprecated=true export function writeValueToSerial() { const p = RadioPacket.getPacket(radio.readRawPacket()); - writeToSerial(p); + if(p) + writeToSerial(p); } /** diff --git a/libs/servo/_locales/servo-jsdoc-strings.json b/libs/servo/_locales/servo-jsdoc-strings.json new file mode 100644 index 00000000..fbd92f4a --- /dev/null +++ b/libs/servo/_locales/servo-jsdoc-strings.json @@ -0,0 +1,14 @@ +{ + "servos.Servo.maxAngle": "Gets the maximum angle for the servo", + "servos.Servo.minAngle": "Gets the minimum angle for the servo", + "servos.Servo.run": "Set the throttle on a continuous servo", + "servos.Servo.run|param|speed": "the throttle of the motor from -100% to 100%", + "servos.Servo.setAngle": "Set the servo angle", + "servos.Servo.setPulse": "Set the pulse width to the servo in microseconds", + "servos.Servo.setPulse|param|micros": "the width of the pulse in microseconds", + "servos.Servo.setRange": "Set the possible rotation range angles for the servo between 0 and 180", + "servos.Servo.setRange|param|maxAngle": "the maximum angle from 90 to 180", + "servos.Servo.setRange|param|minAngle": "the minimum angle from 0 to 90", + "servos.Servo.setStopOnNeutral": "Set a servo stop mode so it will stop when the rotation angle is in the neutral position, 90 degrees.", + "servos.Servo.stop": "Stop sending commands to the servo so that its rotation will stop at the current position." +} \ No newline at end of file diff --git a/libs/servo/_locales/servo-strings.json b/libs/servo/_locales/servo-strings.json new file mode 100644 index 00000000..b5591fe2 --- /dev/null +++ b/libs/servo/_locales/servo-strings.json @@ -0,0 +1,14 @@ +{ + "servos.P0|block": "servo P0", + "servos.P3|block": "servo P3", + "servos.Servo.run|block": "continuous %servo run at %speed=speedPicker \\%", + "servos.Servo.setAngle|block": "set %servo angle to %degrees=protractorPicker °", + "servos.Servo.setPulse|block": "set %servo pulse to %micros μs", + "servos.Servo.setRange|block": "set %servo range from %minAngle to %maxAngle", + "servos.Servo.setStopOnNeutral|block": "set %servo stop on neutral %enabled", + "servos.Servo.stop|block": "stop %servo", + "{id:category}Servos": "Servos", + "{id:group}Configuration": "Configuration", + "{id:group}Continuous": "Continuous", + "{id:group}Positional": "Positional" +} \ No newline at end of file diff --git a/libs/servo/pxt.json b/libs/servo/pxt.json index 7027a98f..fc5e2f87 100644 --- a/libs/servo/pxt.json +++ b/libs/servo/pxt.json @@ -1,3 +1,13 @@ { - "additionalFilePath": "../../node_modules/pxt-common-packages/libs/servo" -} \ No newline at end of file + "additionalFilePath": "../../node_modules/pxt-common-packages/libs/servo", + "files": [ + "README.md", + "servo.ts", + "ns.ts", + "targetoverrides.ts" + ], + "public": true, + "dependencies": { + "core": "file:../core" + } +} diff --git a/libs/servo/targetoverrides.ts b/libs/servo/targetoverrides.ts index 1cef1499..3a05732f 100644 --- a/libs/servo/targetoverrides.ts +++ b/libs/servo/targetoverrides.ts @@ -1,8 +1,6 @@ namespace servos { //% block="servo P0" fixedInstance whenUsed export const P0 = new servos.PinServo(pins.P0); - //% block="servo P1" fixedInstance whenUsed - export const P1 = new servos.PinServo(pins.P1); - //% block="servo P2" fixedInstance whenUsed - export const P2 = new servos.PinServo(pins.P2); + //% block="servo P3" fixedInstance whenUsed + export const P3 = new servos.PinServo(pins.P3); } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 29f69628..278a9c13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "pxt-calliope", - "version": "2.1.57", + "version": "3.0.22", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -36,9 +36,9 @@ "integrity": "sha512-54Dm6NwYeiSQmRB1BLXKr5GELi0wFapR1npi8bnZhEcu84d/yQKqnwwXQ56hZ0RUbTG6L5nqDZaN3dgByQXQRQ==" }, "@types/q": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", - "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==" + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" }, "@types/react": { "version": "16.0.25", @@ -94,9 +94,9 @@ } }, "acorn": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", - "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==" + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==" }, "acorn-node": { "version": "1.8.2", @@ -109,9 +109,9 @@ } }, "acorn-walk": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", - "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==" + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" }, "after": { "version": "0.8.2", @@ -124,9 +124,9 @@ "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==" }, "ajv": { - "version": "6.12.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", - "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", + "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -218,9 +218,9 @@ }, "dependencies": { "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" } } }, @@ -330,9 +330,9 @@ } }, "binary-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" }, "bindings": { "version": "1.5.0", @@ -375,9 +375,9 @@ "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" }, "bn.js": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.1.tgz", - "integrity": "sha512-IUTD/REb78Z2eodka1QZyyEk66pciRcP6Sroka0aI3tG/iwIdYLrBD62RsubR7vqdt3WyX8p4jxeatzmRSphtA==" + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", + "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==" }, "body-parser": { "version": "1.19.0", @@ -405,7 +405,6 @@ "version": "2.10.1", "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "optional": true, "requires": { "hoek": "2.x.x" } @@ -564,25 +563,26 @@ }, "dependencies": { "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" } } }, "browserify-sign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.1.0.tgz", - "integrity": "sha512-VYxo7cDCeYUoBZ0ZCy4UyEUCP3smyBd4DRQM5nrFS1jJjPJjX7rP3oLRpPoWfkhQfyJ0I9ZbHbKafrFD/SGlrg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", "requires": { "bn.js": "^5.1.1", "browserify-rsa": "^4.0.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.2", + "elliptic": "^6.5.3", "inherits": "^2.0.4", "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0" + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" }, "dependencies": { "readable-stream": { @@ -594,6 +594,11 @@ "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" } } }, @@ -606,14 +611,14 @@ } }, "browserslist": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.12.0.tgz", - "integrity": "sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.0.tgz", + "integrity": "sha512-pUsXKAF2lVwhmtpeA3LJrZ76jXuusrNyhduuQs7CDFf9foT4Y38aQOserd2lMe5DSSrjf3fx34oHwryuvxAUgQ==", "requires": { - "caniuse-lite": "^1.0.30001043", - "electron-to-chromium": "^1.3.413", - "node-releases": "^1.1.53", - "pkg-up": "^2.0.0" + "caniuse-lite": "^1.0.30001111", + "electron-to-chromium": "^1.3.523", + "escalade": "^3.0.2", + "node-releases": "^1.1.60" } }, "buffer": { @@ -719,9 +724,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001051", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001051.tgz", - "integrity": "sha512-sw8UUnTlRevawTMZKN7vpfwSjCBVoiMPlYd8oT2VwNylyPCBdMAUmLGUApnYYTtIm5JXsQegUAY7GPHqgfDzjw==" + "version": "1.0.30001116", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001116.tgz", + "integrity": "sha512-f2lcYnmAI5Mst9+g0nkMIznFGsArRmZ0qU+dnq8l91hymdc2J3SFbiPhOJEeDqC1vtE8nc1qNQyklzB8veJefQ==" }, "caseless": { "version": "0.12.0", @@ -759,9 +764,9 @@ } }, "chokidar": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz", - "integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", + "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", "requires": { "anymatch": "~3.1.1", "braces": "~3.0.2", @@ -966,9 +971,9 @@ }, "dependencies": { "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" } } }, @@ -1039,9 +1044,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -1088,9 +1093,9 @@ } }, "css-what": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz", - "integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.3.0.tgz", + "integrity": "sha512-pv9JPyatiPaQ6pf4OvD/dbfm0o5LviWmwxNWzblYf/1u9QZd0ihV+PMwy5jdQWQ3349kZmKEx9WXuSka2dM4cg==" }, "cssesc": { "version": "3.0.0", @@ -1109,9 +1114,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -1163,9 +1168,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -1198,9 +1203,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -1398,9 +1403,9 @@ }, "dependencies": { "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" } } }, @@ -1501,14 +1506,14 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.3.428", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.428.tgz", - "integrity": "sha512-u3+5jEfgLKq/hGO96YfAoOAM1tgFnRDTCD5mLuev44tttcXix+INtVegAkmGzUcfDsnzkPt51XXurXZLLwXt0w==" + "version": "1.3.537", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.537.tgz", + "integrity": "sha512-v1jGX46P9vq1XvCBFJ7T7rHd2kMuSrCHnYvO0TqNoURYt7VoxCnqo5+W84s0jlnq0iQUPk5H2D01RfL4ENe2CA==" }, "elliptic": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", - "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -1520,9 +1525,9 @@ }, "dependencies": { "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" } } }, @@ -1608,9 +1613,9 @@ "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" }, "entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", - "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" }, "errno": { "version": "0.1.7", @@ -1630,21 +1635,21 @@ } }, "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", "object-inspect": "^1.7.0", "object-keys": "^1.1.1", "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" } }, "es-to-primitive": { @@ -1657,6 +1662,11 @@ "is-symbol": "^1.0.2" } }, + "escalade": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz", + "integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==" + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1673,9 +1683,9 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "eventemitter3": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", - "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" }, "events": { "version": "2.1.0", @@ -1728,9 +1738,9 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-json-stable-stringify": { "version": "2.1.0", @@ -1785,14 +1795,6 @@ "unpipe": "~1.0.0" } }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "^2.0.0" - } - }, "findup": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz", @@ -1820,27 +1822,9 @@ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==" }, "follow-redirects": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz", - "integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==", - "requires": { - "debug": "^3.0.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" }, "forever-agent": { "version": "0.6.1", @@ -2061,9 +2045,9 @@ } }, "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" } } }, @@ -2111,8 +2095,7 @@ "hoek": { "version": "2.16.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "optional": true + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" }, "hsl-regex": { "version": "1.0.0", @@ -2145,17 +2128,27 @@ "entities": "^2.0.0" }, "dependencies": { + "dom-serializer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.0.1.tgz", + "integrity": "sha512-1Aj1Qy3YLbdslkI75QEOfdp9TkQ3o8LRISAzxOibjBs/xWwr1WxZFOQphFkZuepHFGo+kB8e5FVJSS0faAJ4Rw==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "entities": "^2.0.0" + } + }, "domelementtype": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==" }, "domutils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.0.0.tgz", - "integrity": "sha512-n5SelJ1axbO636c2yUtOGia/IcJtVtlhQbFiVDBZHKV5ReJO1ViX7sFEemtuyoAnBxk5meNSYgA8V4s0271efg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.2.0.tgz", + "integrity": "sha512-0haAxVr1PR0SqYwCH7mxMpHZUwjih9oPPedqpR/KufsnxPyZ9dyVw1R5093qnJF3WXSbjBkdzRWLw/knJV/fAg==", "requires": { - "dom-serializer": "^0.2.1", + "dom-serializer": "^1.0.1", "domelementtype": "^2.0.1", "domhandler": "^3.0.0" } @@ -2182,14 +2175,14 @@ } }, "http-parser-js": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", - "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz", + "integrity": "sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ==" }, "http-proxy": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", - "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "requires": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -2342,9 +2335,9 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" }, "is-color-stop": { "version": "1.1.0", @@ -2401,11 +2394,11 @@ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" }, "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", "requires": { - "has": "^1.0.3" + "has-symbols": "^1.0.1" } }, "is-resolvable": { @@ -2469,9 +2462,9 @@ "dev": true }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -2696,19 +2689,10 @@ } } }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, "lodash.clonedeep": { "version": "4.5.0", @@ -2830,16 +2814,16 @@ }, "dependencies": { "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" } } }, "mime": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz", - "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==" + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" }, "mime-db": { "version": "1.42.0", @@ -2999,17 +2983,17 @@ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, "node-abi": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.16.0.tgz", - "integrity": "sha512-+sa0XNlWDA6T+bDLmkCUYn6W5k5W6BPRL6mqzSCs6H/xUgtl4D5x2fORKDzopKiU6wsyn/+wXlRXwXeSp+mtoA==", + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.18.0.tgz", + "integrity": "sha512-yi05ZoiuNNEbyT/xXfSySZE+yVnQW6fxPZuFbLyS1s6b5Kw3HzV2PHOM4XR+nsjzkHxByK+2Wg+yCQbe35l8dw==", "requires": { "semver": "^5.4.1" } }, "node-releases": { - "version": "1.1.55", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.55.tgz", - "integrity": "sha512-H3R3YR/8TjT5WPin/wOoHOUPHgvj8leuU/Keta/rwelEQN9pA/S2Dx8/se4pZ2LBxSd0nAGzsNzhqwa77v7F1w==" + "version": "1.1.60", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz", + "integrity": "sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==" }, "noop-logger": { "version": "0.1.1", @@ -3067,9 +3051,9 @@ "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" }, "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" }, "object-keys": { "version": "1.1.1", @@ -3149,27 +3133,6 @@ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" - }, "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -3231,11 +3194,6 @@ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -3252,9 +3210,9 @@ "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=" }, "pbkdf2": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", - "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -3278,14 +3236,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, - "pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", - "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", - "requires": { - "find-up": "^2.1.0" - } - }, "pngjs": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", @@ -3327,9 +3277,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3356,9 +3306,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3387,9 +3337,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3417,9 +3367,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3442,9 +3392,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3467,9 +3417,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3492,9 +3442,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3520,9 +3470,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3555,9 +3505,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3591,9 +3541,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3624,9 +3574,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3659,9 +3609,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3692,9 +3642,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3727,9 +3677,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3754,9 +3704,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3787,9 +3737,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3820,9 +3770,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3852,9 +3802,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3884,9 +3834,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3916,9 +3866,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3949,9 +3899,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3980,9 +3930,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -4012,9 +3962,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -4045,9 +3995,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -4073,9 +4023,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -4116,9 +4066,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -4148,9 +4098,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -4170,14 +4120,14 @@ "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" }, "prebuild-install": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.3.tgz", - "integrity": "sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==", + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.5.tgz", + "integrity": "sha512-YmMO7dph9CYKi5IR/BzjOJlRzpxGGVo1EsLSUZ0mt/Mq0HWZIHOKHHcHdT69yG54C9m6i45GpItwRHpk0Py7Uw==", "requires": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", "github-from-package": "0.0.0", - "minimist": "^1.2.0", + "minimist": "^1.2.3", "mkdirp": "^0.5.1", "napi-build-utils": "^1.0.1", "node-abi": "^2.7.0", @@ -4261,9 +4211,9 @@ }, "dependencies": { "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" } } }, @@ -4330,18 +4280,51 @@ } }, "pxt-common-packages": { - "version": "6.21.10", - "resolved": "https://registry.npmjs.org/pxt-common-packages/-/pxt-common-packages-6.21.10.tgz", - "integrity": "sha512-GsNfjTe0YWQX4nn5lMiXST79yeb8OGCZbeJAP6I0dFfahoCM1H2tQqY/hMEPAznY1QZEgHkYvpw8SEWJvbK6Vw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/pxt-common-packages/-/pxt-common-packages-7.0.4.tgz", + "integrity": "sha512-s1tTRqgkax0VhhqRdzfmKVB9/pw4RieLyPIFmKK77NhMNuvwGDF5DnPL2fknwv6Prd2ozeLoUOztDPaCqGj9XQ==", "requires": { "@jacdac/jacdac-ts": "^0.0.9", - "pxt-core": "^5.36.2" + "pxt-core": "^5.37.15" + }, + "dependencies": { + "pxt-core": { + "version": "5.37.83", + "resolved": "https://registry.npmjs.org/pxt-core/-/pxt-core-5.37.83.tgz", + "integrity": "sha512-4HMV9Zkwu2MB6rdbZNK95pvIvORe/rVBQHs34Eby07wwtB2B4fac0Nnq83Y+zNLSzDd6Th51mXdKIrJjYxLo2w==", + "requires": { + "applicationinsights-js": "^1.0.20", + "bluebird": "3.5.1", + "browserify": "16.2.0", + "chai": "^3.5.0", + "cssnano": "4.1.10", + "dompurify": "2.0.8", + "faye-websocket": "0.11.1", + "karma": "4.4.1", + "karma-chai": "0.1.0", + "karma-chrome-launcher": "3.1.0", + "karma-mocha": "1.3.0", + "less": "2.7.3", + "lzma": "2.3.2", + "marked": "0.3.19", + "mocha": "5.1.0", + "pngjs": "3.4.0", + "postcss": "6.0.21", + "puppeteer": "^2.0.0", + "request": "2.88.0", + "rimraf": "2.5.4", + "rtlcss": "2.2.1", + "sanitize-html": "1.22.0", + "semantic-ui-less": "2.2.14", + "uglify-js": "3.3.21" + } + } } }, "pxt-core": { - "version": "5.36.9", - "resolved": "https://registry.npmjs.org/pxt-core/-/pxt-core-5.36.9.tgz", - "integrity": "sha512-2rrKF+dSrYRwc0GjhPKNR4onzrN4njaWoXQrb9fBvOxsDvpRdrcNnzOi3X7aMv4ocoBYG6wEkCZnk+Ti+AOEFw==", + "version": "6.0.20", + "resolved": "https://registry.npmjs.org/pxt-core/-/pxt-core-6.0.20.tgz", + "integrity": "sha512-dugQC1/10P72exsR3Ed3vGuK8rLkP3+NjrWE+NrLqSH9064Fl20d1fGe8yHGjlbPYyKACDjJeX3fZy1Y12GzEA==", "requires": { "applicationinsights-js": "^1.0.20", "bluebird": "3.5.1", @@ -4539,11 +4522,11 @@ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "requires": { - "ajv": "^6.5.5", + "ajv": "^6.12.3", "har-schema": "^2.0.0" } }, @@ -4668,9 +4651,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -4759,9 +4742,9 @@ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, "simple-concat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", - "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" }, "simple-get": { "version": "3.1.0", @@ -5014,26 +4997,6 @@ "es-abstract": "^1.17.5" } }, - "string.prototype.trimleft": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", - "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimstart": "^1.0.0" - } - }, - "string.prototype.trimright": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", - "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimend": "^1.0.0" - } - }, "string.prototype.trimstart": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", @@ -5081,9 +5044,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.29.tgz", - "integrity": "sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==", + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -5152,9 +5115,9 @@ } }, "tar-fs": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz", - "integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.0.tgz", + "integrity": "sha512-9uW5iDvrIMCVpvasdFHW0wJPez0K4JnMZtsuIeDI7HyMGJNxmDZDOCQROr7lXyS+iL/QMpj07qcjGYTSdRFXUg==", "requires": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -5163,9 +5126,9 @@ } }, "tar-stream": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz", - "integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.3.tgz", + "integrity": "sha512-Z9yri56Dih8IaK8gncVPx4Wqt86NDmQTSh49XLZgjWpGZL9GK9HKParS2scqHCC4w6X9Gh2jwaU45V47XTKwVA==", "requires": { "bl": "^4.0.1", "end-of-stream": "^1.4.1", @@ -5488,19 +5451,19 @@ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" }, "websocket-driver": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", - "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "requires": { - "http-parser-js": ">=0.4.0 <0.4.11", + "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, "websocket-extensions": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==" + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" }, "webusb": { "version": "1.3.1", @@ -5513,9 +5476,9 @@ }, "dependencies": { "@types/node": { - "version": "8.10.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.60.tgz", - "integrity": "sha512-YjPbypHFuiOV0bTgeF07HpEEqhmHaZqYNSdCKeBJa+yFoQ/7BC+FpJcwmi34xUIIRVFktnUyP1dPU8U0612GOg==" + "version": "8.10.62", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.62.tgz", + "integrity": "sha512-76fupxOYVxk36kb7O/6KtrAPZ9jnSK3+qisAX4tQMEuGNdlvl7ycwatlHqjoE6jHfVtXFM3pCrCixZOidc5cuw==" } } }, diff --git a/package.json b/package.json index 8368e952..8600f834 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pxt-calliope", - "version": "2.1.57", + "version": "3.0.22", "description": "micro:bit target for Microsoft MakeCode (PXT)", "keywords": [ "JavaScript", @@ -45,7 +45,7 @@ "typescript": "^3.7.5" }, "dependencies": { - "pxt-common-packages": "6.21.10", - "pxt-core": "5.36.9" + "pxt-common-packages": "7.0.4", + "pxt-core": "6.0.20" } } diff --git a/pxtarget.json b/pxtarget.json index 05be91a8..7b52e407 100644 --- a/pxtarget.json +++ b/pxtarget.json @@ -10,7 +10,9 @@ "libs/radio", "libs/devices", "libs/bluetooth", - "libs/radio-broadcast" + "libs/servo", + "libs/radio-broadcast", + "libs/microphone" ], "cloud": { "workspace": false, @@ -28,20 +30,22 @@ } }, "compile": { - "isNative": true, + "isNative": false, "hasHex": true, "deployDrives": "MINI", "driveName": "MINI", - "hexMimeType": "application/x-calliope-hex", + "hexMimeType": "application/x-microbit-hex", "openocdScript": "source [find interface/cmsis-dap.cfg]; source [find target/nrf51.cfg]", - "flashUsableEnd": 245760, - "flashEnd": 245760, + "flashUsableEnd": 242688, + "flashEnd": 242688, "flashCodeAlign": 1024, "floatingPoint": true, "taggedInts": true, "utf8": false, "gc": true, "imageRefTag": 9, + "shimRenames": { + }, "patches": { "0.0.0 - 1.0.0": [ { @@ -104,13 +108,21 @@ { "usagePage": "0xFF00", "usageId": "0x0001", - "vid": "0x0d28", - "pid": "0x0204" + "vid": "0x1366", + "pid": "0x1025" } ], "webUSB": true, "useNewFunctions": true }, + "compileService": { + "yottaTarget": "calliope-mini-classic-gcc", + "yottaCorePackage": "microbit", + "githubCorePackage": "Amerlander/microbit", + "gittag": "v2.2.0-rc6.03", + "serviceId": "calliope", + "dockerImage": "pext/yotta:latest" + }, "runtime": { "mathBlocks": true, "loopsBlocks": true, @@ -119,6 +131,8 @@ "textBlocks": true, "listsBlocks": true, "functionBlocks": true, + "breakBlock": true, + "continueBlock": true, "functionsOptions": { "useNewFunctions": true, "extraFunctionEditorTypes": [ @@ -127,6 +141,12 @@ "label": "LedSprite", "icon": "send", "defaultName": "sprite" + }, + { + "typeName": "Image", + "label": "Image", + "icon": "image outline", + "defaultName": "image" } ] }, @@ -136,10 +156,9 @@ }, "simulator": { "autoRun": true, - "enableTrace": true, - "streams": true, + "streams": false, "aspectRatio": 1.13, - "parts": false, + "parts": true, "partsAspectRatio": 0.69, "boardDefinition": { "visual": "calliope", @@ -234,7 +253,14 @@ "microphone", "rgbled" ], - "useCrocClips": true, + "pinStyles": { + "P0": "croc", + "P1": "croc", + "P2": "croc", + "P3": "croc", + "EDGE_GND": "croc", + "EDGE_VCC": "croc" + }, "marginWhenBreadboarding": [ 0, 0, @@ -243,15 +269,8 @@ ] } }, - "compileService": { - "yottaTarget": "calliope-mini-classic-gcc", - "yottaCorePackage": "microbit", - "githubCorePackage": "calliope-mini/microbit", - "gittag": "pxtgc-0", - "serviceId": "calliope" - }, "serial": { - "nameFilter": "^(mbed Serial Port|DAPLink CMSIS-DAP)", + "nameFilter": "^(Calliope mini|mbed Serial Port|DAPLink CMSIS-DAP)", "log": true, "useEditor": true, "editorTheme": { @@ -265,11 +284,10 @@ "#107C10" ] }, - "vendorId": "0x0d28", - "productId": "0x0204", + "vendorId": "0x1366", + "productId": "0x1025", "rawHID": true }, - "ignoreDocsErrors": true, "appTheme": { "accentColor": "#249899", "defaultLocale": "de", @@ -332,6 +350,7 @@ } ], "hasReferenceDocs": false, + "hideHomeDetailsVideo": true, "invertedMenu": true, "coloredToolbox": true, "monacoToolbox": true, @@ -366,14 +385,15 @@ "functions": "#005A9E", "arrays": "#E65722" }, + "blocksCollapsing": true, "highContrast": true, "greenScreen": true, - "accessibleBlocks": true, "print": true, "selectLanguage": true, "availableLocales": [ "en", "ar", + "bg", "cs", "da", "de", @@ -381,6 +401,7 @@ "es-ES", "fi", "fr", + "he", "hu", "is", "it", @@ -388,6 +409,7 @@ "ko", "nl", "nb", + "nn-NO", "pl", "pt-BR", "pt-PT", @@ -405,7 +427,8 @@ }, "browserDbPrefixes": { "1": "v1", - "2": "v2" + "2": "v2", + "3": "v3" }, "editorVersionPaths": { "0": "v0" @@ -416,13 +439,15 @@ "simGifTransparent": "rgba(0,0,0,0)", "simGifMaxFrames": 44, "simScreenshotMaxUriLength": 300000, - "importExtensionFiles": true, + "qrCode": true, + "importExtensionFiles": true, + "nameProjectFirst": true, "githubEditor": true, "tutorialBlocksDiff": false, - "python": true, - "pythonToolbox": true, "chooseLanguageRestrictionOnNewProject": true, - "openProjectNewTab": true + "openProjectNewTab": true, + "python": true, + "appFlashingTroubleshoot": "/device/windows-app/troubleshoot" }, "queryVariants": { "hidemenu": { @@ -431,6 +456,5 @@ } } }, - "uploadDocs": false, - "uploadApiStringsBranchRx": "^(master|v[2-9]\\.\\d+\\.\\d+)$" -} \ No newline at end of file + "uploadDocs": true +} diff --git a/pxtwapp/pxtwapp/package.appxmanifest b/pxtwapp/pxtwapp/package.appxmanifest index 7402c62d..32ef2a2c 100644 --- a/pxtwapp/pxtwapp/package.appxmanifest +++ b/pxtwapp/pxtwapp/package.appxmanifest @@ -51,7 +51,7 @@ - + diff --git a/sim/dalboard.ts b/sim/dalboard.ts index 6f18e9cd..51bb2627 100644 --- a/sim/dalboard.ts +++ b/sim/dalboard.ts @@ -1,8 +1,10 @@ /// +/// +/// namespace pxsim { export class DalBoard extends CoreBoard - implements RadioBoard { + implements RadioBoard, LightBoard { // state & update logic for component services ledMatrixState: LedMatrixState; edgeConnectorState: EdgeConnectorState; @@ -13,8 +15,8 @@ namespace pxsim { lightSensorState: LightSensorState; buttonPairState: ButtonPairState; radioState: RadioState; - // TODO: not singletons - neopixelState: NeoPixelState; + microphoneState: AnalogSensorState; + lightState: pxt.Map; rgbLedState: number; speakerState: SpeakerState; fileSystem: FileSystemState; @@ -27,6 +29,7 @@ namespace pxsim { super() // components + this.lightState = {}; this.fileSystem = new FileSystemState(); this.builtinParts["ledmatrix"] = this.ledMatrixState = new LedMatrixState(runtime); this.builtinParts["buttonpair"] = this.buttonPairState = new ButtonPairState({ @@ -72,23 +75,25 @@ namespace pxsim { ID_RADIO: DAL.MICROBIT_ID_RADIO, RADIO_EVT_DATAGRAM: DAL.MICROBIT_RADIO_EVT_DATAGRAM }); + this.builtinParts["microphone"] = this.microphoneState = new AnalogSensorState(3001 /* DEVICE_ID_MICROPHONE */, 52, 120, 75, 96); this.builtinParts["accelerometer"] = this.accelerometerState = new AccelerometerState(runtime); this.builtinParts["serial"] = this.serialState = new SerialState(); this.builtinParts["thermometer"] = this.thermometerState = new ThermometerState(); this.builtinParts["lightsensor"] = this.lightSensorState = new LightSensorState(); this.builtinParts["compass"] = this.compassState = new CompassState(); - this.builtinParts["neopixel"] = this.neopixelState = new NeoPixelState(); this.builtinParts["speaker"] = this.speakerState = new SpeakerState(); this.builtinParts["microservo"] = this.edgeConnectorState; this.builtinVisuals["buttonpair"] = () => new visuals.ButtonPairView(); this.builtinVisuals["ledmatrix"] = () => new visuals.LedMatrixView(); - this.builtinVisuals["neopixel"] = () => new visuals.NeoPixelView(); this.builtinVisuals["microservo"] = () => new visuals.MicroServoView(); + this.builtinParts["neopixel"] = (pin: Pin) => { return this.neopixelState(pin.id); }; + this.builtinVisuals["neopixel"] = () => new visuals.NeoPixelView(pxsim.parsePinString); + this.builtinPartVisuals["neopixel"] = (xy: visuals.Coord) => visuals.mkNeoPixelPart(xy); + this.builtinPartVisuals["buttonpair"] = (xy: visuals.Coord) => visuals.mkBtnSvg(xy); this.builtinPartVisuals["ledmatrix"] = (xy: visuals.Coord) => visuals.mkLedMatrixSvg(xy, 8, 8); - this.builtinPartVisuals["neopixel"] = (xy: visuals.Coord) => visuals.mkNeoPixelPart(xy); this.builtinPartVisuals["microservo"] = (xy: visuals.Coord) => visuals.mkMicroServoPart(xy); } @@ -114,8 +119,6 @@ namespace pxsim { initAsync(msg: SimulatorRunMessage): Promise { super.initAsync(msg); - const options = (msg.options || {}) as RuntimeOptions; - const boardDef = msg.boardDefinition; const cmpsList = msg.parts; const cmpDefs = msg.partDefinitions || {}; @@ -143,6 +146,19 @@ namespace pxsim { return Promise.resolve(); } + tryGetNeopixelState(pinId: number): CommonNeoPixelState { + return this.lightState[pinId]; + } + + neopixelState(pinId: number): CommonNeoPixelState { + if (pinId === undefined) { + pinId = DAL.MICROBIT_ID_IO_P0; + } + let state = this.lightState[pinId]; + if (!state) state = this.lightState[pinId] = new CommonNeoPixelState(); + return state; + } + screenshotAsync(width?: number): Promise { return this.viewHost.screenshotAsync(width); } @@ -180,4 +196,15 @@ namespace pxsim { export function board(): DalBoard { return runtime.board as DalBoard; } -} + + export function parsePinString(gpioPin: string): Pin { + if (gpioPin == "*") + return board().edgeConnectorState.getPin(DAL.MICROBIT_ID_IO_P0); + + const m = /^(Analog|Digital)Pin\.P(\d)+/.exec(gpioPin); + if (!m) + return undefined; + const pinNum = parseInt(m[2]); + return board().edgeConnectorState.pins[pinNum] + } +} \ No newline at end of file diff --git a/sim/state/accelerometer.ts b/sim/state/accelerometer.ts index 80172fd6..01b32549 100644 --- a/sim/state/accelerometer.ts +++ b/sim/state/accelerometer.ts @@ -16,6 +16,7 @@ namespace pxsim.input { export function isGesture(gesture: number): boolean { const b = accForGesture(gesture); + b.accelerometer.activate(); return b.accelerometer.getGesture() == gesture; } @@ -33,28 +34,25 @@ namespace pxsim.input { acc.activate(AccelerometerFlag.Z); return acc.getZ(); default: - acc.activate(); - return Math.floor(Math.sqrt(acc.instantaneousAccelerationSquared())); + acc.activate(AccelerometerFlag.Strength); + return acc.getStrength(); } } export function rotation(kind: number): number { const b = board().accelerometerState; const acc = b.accelerometer; - acc.activate(); - const x = acc.getX(MicroBitCoordinateSystem.NORTH_EAST_DOWN); - const y = acc.getY(MicroBitCoordinateSystem.NORTH_EAST_DOWN); - const z = acc.getZ(MicroBitCoordinateSystem.NORTH_EAST_DOWN); - - const roll = Math.atan2(y, z); - const pitch = Math.atan(-x / (y * Math.sin(roll) + z * Math.cos(roll))); - - let r = 0; switch (kind) { - case 0: r = pitch; break; - case 1: r = roll; break; + case 0: { + acc.activate(AccelerometerFlag.Pitch); + return acc.getPitch(); + } + case 1: { + acc.activate(AccelerometerFlag.Roll); + return acc.getRoll(); + } + default: return 0; } - return Math.floor(r / Math.PI * 180); } export function setAccelerometerRange(range: number) { @@ -117,8 +115,11 @@ namespace pxsim { export enum AccelerometerFlag { X = 1, - Y = 2, - Z = 4 + Y = 1 << 1, + Z = 1 << 2, + Strength = 1 << 3, + Pitch = 1 << 4, + Roll = 1 << 5 } export class Accelerometer { @@ -148,7 +149,7 @@ namespace pxsim { this.isActive = true; this.runtime.queueDisplayUpdate(); } - if (flags) + if (!!flags) this.flags |= flags; } @@ -169,7 +170,29 @@ namespace pxsim { board().bus.queue(this.id, DAL.MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE) } - public instantaneousAccelerationSquared() { + public getStrength() { + return Math.floor(Math.sqrt(this.instantaneousAccelerationSquared())); + } + + updateEnvironmentGlobals() { + // update debugger + if (this.isActive) { + if (this.flags & AccelerometerFlag.X) + this.runtime.environmentGlobals[pxsim.localization.lf("acceleration.x")] = this.sample.x; + if (this.flags & AccelerometerFlag.Y) + this.runtime.environmentGlobals[pxsim.localization.lf("acceleration.y")] = this.sample.y; + if (this.flags & AccelerometerFlag.Z) + this.runtime.environmentGlobals[pxsim.localization.lf("acceleration.z")] = this.sample.z; + if (this.flags & AccelerometerFlag.Strength) + this.runtime.environmentGlobals[pxsim.localization.lf("acceleration.strength")] = Math.sqrt(this.instantaneousAccelerationSquared()); + if (this.flags & AccelerometerFlag.Pitch) + this.runtime.environmentGlobals[pxsim.localization.lf("acceleration.pitch")] = this.getPitch(); + if (this.flags & AccelerometerFlag.Roll) + this.runtime.environmentGlobals[pxsim.localization.lf("acceleration.roll")] = this.getRoll(); + } + } + + private instantaneousAccelerationSquared() { // Use pythagoras theorem to determine the combined force acting on the device. return this.sample.x * this.sample.x + this.sample.y * this.sample.y + this.sample.z * this.sample.z; } @@ -294,7 +317,6 @@ namespace pxsim { * @endcode */ public getX(system: MicroBitCoordinateSystem = MicroBitCoordinateSystem.SIMPLE_CARTESIAN): number { - this.activate(); switch (system) { case MicroBitCoordinateSystem.SIMPLE_CARTESIAN: return -this.sample.x; @@ -319,7 +341,6 @@ namespace pxsim { * @endcode */ public getY(system: MicroBitCoordinateSystem = MicroBitCoordinateSystem.SIMPLE_CARTESIAN): number { - this.activate(); switch (system) { case MicroBitCoordinateSystem.SIMPLE_CARTESIAN: return -this.sample.y; @@ -344,7 +365,6 @@ namespace pxsim { * @endcode */ public getZ(system: MicroBitCoordinateSystem = MicroBitCoordinateSystem.SIMPLE_CARTESIAN): number { - this.activate(); switch (system) { case MicroBitCoordinateSystem.NORTH_EAST_DOWN: return -this.sample.z; @@ -365,7 +385,6 @@ namespace pxsim { * @endcode */ public getPitch(): number { - this.activate(); return Math.floor((360 * this.getPitchRadians()) / (2 * Math.PI)); } @@ -384,7 +403,6 @@ namespace pxsim { * @endcode */ public getRoll(): number { - this.activate(); return Math.floor((360 * this.getRollRadians()) / (2 * Math.PI)); } diff --git a/sim/state/edgeconnector.ts b/sim/state/edgeconnector.ts index e32d6c4d..f403a8bc 100644 --- a/sim/state/edgeconnector.ts +++ b/sim/state/edgeconnector.ts @@ -47,7 +47,7 @@ namespace pxsim.pins { export function setPull(pinId: number, pull: number) { let pin = getPin(pinId); if (!pin) return; - pin.pull = pull; + pin.setPull(pull); } export function analogReadPin(pinId: number): number { @@ -61,7 +61,7 @@ namespace pxsim.pins { let pin = getPin(pinId); if (!pin) return; pin.mode = PinFlags.Analog | PinFlags.Output; - pin.value = value ? value : 0; + pin.value = value | 0; runtime.queueDisplayUpdate(); } @@ -101,22 +101,38 @@ namespace pxsim.pins { pin.pitch = true; } + export function analogSetPitchVolume(volume: number) { + const ec = board().edgeConnectorState; + ec.pitchVolume = Math.max(0, Math.min(0xff, volume | 0)); + } + + export function analogPitchVolume() { + const ec = board().edgeConnectorState; + return ec.pitchVolume; + } + export function analogPitch(frequency: number, ms: number) { // update analog output - let pins = board().edgeConnectorState.pins; - let pin = pins.filter(pin => !!pin && pin.pitch)[0] || pins[0]; + const b = board(); + if (!b) return; + const ec = b.edgeConnectorState; + const pins = ec.pins; + const pin = pins.filter(pin => !!pin && pin.pitch)[0] || pins[0]; + const pitchVolume = ec.pitchVolume | 0; pin.mode = PinFlags.Analog | PinFlags.Output; - if (frequency <= 0) { + if (frequency <= 0 || pitchVolume <= 0) { pin.value = 0; pin.period = 0; } else { - pin.value = 512; + const v = 1 << (pitchVolume >> 5); + pin.value = v; pin.period = 1000000 / frequency; } runtime.queueDisplayUpdate(); let cb = getResume(); - AudioContextManager.tone(frequency, 1); + const v = pitchVolume / 0xff; + AudioContextManager.tone(frequency, v); if (ms <= 0) cb(); else { setTimeout(() => { @@ -129,4 +145,11 @@ namespace pxsim.pins { }, ms); } } + + export function pushButton(pinId: number) { + const b = board(); + if (!b) return; + const ec = b.edgeConnectorState; + // TODO support buttons here + } } \ No newline at end of file diff --git a/sim/state/edgeconnectorsim.ts b/sim/state/edgeconnectorsim.ts index b136fbd7..55944245 100644 --- a/sim/state/edgeconnectorsim.ts +++ b/sim/state/edgeconnectorsim.ts @@ -86,9 +86,11 @@ namespace pxsim { export class EdgeConnectorState { pins: Pin[]; + pitchVolume: number; constructor(public props: EdgeConnectorProps) { this.pins = props.pins.map(id => id != undefined ? new Pin(id) : null); + this.pitchVolume = 0xff } public getPin(id: number) { diff --git a/sim/state/ledmatrix.ts b/sim/state/ledmatrix.ts index 7fa1eaa9..7822e8be 100644 --- a/sim/state/ledmatrix.ts +++ b/sim/state/ledmatrix.ts @@ -19,51 +19,52 @@ namespace pxsim { } export class Image extends RefObject { - public static height: number = 5; + public height: number; public width: number; public data: number[]; constructor(width: number, data: number[]) { super(); this.width = width; this.data = data; + this.height = (this.data.length / this.width) | 0; } public print() { - console.debug(`Image id:${this.id} size:${this.width}x${Image.height}`) + console.debug(`Image id:${this.id} size:${this.width}x${this.height}`) } public get(x: number, y: number): number { - x = x >> 0; - y = y >> 0; - if (x < 0 || x >= this.width || y < 0 || y >= 5) return 0; + x = x | 0; + y = y | 0; + if (x < 0 || x >= this.width || y < 0 || y >= this.height) return 0; return this.data[y * this.width + x]; } public set(x: number, y: number, v: number) { - x = x >> 0; - y = y >> 0; - if (x < 0 || x >= this.width || y < 0 || y >= 5) return; + x = x | 0; + y = y | 0; + if (x < 0 || x >= this.width || y < 0 || y >= this.height) return; this.data[y * this.width + x] = Math.max(0, Math.min(255, v)); } public copyTo(xSrcIndex: number, length: number, target: Image, xTargetIndex: number): void { - xSrcIndex = xSrcIndex >> 0; - length = length >> 0; - xTargetIndex = xTargetIndex >> 0; + xSrcIndex = xSrcIndex | 0; + length = length | 0; + xTargetIndex = xTargetIndex | 0; for (let x = 0; x < length; x++) { - for (let y = 0; y < 5; y++) { + for (let y = 0; y < this.height; y++) { let value = this.get(xSrcIndex + x, y); target.set(xTargetIndex + x, y, value); } } } public shiftLeft(cols: number) { - cols = cols >> 0; + cols = cols | 0; for (let x = 0; x < this.width; ++x) - for (let y = 0; y < 5; ++y) + for (let y = 0; y < this.height; ++y) this.set(x, y, x < this.width - cols ? this.get(x + cols, y) : 0); } public shiftRight(cols: number) { cols = cols >> 0; for (let x = this.width - 1; x >= 0; --x) - for (let y = 0; y < 5; ++y) + for (let y = 0; y < this.height; ++y) this.set(x, y, x >= cols ? this.get(x - cols, y) : 0); } @@ -85,7 +86,7 @@ namespace pxsim { } export function createImageFromBuffer(data: number[]): Image { - return new Image(data.length / 5, data); + return new Image((data.length / 5) | 0, data); } export function createImageFromString(text: string): Image { @@ -110,15 +111,14 @@ namespace pxsim { return sprite; } + export const FONT_DATA = [0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x0, 0x8, 0xa, 0x4a, 0x40, 0x0, 0x0, 0xa, 0x5f, 0xea, 0x5f, 0xea, 0xe, 0xd9, 0x2e, 0xd3, 0x6e, 0x19, 0x32, 0x44, 0x89, 0x33, 0xc, 0x92, 0x4c, 0x92, 0x4d, 0x8, 0x8, 0x0, 0x0, 0x0, 0x4, 0x88, 0x8, 0x8, 0x4, 0x8, 0x4, 0x84, 0x84, 0x88, 0x0, 0xa, 0x44, 0x8a, 0x40, 0x0, 0x4, 0x8e, 0xc4, 0x80, 0x0, 0x0, 0x0, 0x4, 0x88, 0x0, 0x0, 0xe, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, 0x22, 0x44, 0x88, 0x10, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x4, 0x8c, 0x84, 0x84, 0x8e, 0x1c, 0x82, 0x4c, 0x90, 0x1e, 0x1e, 0xc2, 0x44, 0x92, 0x4c, 0x6, 0xca, 0x52, 0x5f, 0xe2, 0x1f, 0xf0, 0x1e, 0xc1, 0x3e, 0x2, 0x44, 0x8e, 0xd1, 0x2e, 0x1f, 0xe2, 0x44, 0x88, 0x10, 0xe, 0xd1, 0x2e, 0xd1, 0x2e, 0xe, 0xd1, 0x2e, 0xc4, 0x88, 0x0, 0x8, 0x0, 0x8, 0x0, 0x0, 0x4, 0x80, 0x4, 0x88, 0x2, 0x44, 0x88, 0x4, 0x82, 0x0, 0xe, 0xc0, 0xe, 0xc0, 0x8, 0x4, 0x82, 0x44, 0x88, 0xe, 0xd1, 0x26, 0xc0, 0x4, 0xe, 0xd1, 0x35, 0xb3, 0x6c, 0xc, 0x92, 0x5e, 0xd2, 0x52, 0x1c, 0x92, 0x5c, 0x92, 0x5c, 0xe, 0xd0, 0x10, 0x10, 0xe, 0x1c, 0x92, 0x52, 0x52, 0x5c, 0x1e, 0xd0, 0x1c, 0x90, 0x1e, 0x1e, 0xd0, 0x1c, 0x90, 0x10, 0xe, 0xd0, 0x13, 0x71, 0x2e, 0x12, 0x52, 0x5e, 0xd2, 0x52, 0x1c, 0x88, 0x8, 0x8, 0x1c, 0x1f, 0xe2, 0x42, 0x52, 0x4c, 0x12, 0x54, 0x98, 0x14, 0x92, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x11, 0x3b, 0x75, 0xb1, 0x31, 0x11, 0x39, 0x35, 0xb3, 0x71, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x1c, 0x92, 0x5c, 0x90, 0x10, 0xc, 0x92, 0x52, 0x4c, 0x86, 0x1c, 0x92, 0x5c, 0x92, 0x51, 0xe, 0xd0, 0xc, 0x82, 0x5c, 0x1f, 0xe4, 0x84, 0x84, 0x84, 0x12, 0x52, 0x52, 0x52, 0x4c, 0x11, 0x31, 0x31, 0x2a, 0x44, 0x11, 0x31, 0x35, 0xbb, 0x71, 0x12, 0x52, 0x4c, 0x92, 0x52, 0x11, 0x2a, 0x44, 0x84, 0x84, 0x1e, 0xc4, 0x88, 0x10, 0x1e, 0xe, 0xc8, 0x8, 0x8, 0xe, 0x10, 0x8, 0x4, 0x82, 0x41, 0xe, 0xc2, 0x42, 0x42, 0x4e, 0x4, 0x8a, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x8, 0x4, 0x80, 0x0, 0x0, 0x0, 0xe, 0xd2, 0x52, 0x4f, 0x10, 0x10, 0x1c, 0x92, 0x5c, 0x0, 0xe, 0xd0, 0x10, 0xe, 0x2, 0x42, 0x4e, 0xd2, 0x4e, 0xc, 0x92, 0x5c, 0x90, 0xe, 0x6, 0xc8, 0x1c, 0x88, 0x8, 0xe, 0xd2, 0x4e, 0xc2, 0x4c, 0x10, 0x10, 0x1c, 0x92, 0x52, 0x8, 0x0, 0x8, 0x8, 0x8, 0x2, 0x40, 0x2, 0x42, 0x4c, 0x10, 0x14, 0x98, 0x14, 0x92, 0x8, 0x8, 0x8, 0x8, 0x6, 0x0, 0x1b, 0x75, 0xb1, 0x31, 0x0, 0x1c, 0x92, 0x52, 0x52, 0x0, 0xc, 0x92, 0x52, 0x4c, 0x0, 0x1c, 0x92, 0x5c, 0x90, 0x0, 0xe, 0xd2, 0x4e, 0xc2, 0x0, 0xe, 0xd0, 0x10, 0x10, 0x0, 0x6, 0xc8, 0x4, 0x98, 0x8, 0x8, 0xe, 0xc8, 0x7, 0x0, 0x12, 0x52, 0x52, 0x4f, 0x0, 0x11, 0x31, 0x2a, 0x44, 0x0, 0x11, 0x31, 0x35, 0xbb, 0x0, 0x12, 0x4c, 0x8c, 0x92, 0x0, 0x11, 0x2a, 0x44, 0x98, 0x0, 0x1e, 0xc4, 0x88, 0x1e, 0x6, 0xc4, 0x8c, 0x84, 0x86, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0xc, 0x88, 0x18, 0x0, 0x0, 0xc, 0x83, 0x60]; export function createFont(): Image { - const data = [0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x0, 0x8, 0xa, 0x4a, 0x40, 0x0, 0x0, 0xa, 0x5f, 0xea, 0x5f, 0xea, 0xe, 0xd9, 0x2e, 0xd3, 0x6e, 0x19, 0x32, 0x44, 0x89, 0x33, 0xc, 0x92, 0x4c, 0x92, 0x4d, 0x8, 0x8, 0x0, 0x0, 0x0, 0x4, 0x88, 0x8, 0x8, 0x4, 0x8, 0x4, 0x84, 0x84, 0x88, 0x0, 0xa, 0x44, 0x8a, 0x40, 0x0, 0x4, 0x8e, 0xc4, 0x80, 0x0, 0x0, 0x0, 0x4, 0x88, 0x0, 0x0, 0xe, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, 0x22, 0x44, 0x88, 0x10, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x4, 0x8c, 0x84, 0x84, 0x8e, 0x1c, 0x82, 0x4c, 0x90, 0x1e, 0x1e, 0xc2, 0x44, 0x92, 0x4c, 0x6, 0xca, 0x52, 0x5f, 0xe2, 0x1f, 0xf0, 0x1e, 0xc1, 0x3e, 0x2, 0x44, 0x8e, 0xd1, 0x2e, 0x1f, 0xe2, 0x44, 0x88, 0x10, 0xe, 0xd1, 0x2e, 0xd1, 0x2e, 0xe, 0xd1, 0x2e, 0xc4, 0x88, 0x0, 0x8, 0x0, 0x8, 0x0, 0x0, 0x4, 0x80, 0x4, 0x88, 0x2, 0x44, 0x88, 0x4, 0x82, 0x0, 0xe, 0xc0, 0xe, 0xc0, 0x8, 0x4, 0x82, 0x44, 0x88, 0xe, 0xd1, 0x26, 0xc0, 0x4, 0xe, 0xd1, 0x35, 0xb3, 0x6c, 0xc, 0x92, 0x5e, 0xd2, 0x52, 0x1c, 0x92, 0x5c, 0x92, 0x5c, 0xe, 0xd0, 0x10, 0x10, 0xe, 0x1c, 0x92, 0x52, 0x52, 0x5c, 0x1e, 0xd0, 0x1c, 0x90, 0x1e, 0x1e, 0xd0, 0x1c, 0x90, 0x10, 0xe, 0xd0, 0x13, 0x71, 0x2e, 0x12, 0x52, 0x5e, 0xd2, 0x52, 0x1c, 0x88, 0x8, 0x8, 0x1c, 0x1f, 0xe2, 0x42, 0x52, 0x4c, 0x12, 0x54, 0x98, 0x14, 0x92, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x11, 0x3b, 0x75, 0xb1, 0x31, 0x11, 0x39, 0x35, 0xb3, 0x71, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x1c, 0x92, 0x5c, 0x90, 0x10, 0xc, 0x92, 0x52, 0x4c, 0x86, 0x1c, 0x92, 0x5c, 0x92, 0x51, 0xe, 0xd0, 0xc, 0x82, 0x5c, 0x1f, 0xe4, 0x84, 0x84, 0x84, 0x12, 0x52, 0x52, 0x52, 0x4c, 0x11, 0x31, 0x31, 0x2a, 0x44, 0x11, 0x31, 0x35, 0xbb, 0x71, 0x12, 0x52, 0x4c, 0x92, 0x52, 0x11, 0x2a, 0x44, 0x84, 0x84, 0x1e, 0xc4, 0x88, 0x10, 0x1e, 0xe, 0xc8, 0x8, 0x8, 0xe, 0x10, 0x8, 0x4, 0x82, 0x41, 0xe, 0xc2, 0x42, 0x42, 0x4e, 0x4, 0x8a, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x8, 0x4, 0x80, 0x0, 0x0, 0x0, 0xe, 0xd2, 0x52, 0x4f, 0x10, 0x10, 0x1c, 0x92, 0x5c, 0x0, 0xe, 0xd0, 0x10, 0xe, 0x2, 0x42, 0x4e, 0xd2, 0x4e, 0xc, 0x92, 0x5c, 0x90, 0xe, 0x6, 0xc8, 0x1c, 0x88, 0x8, 0xe, 0xd2, 0x4e, 0xc2, 0x4c, 0x10, 0x10, 0x1c, 0x92, 0x52, 0x8, 0x0, 0x8, 0x8, 0x8, 0x2, 0x40, 0x2, 0x42, 0x4c, 0x10, 0x14, 0x98, 0x14, 0x92, 0x8, 0x8, 0x8, 0x8, 0x6, 0x0, 0x1b, 0x75, 0xb1, 0x31, 0x0, 0x1c, 0x92, 0x52, 0x52, 0x0, 0xc, 0x92, 0x52, 0x4c, 0x0, 0x1c, 0x92, 0x5c, 0x90, 0x0, 0xe, 0xd2, 0x4e, 0xc2, 0x0, 0xe, 0xd0, 0x10, 0x10, 0x0, 0x6, 0xc8, 0x4, 0x98, 0x8, 0x8, 0xe, 0xc8, 0x7, 0x0, 0x12, 0x52, 0x52, 0x4f, 0x0, 0x11, 0x31, 0x2a, 0x44, 0x0, 0x11, 0x31, 0x35, 0xbb, 0x0, 0x12, 0x4c, 0x8c, 0x92, 0x0, 0x11, 0x2a, 0x44, 0x98, 0x0, 0x1e, 0xc4, 0x88, 0x1e, 0x6, 0xc4, 0x8c, 0x84, 0x86, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0xc, 0x88, 0x18, 0x0, 0x0, 0xc, 0x83, 0x60]; - - let nb = data.length; + let nb = FONT_DATA.length; let n = nb / 5; let font = createInternalImage(nb); for (let c = 0; c < n; c++) { for (let row = 0; row < 5; row++) { - let char = data[c * 5 + row]; + let char = FONT_DATA[c * 5 + row]; for (let col = 0; col < 5; col++) { if ((char & (1 << col)) != 0) font.set((c * 5 + 4) - col, row, 255); @@ -129,6 +129,24 @@ namespace pxsim { } } +namespace pxsim.fonts { + export function charCodeBuffer(charCode: number): RefBuffer { + if (charCode < DAL.MICROBIT_FONT_ASCII_START || charCode > DAL.MICROBIT_FONT_ASCII_END) + return undefined; + + const b = board(); + const led = b.ledMatrixState; + const font = led.font; + const h = font.height; + const w = font.width; + const buf = control.createBuffer(h); + const offset = (charCode - DAL.MICROBIT_FONT_ASCII_START) * h; + for (let row = 0; row < h; ++row) + buf.data[row] = FONT_DATA[offset + row]; + return buf; + } +} + namespace pxsim.images { export function createImage(img: Image) { return img @@ -177,7 +195,7 @@ namespace pxsim.ImageMethods { export function height(leds: Image): number { pxtrt.nullCheck(leds) - return Image.height; + return leds.height; } export function width(leds: Image): number { @@ -186,11 +204,11 @@ namespace pxsim.ImageMethods { } export function plotFrame(leds: Image, frame: number) { - ImageMethods.plotImage(leds, frame * Image.height); + ImageMethods.plotImage(leds, frame * leds.height); } export function showFrame(leds: Image, frame: number, interval: number) { - ImageMethods.showImage(leds, frame * Image.height, interval); + ImageMethods.showImage(leds, frame * leds.height, interval); } export function pixel(leds: Image, x: number, y: number): number { @@ -268,7 +286,7 @@ namespace pxsim.ImageMethods { namespace pxsim.basic { export function showNumber(x: number, interval: number) { - interval = interval >> 0; + interval |= 0; if (interval <= 0) interval = 1; let leds = createImageFromString(x.toString()); @@ -277,7 +295,7 @@ namespace pxsim.basic { } export function showString(s: string, interval: number) { - interval = interval >> 0; + interval |= 0; if (interval <= 0) interval = 1; if (s.length == 0) { @@ -291,6 +309,7 @@ namespace pxsim.basic { } export function showLeds(leds: Image, interval: number): void { + interval |= 0; showAnimation(leds, interval); } @@ -300,6 +319,7 @@ namespace pxsim.basic { } export function showAnimation(leds: Image, interval: number): void { + interval |= 0; ImageMethods.scrollImage(leds, 5, interval); } @@ -310,13 +330,17 @@ namespace pxsim.basic { namespace pxsim.led { export function plot(x: number, y: number) { + x |= 0; + y |= 0; board().ledMatrixState.image.set(x, y, 0xff); runtime.queueDisplayUpdate() } export function plotBrightness(x: number, y: number, brightness: number) { + x |= 0; + y |= 0; const state = board().ledMatrixState; - brightness = brightness >> 0; + brightness |= 0; brightness = Math.max(0, Math.min(led.brightness(), brightness)); if (brightness != 0 && brightness != 0xff && state.displayMode != DisplayMode.greyscale) state.displayMode = DisplayMode.greyscale; @@ -325,12 +349,16 @@ namespace pxsim.led { } export function unplot(x: number, y: number) { + x |= 0; + y |= 0; board().ledMatrixState.image.set(x, y, 0); runtime.queueDisplayUpdate() } - export function point(x: number, y: number): boolean { - return !!board().ledMatrixState.image.get(x, y); + export function pointBrightness(x: number, y: number): number { + x |= 0; + y |= 0; + return board().ledMatrixState.image.get(x, y); } export function brightness(): number { @@ -338,7 +366,7 @@ namespace pxsim.led { } export function setBrightness(value: number): void { - value = value >> 0; + value |= 0; board().ledMatrixState.brigthness = Math.max(0, Math.min(255, value)); runtime.queueDisplayUpdate() } diff --git a/sim/state/misc.ts b/sim/state/misc.ts index d672b190..74063b9a 100644 --- a/sim/state/misc.ts +++ b/sim/state/misc.ts @@ -136,6 +136,10 @@ namespace pxsim.pins { return 0; } + export function spiTransfer(cmd: RefBuffer, resp: RefBuffer): void { + // TODO + } + export function spiFrequency(f: number): void { // TODO } @@ -219,7 +223,7 @@ namespace pxsim.bluetooth { } export function uartReadBuffer(): RefBuffer { - return pins.createBuffer(0); + return pins.createBuffer(0); } export function uartReadUntil(del: string): string { @@ -241,3 +245,14 @@ namespace pxsim.bluetooth { export function setTransmitPower(power: number) { } } +namespace pxsim.light { + export function sendWS2812Buffer(buffer: RefBuffer, pin: number) { + pxsim.sendBufferAsm(buffer, pin) + } + + export function setMode(pin: number, mode: number) { + const lp = neopixelState(pin); + if (!lp) return; + lp.mode = mode & 0xff; + } +} diff --git a/sim/state/neopixel.ts b/sim/state/neopixel.ts deleted file mode 100644 index e57f9a9b..00000000 --- a/sim/state/neopixel.ts +++ /dev/null @@ -1,13 +0,0 @@ -namespace pxsim { - export function sendBufferAsm(buffer: RefBuffer, pin: DigitalPin) { - let b = board(); - if (b) { - let np = b.neopixelState; - if (np) { - let buf = buffer.data; - np.updateBuffer(buf as any, pin); // TODO this is wrong - runtime.queueDisplayUpdate(); - } - } - } -} diff --git a/sim/state/serial.ts b/sim/state/serial.ts index 897436cf..31cedecf 100644 --- a/sim/state/serial.ts +++ b/sim/state/serial.ts @@ -73,8 +73,13 @@ namespace pxsim.serial { } export function readBuffer(length: number) { + length |= 0; if (length <= 0) length = 64; return pins.createBuffer(length); } + + export function setBaudRate(rate: number) { + // TODO + } } \ No newline at end of file diff --git a/sim/tsconfig.json b/sim/tsconfig.json index 2fa70fa6..ba44bb72 100644 --- a/sim/tsconfig.json +++ b/sim/tsconfig.json @@ -16,6 +16,8 @@ "*.ts", "state/*.ts", "visuals/*.ts", + "../node_modules/pxt-common-packages/libs/core/sim/analogSensor.ts", + "../node_modules/pxt-common-packages/libs/core/sim/neopixel.ts", "../node_modules/pxt-common-packages/libs/radio/sim/*.ts" ] } diff --git a/sim/visuals/boardview.ts b/sim/visuals/boardview.ts index 2c09405a..9a7bee81 100644 --- a/sim/visuals/boardview.ts +++ b/sim/visuals/boardview.ts @@ -3,8 +3,7 @@ namespace pxsim.visuals { return new visuals.MicrobitBoardSvg({ runtime: runtime, theme: visuals.randomTheme(), - disableTilt: false, - wireframe: opts.wireframe, + wireframe: opts.wireframe }); } -} +} \ No newline at end of file diff --git a/sim/visuals/microbit.ts b/sim/visuals/microbit.ts index f7e1fa7b..f1c76eb2 100644 --- a/sim/visuals/microbit.ts +++ b/sim/visuals/microbit.ts @@ -140,9 +140,31 @@ namespace pxsim.visuals { stroke: none; fill: #777; } + .sim-label, .sim-button-label { + fill: #000; + } .sim-wireframe .sim-board { stroke-width: 2px; } + *:focus { + outline: none; + } + *:focus .sim-button-outer, + .sim-pin:focus, + .sim-thermometer:focus, + .sim-shake:focus, + .sim-light-level-button:focus { + stroke: #4D90FE; + stroke-width: 5px !important; + } + .no-drag, .sim-text, .sim-text-pin { + user-drag: none; + user-select: none; + -moz-user-select: none; + -webkit-user-drag: none; + -webkit-user-select: none; + -ms-user-select: none; + } `; const BOARD_SVG = ` svg.setGradientColors(lg, theme.pin, theme.pinActive)); svg.setGradientColors(this.lightLevelGradient, theme.lightLevelOn, theme.lightLevelOff); @@ -1031,6 +1055,7 @@ namespace pxsim.visuals { this.updateGestures(); this.updateRgbLed(); this.updateSpeaker(); + this.updateRSSI(); if (!runtime || runtime.dead) U.addClass(this.element, "grayscale"); else U.removeClass(this.element, "grayscale"); @@ -1092,6 +1117,33 @@ namespace pxsim.visuals { } } + private updateRSSI() { + let state = this.board; + if (!state) return; + const v = state.radioState.datagram.rssi; + if (v === undefined) return; + + if (!this.rssi) { + let ax = 380; + let dax = 18; + let ayt = 10; + let ayb = 40; + const wh = dax * 5; + for (let i = 0; i < 4; ++i) + svg.child(this.g, "rect", { x: ax - 90 + i * 6, y: ayt + 28 - i * 4, width: 4, height: 2 + i * 4, fill: "#fff" }) + this.rssi = svg.child(this.g, "text", { x: ax - 64, y: ayb, class: "sim-text" }) as SVGTextElement; + this.rssi.textContent = ""; + } + + const vt = v.toString(); + if (vt !== this.rssi.textContent) { + this.rssi.textContent = v.toString(); + this.antenna.setAttribute("aria-valuenow", this.rssi.textContent); + accessibility.setLiveContent(this.rssi.textContent); + } + } + + private updatePin(pin: Pin, index: number) { if (!pin) return; let text = this.pinTexts[pin.id]; @@ -1106,12 +1158,22 @@ namespace pxsim.visuals { } else if (pin.mode & PinFlags.Touch) { v = pin.touched ? "0%" : "100%"; - if (text) text.textContent = "TOUCHED"; + if (text) text.textContent = ""; } else { v = "100%"; - if (text) text.textContent = "unused"; + if (text) text.textContent = ""; } if (v) svg.setGradientValue(this.pinGradients[index], v); + + if (pin.mode !== PinFlags.Unused) { + accessibility.makeFocusable(this.pins[index]); + accessibility.setAria(this.pins[index], "slider", this.pins[index].firstChild.textContent); + this.pins[index].setAttribute("aria-valuemin", "0"); + this.pins[index].setAttribute("aria-valuemax", pin.mode & PinFlags.Analog ? "1023" : "100"); + this.pins[index].setAttribute("aria-orientation", "vertical"); + this.pins[index].setAttribute("aria-valuenow", text ? text.textContent : v); + accessibility.setLiveContent(text ? text.textContent : v); + } } private updateTemperature() { diff --git a/sim/visuals/neopixel.ts b/sim/visuals/neopixel.ts deleted file mode 100644 index 68b2916d..00000000 --- a/sim/visuals/neopixel.ts +++ /dev/null @@ -1,242 +0,0 @@ -/// -/// -/// - -namespace pxsim.visuals { - const PIXEL_SPACING = PIN_DIST * 3; - const PIXEL_RADIUS = PIN_DIST; - const CANVAS_WIDTH = 1.2 * PIN_DIST; - const CANVAS_HEIGHT = 12 * PIN_DIST; - const CANVAS_VIEW_WIDTH = CANVAS_WIDTH; - const CANVAS_VIEW_HEIGHT = CANVAS_HEIGHT; - const CANVAS_VIEW_PADDING = PIN_DIST * 4; - const CANVAS_LEFT = 1.4 * PIN_DIST; - const CANVAS_TOP = PIN_DIST; - - // For the instructions parts list - export function mkNeoPixelPart(xy: Coord = [0, 0]): SVGElAndSize { - const NP_PART_XOFF = -13.5; - const NP_PART_YOFF = -11; - const NP_PART_WIDTH = 87.5; - const NP_PART_HEIGHT = 190; - const NEOPIXEL_PART_IMG = ` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -`; - let [x, y] = xy; - let l = x + NP_PART_XOFF; - let t = y + NP_PART_YOFF; - let w = NP_PART_WIDTH; - let h = NP_PART_HEIGHT; - let img = svg.elt("image"); - svg.hydrate(img, { - class: "sim-neopixel-strip", x: l, y: t, width: w, height: h, - href: svg.toDataUri(NEOPIXEL_PART_IMG) - }); - return { el: img, x: l, y: t, w: w, h: h }; - } - export class NeoPixel { - public el: SVGElement; - public cy: number; - - constructor(xy: Coord = [0, 0]) { - let el = svg.elt("rect"); - let r = PIXEL_RADIUS; - let [cx, cy] = xy; - let y = cy - r; - svg.hydrate(el, { x: "-50%", y: y, width: "100%", height: r * 2, class: "sim-neopixel" }); - this.el = el; - this.cy = cy; - } - - public setRgb(rgb: [number, number, number]) { - let hsl = visuals.rgbToHsl(rgb); - let [h, s, l] = hsl; - // at least 70% luminosity - l = Math.max(l, 60); - let fill = `hsl(${h}, ${s}%, ${l}%)`; - this.el.setAttribute("fill", fill); - } - } - - export class NeoPixelCanvas { - public canvas: SVGSVGElement; - public pin: number; - public pixels: NeoPixel[]; - private viewBox: [number, number, number, number]; - private background: SVGRectElement; - - constructor(pin: number) { - this.pixels = []; - this.pin = pin; - let el = svg.elt("svg"); - svg.hydrate(el, { - "class": `sim-neopixel-canvas`, - "x": "0px", - "y": "0px", - "width": `${CANVAS_WIDTH}px`, - "height": `${CANVAS_HEIGHT}px`, - }); - this.canvas = el; - this.background = svg.child(el, "rect", { class: "sim-neopixel-background hidden" }); - this.updateViewBox(-CANVAS_VIEW_WIDTH / 2, 0, CANVAS_VIEW_WIDTH, CANVAS_VIEW_HEIGHT); - } - - private updateViewBox(x: number, y: number, w: number, h: number) { - this.viewBox = [x, y, w, h]; - svg.hydrate(this.canvas, { "viewBox": `${x} ${y} ${w} ${h}` }); - svg.hydrate(this.background, { "x": x, "y": y, "width": w, "height": h }); - } - - public update(colors: RGBW[]) { - if (!colors || colors.length <= 0) - return; - - for (let i = 0; i < colors.length; i++) { - let pixel = this.pixels[i]; - if (!pixel) { - let cxy: Coord = [0, CANVAS_VIEW_PADDING + i * PIXEL_SPACING]; - pixel = this.pixels[i] = new NeoPixel(cxy); - svg.hydrate(pixel.el, { title: `offset: ${i}` }); - this.canvas.appendChild(pixel.el); - } - let color = colors[i]; - pixel.setRgb([color[0], color[1], color[2]]); - } - - //show the canvas if it's hidden - U.removeClass(this.background, "hidden"); - - //resize if necessary - let [first, last] = [this.pixels[0], this.pixels[this.pixels.length - 1]] - let yDiff = last.cy - first.cy; - let newH = yDiff + CANVAS_VIEW_PADDING * 2; - let [oldX, oldY, oldW, oldH] = this.viewBox; - if (oldH < newH) { - let scalar = newH / oldH; - let newW = oldW * scalar; - this.updateViewBox(-newW / 2, oldY, newW, newH); - } - } - - public setLoc(xy: Coord) { - let [x, y] = xy; - svg.hydrate(this.canvas, { x: x, y: y }); - } - }; - - function digitalPinToPinNumber(gpioPin: string): number { - const MICROBIT_ID_IO_P0 = 7; //TODO: don't hardcode this, import enums.d.ts - if (gpioPin == "*") { - return MICROBIT_ID_IO_P0; - } - let pinSplit = gpioPin.split("DigitalPin.P"); - U.assert(pinSplit.length === 2, "Unknown format for pin (for NeoPixel): " + gpioPin); - let pinNumStr = pinSplit[1]; - let pinNum = Number(pinNumStr) + MICROBIT_ID_IO_P0; - return pinNum - } - function parseNeoPixelMode(modeStr: string): NeoPixelMode { - const modeMap: Map = { - "NeoPixelMode.RGB": NeoPixelMode.RGB, - "NeoPixelMode.RGBW": NeoPixelMode.RGBW - }; - return modeMap[modeStr] || NeoPixelMode.RGB; - } - - export class NeoPixelView implements IBoardPart { - public style: string = ` - .sim-neopixel-canvas { - } - .sim-neopixel-canvas-parent:hover { - transform-origin: center; - transform: scale(4) translateY(-60px); - -moz-transform: scale(4) translateY(-220px); - } - .sim-neopixel-canvas .hidden { - visibility:hidden; - } - .sim-neopixel-background { - fill: rgba(255,255,255,0.9); - } - .sim-neopixel-strip { - } - `; - public element: SVGElement; - public overElement: SVGElement; - public defs: SVGElement[]; - private state: NeoPixelState; - private canvas: NeoPixelCanvas; - private part: SVGElAndSize; - private stripGroup: SVGGElement; - private lastLocation: Coord; - private pin: number; - private mode: NeoPixelMode; - - public init(bus: EventBus, state: NeoPixelState, svgEl: SVGSVGElement, otherParams: Map): void { - U.assert(!!otherParams["mode"], "NeoPixels assumes a RGB vs RGBW mode is passed to it"); - U.assert(!!otherParams["pin"], "NeoPixels assumes a pin is passed to it"); - let modeStr = otherParams["mode"]; - this.mode = parseNeoPixelMode(modeStr); - this.state = state; - this.stripGroup = svg.elt("g"); - this.element = this.stripGroup; - let pinStr = otherParams["pin"]; - this.pin = digitalPinToPinNumber(pinStr); - this.lastLocation = [0, 0]; - let part = mkNeoPixelPart(); - this.part = part; - this.stripGroup.appendChild(part.el); - let canvas = new NeoPixelCanvas(this.pin); - this.canvas = canvas; - let canvasG = svg.elt("g", { class: "sim-neopixel-canvas-parent" }); - this.overElement = canvasG; - canvasG.appendChild(canvas.canvas); - this.updateStripLoc(); - } - public moveToCoord(xy: Coord): void { - let [x, y] = xy; - let loc: Coord = [x, y]; - this.lastLocation = loc; - this.updateStripLoc(); - } - private updateStripLoc() { - let [x, y] = this.lastLocation; - U.assert(typeof x === "number" && typeof y === "number", "invalid x,y for NeoPixel strip"); - this.canvas.setLoc([x + CANVAS_LEFT, y + CANVAS_TOP]); - svg.hydrate(this.part.el, { transform: `translate(${x} ${y})` }); //TODO: update part's l,h, etc. - } - public updateState(): void { - let colors = this.state.getColors(this.pin, this.mode); - this.canvas.update(colors); - } - public updateTheme(): void { } - } -} diff --git a/webmanifest.json b/webmanifest.json index 68b81b56..71bd8f72 100644 --- a/webmanifest.json +++ b/webmanifest.json @@ -1,5 +1,5 @@ { - "name": "makecode.microbit.org", + "name": "makecode.calliope.cc", "display": "fullscreen", "orientation": "portrait", "icons": [ @@ -53,7 +53,7 @@ "related_applications": [ { "platform": "play", - "id": "com.samsung.microbit" + "id": "cc.calliope.mini" } ] } \ No newline at end of file