V4 updates for beta testing (#147)

* change simulator svg

* change radio image

* Remove google fonts cdn

* change color of 'advanced' button

* font fix

* font fix 2

* display fix

* change fullsceen simulator bg

* Continuous servo

* handle continuous state

* adding shims

* update rendering for continuous servos

* fixing sim

* fix sig

* typo

* fix sim

* bump pxt

* bump pxt

* rerun travis

* Input blocks revision

- add Button and Pin event types
- merge onPinPressed & onPinReleased in new onPinEvent function
- create new onButtonEvent function

* update input blocks in docs and tests

* remove device_pin_release block

* Hide DAL.x behind Enum

* bring back deprecated blocks, but hide them

* shims and locales files

* fix input.input. typing

* remove buildpr

* bump V3

* update simulator aspect ratio

* add Loudness Block

* revoke loudness block

* Adds soundLevel

To be replaced by pxt-common-packages when DAL is updated.

* Remove P0 & P3 from AnalogPin

* Fix Sound and replace AnalogPin.P0

* remove approved extensions

* V4 Updates from remote Repo

* locales

* add storage functions

* fix storage functions

* fix int/float values

* decrease decimal precision

* reorder blocks

* Update BLE Settings and Storage Blocks

* Fetch MicroBit changes up to v4.0.18

* Update timing for LED Matrix usage

* use 32kb ram (mini v2)

* resize gatt table

* Revert "use 32kb ram (mini v2)"

This reverts commit 4b15592f0f.

* fix missleading indentation

* add support for 32kb and 16kb ram

* only MIT extensions in preferredRepos

* remove extensions without MIT License file

* add updated extensions

* add extensions with MIT license

Co-authored-by: Juri <gitkraken@juriwolf.de>
Co-authored-by: Juri <info@juriwolf.de>
This commit is contained in:
Amerlander 2022-03-22 17:36:19 +01:00 committed by GitHub
parent d0a85fd0d2
commit 3e0c9b43a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
115 changed files with 16788 additions and 7690 deletions

8
.github/lock.yml vendored
View File

@ -30,13 +30,7 @@ lockLabel: false
# Comment to post before locking. Set to `false` to disable
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.
lockComment: false

51
.github/workflows/codeql.yml vendored Normal file
View File

@ -0,0 +1,51 @@
name: "Code scanning - action"
on:
push:
pull_request:
schedule:
- cron: '0 19 * * 0'
jobs:
CodeQL-Build:
# CodeQL runs on ubuntu-latest and windows-latest
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: javascript
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@ -1,12 +0,0 @@
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 }}

View File

@ -1,9 +1,10 @@
name: pxt-buildtarget
name: pxt-buildmain
on:
push:
branches:
- master
- 'master'
- 'main'
create:
jobs:

31
.github/workflows/pxt-buildpr.yml vendored Normal file
View File

@ -0,0 +1,31 @@
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

39
.github/workflows/pxt-buildpush.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: pxt-buildpush
on:
push:
# main/master has its own build that includes the crowdin key
branches-ignore:
- 'main'
- 'master'
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:
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

View File

@ -11,9 +11,12 @@ jobs:
strategy:
matrix:
node-version: [8.x]
branch: [stable3.0]
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
with:
ref: ${{ matrix.branch }}
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
@ -45,5 +48,5 @@ jobs:
uses: actions/upload-artifact@v2
if: ${{ always() }}
with:
name: logs
name: logs-${{ matrix.branch }}
path: temp/ghpkgs/*.txt

View File

@ -1,27 +0,0 @@
language: node_js
os: linux
dist: trusty
node_js:
- "8.9.4"
before_install:
- export CHROME_BIN=chromium-browser
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
script:
- "node node_modules/pxt-core/built/pxt.js travis"
# - "(cd libs/lang-test0; node ../../node_modules/pxt-core/built/pxt.js run)"
# - "(cd libs/lang-test1; node ../../node_modules/pxt-core/built/pxt.js run)"
# - "(cd libs/lang-test0; node ../../node_modules/pxt-core/built/pxt.js test)"
# - "(cd libs/lang-test1; node ../../node_modules/pxt-core/built/pxt.js test)"
# - "node node_modules/pxt-core/built/pxt.js testdir tests"
# - "(cd libs/hello; node ../../node_modules/pxt-core/built/pxt.js testconv http://az851932.vo.msecnd.net/files/td-converter-tests-v1.json)"
sudo: false
notifications:
email:
- touchdevelop-build@microsoft.com
cache:
directories:
- node_modules
- built/cache
- libs/hello/built/cache

View File

@ -1,6 +1,5 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.autoSave": "afterDelay",
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/built/**": true,

19
.vscode/tasks.json vendored
View File

@ -1,20 +1,19 @@
{
"version": "0.1.0",
"version": "2.0.0",
// Task runner is jake
"command": "pxt",
// Need to be executed in shell / cmd
"isShellCommand": true,
"showOutput": "always",
"tasks": [
{
// TS build command is local.
"taskName": "serve",
// Make this the default build command.
"isBuildCommand": true,
// Use the redefined Typescript output problem matcher.
"label": "serve",
"type": "shell",
"command": "pxt",
"args": [
"serve"
],
"problemMatcher": [
"$tsc"
]
],
"group": "build"
}
]
}

View File

@ -1,4 +1,4 @@
# micro:bit target for PXT
# calliope target for PXT

View File

@ -1,13 +0,0 @@
{
"folders": [
{
"path": "../pxt"
},
{
"path": "../pxt-common-packages"
},
{
"path": "."
}
]
}

131
compiler/combiner.ts Normal file
View File

@ -0,0 +1,131 @@
/// <reference path="../node_modules/pxt-core/built/pxtcompiler.d.ts"/>
namespace ts.pxtc.extension {
pxtc.compilerHooks.postBinary = (program: ts.Program, opts: CompileOptions, res: CompileResult) => {
if (!opts.target.isNative)
return
const mbdal = res.outfiles["mbdal-binary.hex"]
const mbcodal = res.outfiles["mbcodal-binary.hex"]
if (!mbdal || !mbcodal)
return
let outp = ""
wrapHex(mbdal, 0x00, [0x99, 0x01, 0xc0, 0xde])
wrapHex(mbcodal, 0x0D, [0x99, 0x03, 0xc0, 0xde], true)
outp += ":00000001FF\n"
res.outfiles["binary.hex"] = outp
function hex2str(bytes: number[]) {
return ts.pxtc.hexfile.hexBytes([bytes.length - 3].concat(bytes)) + "\n"
}
function paddingString(len: number) {
let r = ""
const len0 = len
while (len >= 44) {
r += hex2str([0x00, 0x00, 0x0C,
0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42])
len -= 44
}
if (len >= 12) {
const numBytes = (len - 11) >> 1
const bytes = [0x00, 0x00, 0x0C]
for (let i = 0; i < numBytes; ++i) bytes.push(0x42)
const add = hex2str(bytes)
r += add
len -= add.length
}
while (len--)
r += "\n"
U.assert(r.length == len0)
return r
}
function addBlock(blk: string) {
const leftoff = blk.length & 511
outp += blk + paddingString(512 - leftoff)
}
function wrapHex(inpHex: string, dataType: number, deviceType: number[], keepSrc = false) {
let blk =
hex2str([0x00, 0x00, 0x04, 0x00, 0x00])
+ hex2str([0x00, 0x00, 0x0A].concat(deviceType))
let upperAddr = 0
const lines = inpHex.split(/\r?\n/)
for (let i = 0; i < lines.length; ++i) {
const line = lines[i]
if (!line)
continue
const parsed = ts.pxtc.hexfile.parseHexRecord(line)
switch (parsed.type) {
case 0x00:
/*
const parsed2 = parsed.len <= 16 && lines[i + 1] ?
ts.pxtc.hexfile.parseHexRecord(lines[i + 1])
: null
// if this and next line can fit in 32 bytes, concat them
if (parsed2 && parsed2.type == 0x00 &&
parsed2.addr == parsed.addr + parsed.len &&
parsed.len + parsed2.len <= 32) {
parsed.data = parsed.data.concat(parsed2.data)
parsed.len += parsed2.len
i++
}
*/
addData([parsed.addr >> 8, parsed.addr & 0xff, dataType]
.concat(parsed.data))
break
case 0x01:
flush()
if (keepSrc) break
else return
case 0x04:
const newUpper = ((parsed.data[0] << 8) | parsed.data[1]) << 16
if (upperAddr != newUpper) {
upperAddr = newUpper
addData([0, 0, 0x04, parsed.data[0], parsed.data[1]])
}
break
case 0x03:
case 0x05:
// ignore
break
case 0x0E:
// src record
addData([parsed.addr >> 8, parsed.addr & 0xff, 0x0E]
.concat(parsed.data))
break
default:
U.oops(`unknown hex record type: ${line}`)
break
}
}
flush()
function addData(bytes: number[]) {
const newData = hex2str(bytes)
blk += newData
}
function flush() {
if (blk)
addBlock(blk)
blk = ""
}
}
}
}

23
compiler/tsconfig.json Normal file
View File

@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "es2017",
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"declaration": true,
"moduleResolution": "node",
"isolatedModules": false,
"out": "../built/compiler.js",
"rootDir": ".",
"newLine": "LF",
"sourceMap": false,
"typeRoots": ["../node_modules/@types"],
"lib": [
"dom",
"dom.iterable",
"scripthost",
"es2017",
"ES2018.Promise"
]
}
}

View File

@ -0,0 +1,2 @@
Micro:bit and micro:bit logo are trademarks and/ or copyrights of the Micro:bit
Educational Foundation. &copy; Micro:bit Educational Foundation. All rights reserved.

View File

@ -78,6 +78,13 @@ input.onButtonPressed(Button.B, () => {
We have tons of [projects](/projects), [examples](/examples) and [courses](/courses) to get your started!
## C++ Runtime
The [C++ micro:bit runtime](http://lancaster-university.github.io/microbit-docs/), created at [Lancaster University](http://www.lancaster.ac.uk/), provides access to the hardware functions of the micro:bit,
as well as a set of helper functions (such as displaying a number/image/string on the LED screen).
The [micro:bit library](/reference) mirrors the functions of the C++ library.
When code is compiled to ARM machine code, the calls to JavaScript micro:bit functions are replaced with calls to the corresponding C++ functions.
## [Command Line Tools](/cli)

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

21
docs/hero-banner.md Normal file
View File

@ -0,0 +1,21 @@
# Hero Banner
Here are some cool activities to get you started with your @boardname@!
## Intro Content
### ~ codecard
* name: CalliopEO
* description: CALLIOPEO Taking the Calliope mini to the ISS.
* imageUrl: /calliope/02_Hero_CalliopEO.png
* url: https://calliope.cc/calliopeo
* buttonLabel: Participate!
* cardType: link
---
* name: The 5x5 LED matrix
* description: KIDS LAB play, learn and hack!
* imageUrl: /calliope/03_Hero_KidsLab.png
* url: https://calliope.cc/programmieren/kidslab
* buttonLabel: Explore!
* cardType: link
### ~

View File

@ -6,7 +6,7 @@ Tell everyone who you are. Show you name on the LEDs.
![Name scrolling on the LEDs](/calliope/tutorials/02_nametag_animation.gif)
## Step 1 @fullscreen
## Step 1
Place the ``||basic:show string||`` block in the ``||basic:forever||`` block to repeat it. Change the text to your name.
@ -16,13 +16,12 @@ basic.forever(() => {
});
```
## Step 2 @fullscreen
## Step 2
Look at the simulator and make sure it shows your name on the screen.
![Name scrolling on the LEDs](/calliope/tutorials/02_nametag_animation.gif)
## Step 3 @fullscreen
Place more ``||basic:show string||`` blocks to create your own story.
@ -33,6 +32,6 @@ basic.forever(() => {
})
```
## Step 4 @unplugged
## Step 4
If you have a @boardname@ connected, click ``|Download|`` to transfer your code and watch your name scroll!

BIN
docs/skillmap/img/space.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

37
docs/skillmap/mini.md Normal file
View File

@ -0,0 +1,37 @@
# Build a mini Explorer
* name: Build a mini Explorer
* description: Learn to make a Galga-style game by following this short series of tutorials.
* bannerUrl: /skillmap/img/spacet4.gif
* backgroundurl: /skillmap/img/space.png
* primarycolor: #2EA9B0
* secondarycolor: #d6f7fa
* tertiarycolor: #5d416b
* highlightcolor: #FFFFFF
* completednodecolor: #504c52
* tags: beginner, mini, first steps
## mini
* name: Design a mini Explorer
* description: Let's explore the depths of mini! We'll add a vessel for mini travel, create some enemies, and make sure we have plenty of fuel for the journey.
* completionUrl: /skillmap/img/spacet4.gif
### mini-activity1
* allowcodecarryover: false
* name: Prepare Your Ship
* type: tutorial
* description: Get your miniship ready for an adventure!
* tags: easy, sprites, scroller
* url: /calliope/firststeps/firstSteps
* imageUrl: /skillmap/img/spacet4.gif
### mini-cert-1
* name: Congrats!
* kind: completion
* type: certificate
* imageUrl: /skillmap/img/spacet4.gif
* url: /skillmap/img/spacet4.gif

81
docs/skillmap/space.md Normal file
View File

@ -0,0 +1,81 @@
# Build a Space Explorer
* name: Build a Space Explorer
* description: Learn to make a Galga-style game by following this short series of tutorials.
* infoUrl: skillmap/educator-info/int-map-info
* bannerUrl: /static/skillmap/space/spacet4.gif
* backgroundurl: /static/skillmap/backgrounds/space-comp.png
* primarycolor: #2EA9B0
* secondarycolor: #d6f7fa
* tertiarycolor: #5d416b
* highlightcolor: #FFFFFF
* completednodecolor: #504c52
* tags: intermediate, space, projectiles
* alternatesources: github:https://github.com/microsoft/pxt-skillmap-sample/skillmap.md
## space
* name: Design a Space Explorer
* description: Let's explore the depths of space! We'll add a vessel for space travel, create some enemies, and make sure we have plenty of fuel for the journey.
* completionUrl: /static/skillmap/certificates/design-a-space-explorer.pdf
### space-activity1
* allowcodecarryover: false
* name: Prepare Your Ship
* type: tutorial
* description: Get your spaceship ready for an adventure!
* tags: easy, sprites, scroller
* next: space-activity2, pusher1
* url: /skillmap/space/space1
* imageUrl: /static/skillmap/space/spacet1.gif
### space-activity2
* name: Ready, aim, fire!
* type: tutorial
* description: Equip your ship with projectiles and special effects.
* tags: easy, projectiles, kinds
* next: pusher2, space-activity3
* url: /skillmap/space/space2
* imageUrl: /static/skillmap/space/spacet2.gif
### space-activity3
* name: Here comes trouble!
* description: Watch out for danger! Add enemies and countdown lives in your game.
* type: tutorial
* tags: intermediate, enemies, kinds
* next: space-activity4
* url: /skillmap/space/space3
* imageUrl: /static/skillmap/space/spacet3.gif
### space-activity4
* name: Fuel Up!
* type: tutorial
* description: Use an extension to add a fuel gauge to your ship. Make sure to refuel often!
* tags: intermediate, extensions
* next: space-cert-1
* url: /skillmap/space/space4
* imageUrl: /static/skillmap/space/spacet4.gif
### space-cert-1
* name: Congrats!
* kind: completion
* type: certificate
* imageUrl: /static/skillmap/certificates/space-cert.png
* url: /static/skillmap/certificates/design-a-space-explorer.pdf
### pusher1
* name: Blank node
* kind: layout
### pusher2
* name: Blank node
* kind: layout

View File

@ -0,0 +1,172 @@
# Space Explorer
## Introduction @showdialog
** Let's explore the depths of space! **
In this tutorial, you'll design a spaceship for your journey.
![Flying through space](/static/skillmap/space/space1.gif "Blasting through a starfield" )
## Set the scene
**Give 'em something to look at** 🔭
---
► Drag the ``||scene:start screen [confetti] effect ⊕||`` from the ``||scene:Scene||`` category and
into the ``||loops:on start||`` block that's already in the workspace.
► Next, select ``||scene:star field||`` (instead of ``||scene:confetti||``) from the dropdown
and watch as you blast into space! 🚀
---
```blocks
// @highlight
effects.starField.startScreenEffect()
```
## Draw your ship
**🧑🏿‍🚀 Time to choose our ship! 👩🏾‍🚀**
---
► From the ``||sprites:Sprites||`` category, drag the ``||variables:set [mySprite] to sprite [ ] of kind [Player]||``
block and place it at the end of the ``||loops:on start||`` container.
► Click on the grey box in the middle of your
``||variables:set [mySprite] to sprite [ ] of kind [Player]||`` block
to design a ship of your own! Are you a rusty pile of scraps or a sleek, futuristic rocket?
---
**Tip:** Don't feel like drawing your ship? Once you're in the sprite editor,
flip to the gallery and choose from premade images.
```blocks
effects.starField.startScreenEffect()
// @highlight
let mySprite = sprites.create(img`
. . . . . . . 9 9 . . . . . . .
. . . . . . 9 . . 9 . . . . . .
. . . . . . 9 . . 9 . . . . . .
. . . . . 9 . 9 9 . 9 . . . . .
. . . . . 9 . 9 9 . 9 . . . . .
. . . . 9 . 9 9 9 9 . 9 . . . .
. . . . 9 . 9 9 9 9 . 9 . . . .
. . . 9 . 9 9 9 9 9 9 . 9 . . .
. . . 9 . 9 . . . . 9 . 9 . . .
. . 9 . 9 9 . 9 9 . 9 9 . 9 . .
. . 9 . 9 9 . . . . 9 9 . 9 . .
. 9 . 9 9 9 . 9 9 9 9 9 9 . 9 .
. 9 . 9 9 9 . 9 9 9 9 9 9 . 9 .
9 . 9 9 9 9 9 9 9 9 9 9 9 9 . 9
9 . . . . . . . . . . . . . . 9
9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
`, SpriteKind.Player)
```
## Control your ship
🌟 Let's get your ship moving 🌟
---
► Find the ``||controller:move [mySprite] with buttons ⊕||`` block
and drag it into the bottom of the ``||loops:on start||`` container.
** Now try moving your ship around on the game screen! **
Your ship will move with the joystick, arrow keys, or **W A S D** keys.
```blocks
effects.starField.startScreenEffect()
let mySprite = sprites.create(img`
. . . . . . . 9 9 . . . . . . .
. . . . . . 9 . . 9 . . . . . .
. . . . . . 9 . . 9 . . . . . .
. . . . . 9 . 9 9 . 9 . . . . .
. . . . . 9 . 9 9 . 9 . . . . .
. . . . 9 . 9 9 9 9 . 9 . . . .
. . . . 9 . 9 9 9 9 . 9 . . . .
. . . 9 . 9 9 9 9 9 9 . 9 . . .
. . . 9 . 9 . . . . 9 . 9 . . .
. . 9 . 9 9 . 9 9 . 9 9 . 9 . .
. . 9 . 9 9 . . . . 9 9 . 9 . .
. 9 . 9 9 9 . 9 9 9 9 9 9 . 9 .
. 9 . 9 9 9 . 9 9 9 9 9 9 . 9 .
9 . 9 9 9 9 9 9 9 9 9 9 9 9 . 9
9 . . . . . . . . . . . . . . 9
9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
`, SpriteKind.Player)
// @highlight
controller.moveSprite(mySprite)
```
## Stay in screen
**Uh-oh, if you move off screen, your ship disappears!**
---
► To keep your ship from exploring beyond the edges, find
the ``||sprites:set [mySprite] stay in screen <on>||`` block and
snap it in at the end of the program.
```blocks
effects.starField.startScreenEffect()
let mySprite = sprites.create(img`
. . . . . . . 9 9 . . . . . . .
. . . . . . 9 . . 9 . . . . . .
. . . . . . 9 . . 9 . . . . . .
. . . . . 9 . 9 9 . 9 . . . . .
. . . . . 9 . 9 9 . 9 . . . . .
. . . . 9 . 9 9 9 9 . 9 . . . .
. . . . 9 . 9 9 9 9 . 9 . . . .
. . . 9 . 9 9 9 9 9 9 . 9 . . .
. . . 9 . 9 . . . . 9 . 9 . . .
. . 9 . 9 9 . 9 9 . 9 9 . 9 . .
. . 9 . 9 9 . . . . 9 9 . 9 . .
. 9 . 9 9 9 . 9 9 9 9 9 9 . 9 .
. 9 . 9 9 9 . 9 9 9 9 9 9 . 9 .
9 . 9 9 9 9 9 9 9 9 9 9 9 9 . 9
9 . . . . . . . . . . . . . . 9
9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
`, SpriteKind.Player)
controller.moveSprite(mySprite)
// @highlight
mySprite.setStayInScreen(true)
```
## Finale @showdialog
**Great Job!**
---
**Try your project on the game screen
before you click finish on the tutorial.**
Is everything how you want it? You can always go back and edit steps if you discover you'd like them to work differently.
## Byeeee
** 🚀 That's it! 🚀**
You're all set to travel the universe!
Click **Finish** to return to the main page where you can share your game
with family and friends!

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

19
docs/skillmaps.md Normal file
View File

@ -0,0 +1,19 @@
# Skillmaps
## Getting started
```codecard
[
{
"name": "Beginner Skillmap",
"cardType": "link",
"description": "Learn to make exciting and shareable arcade games by following a few quick tutorials!",
"imageUrl": "/static/skillmap/backgrounds/beginner.png",
"url": "http://localhost:3232--skillmap#mini",
"label": "New? Try This!",
"labelClass": "orange ribbon large",
"directOpen": true
}
]
```

View File

@ -12,7 +12,7 @@ export function renderUsbPairDialog(firmwareUrl?: string, failedOnce?: boolean):
<div className="column">
<div className="ui">
<div className="image">
<img alt={lf("Comic connecting micro:bit to computer")} className="ui medium rounded image" src="./static/download/connect.png" />
<img alt={lf("Comic connecting calliope mini to computer")} className="ui medium rounded image" src="./static/download/connect.png" />
</div>
<div className="content">
<div className="description">
@ -27,7 +27,7 @@ export function renderUsbPairDialog(firmwareUrl?: string, failedOnce?: boolean):
<div className="column">
<div className="ui">
<div className="image">
<img alt={lf("Comic of successful micro:bit connection")} className="ui medium rounded image" src="./static/download/pair.png" />
<img alt={lf("Comic of successful calliope mini connection")} className="ui medium rounded image" src="./static/download/pair.png" />
</div>
<div className="content">
<div className="description">
@ -51,7 +51,7 @@ export function renderUsbPairDialog(firmwareUrl?: string, failedOnce?: boolean):
<div className="ui header inverted">{lf("Update Firmware")}</div>
<strong className="ui small">{lf("You must have version 0249 or above of the firmware")}</strong>
<div className="image">
<img alt={lf("Comic rainbow updating micro:bit firmware")} className="ui image" src="./static/download/firmware.png" />
<img alt={lf("Comic rainbow updating calliope mini firmware")} className="ui image" src="./static/download/firmware.png" />
</div>
<a className="ui button" role="button" href={firmwareUrl} target="_blank">{lf("Check Firmware")}</a>
</div>
@ -73,7 +73,7 @@ export function renderBrowserDownloadInstructions(): JSX.Element {
<div className="column">
<div className="ui">
<div className="image">
<img alt={lf("Comic connecting micro:bit to computer")} className="ui medium rounded image" src="./static/download/connect.png" />
<img alt={lf("Comic connecting calliope mini to computer")} className="ui medium rounded image" src="./static/download/connect.png" />
</div>
<div className="content">
<div className="description">
@ -88,7 +88,7 @@ export function renderBrowserDownloadInstructions(): JSX.Element {
<div className="column">
<div className="ui">
<div className="image">
<img alt={lf("Comic moving hex file to micro:bit")} className="ui medium rounded image" src="./static/download/transfer.png" />
<img alt={lf("Comic moving hex file to calliope mini")} className="ui medium rounded image" src="./static/download/transfer.png" />
</div>
<div className="content">
<div className="description">

View File

@ -9,7 +9,7 @@ import * as flash from "./flash";
import * as patch from "./patch";
pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> {
pxt.debug('loading microbit target extensions...')
pxt.debug('loading calliope mini target extensions...')
const manyAny = Math as any;
if (!manyAny.imul)
@ -24,35 +24,22 @@ pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): P
};
const res: pxt.editor.ExtensionResult = {
hexFileImporters: [{
id: "blockly",
canImport: data => data.meta.cloudId == "microbit.co.uk" && data.meta.editor == "blockly",
importAsync: (project, data) => {
pxt.tickEvent('import.legacyblocks.redirect');
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 dialogs.cantImportAsync(project);
}
}]
hexFileImporters: []
};
pxt.usb.setFilters([{
vendorId: 0x1366,
productId: 0x1025
},
{
vendorId: 0x0D28,
productId: 0x0204
productId: 0x0204,
classCode: 0xff,
subclassCode: 0x03 // the ctrl pipe endpoint
}, {
vendorId: 0x0D28,
productId: 0x0204,
classCode: 0xff,
subclassCode: 0x00 // the custom CMSIS2 endpoint
}])
res.mkPacketIOWrapper = flash.mkDAPLinkPacketIOWrapper;
res.blocklyPatch = patch.patchBlocks;
res.renderBrowserDownloadInstructions = dialogs.renderBrowserDownloadInstructions;
res.renderUsbPairDialog = dialogs.renderUsbPairDialog;
return Promise.resolve<pxt.editor.ExtensionResult>(res);
}

View File

@ -1,9 +1,11 @@
const imul = (Math as any).imul;
const timeoutMessage = "timeout"
const membase = 0x20000000
const loadAddr = membase
const dataAddr = 0x20002000
const stackAddr = 0x20001000
const timeoutMessage = "timeout";
const membase = 0x20000000;
const loadAddr = membase;
const dataAddr = 0x20002000;
const stackAddr = 0x20001000;
const FULL_FLASH_TIMEOUT = 100000; // 100s
const PARTIAL_FLASH_TIMEOUT = 60000; // 60s
const flashPageBIN = new Uint32Array([
0xbe00be00, // bkpt - LR is set to this
@ -35,7 +37,7 @@ function log(msg: string) {
let ts = ("00000" + now).slice(-5)
pxt.debug(`dap ${ts}: ${msg}`)
}
const logV = /webusbdbg=1/.test(window.location.href) ? log : (msg: string) => { }
function murmur3_core(data: Uint8Array) {
let h0 = 0x2F9BE6CC;
@ -57,23 +59,41 @@ function murmur3_core(data: Uint8Array) {
return [h0, h1]
}
function bufferConcat(a: Uint8Array, b: Uint8Array) {
const r = new Uint8Array(a.length + b.length)
r.set(a, 0)
r.set(b, a.length)
return r
}
class DAPWrapper implements pxt.packetio.PacketIOWrapper {
familyID: number;
private dap: DapJS.DAP;
private cortexM: DapJS.CortexM
private cmsisdap: any;
private flashing = false;
private flashAborted = false;
private readSerialId = 0;
private pbuf = new pxt.U.PromiseBuffer<Uint8Array>();
private pageSize = 1024;
private numPages = 256;
private binName = pxtc.BINARY_HEX;
private usesCODAL = false;
private forceFullFlash = /webusbfullflash=1/.test(window.location.href);
private get useJACDAC() {
return this.usesCODAL;
}
onSerial = (buf: Uint8Array, isStderr: boolean) => { };
onCustomEvent = (type: string, payload: Uint8Array) => { };
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.familyID = 0x0D28; // this is the microbit vendor id, not quite UF2 family id
this.io.onDeviceConnectionChanged = (connect) => {
log(`device connection changed`);
this.disconnectAsync()
.then(() => connect && this.reconnectAsync());
}
this.io.onData = buf => {
// console.log("RD: " + pxt.Util.toHex(buf))
this.pbuf.push(buf);
@ -82,96 +102,199 @@ class DAPWrapper implements pxt.packetio.PacketIOWrapper {
this.allocDAP();
}
icon = "usb";
icon = "xicon microbit";
private pendingSerial: Uint8Array
private lastPendingSerial: number
private processSerialLine(line: Uint8Array) {
if (this.onSerial) {
try {
// catch encoding bugs
this.onSerial(line, false)
}
catch (err) {
log(`serial decoding error: ${err.message}`);
pxt.tickEvent("hid.flash.serial.decode.error");
console.error({ err, line })
}
}
}
private async readSerial(): Promise<number> {
let buf = await this.dapCmdNums(0x83)
const len = buf[1]
// concat received data with previous data
if (len) {
buf = buf.slice(2, 2 + len)
if (this.pendingSerial) buf = bufferConcat(this.pendingSerial, buf)
let ptr = 0
let beg = 0
while (ptr < buf.length) {
if (buf[ptr] == 10 || buf[ptr] == 13) {
ptr++;
// eat \r\n
while (ptr < buf.length && (buf[ptr] == 10 || buf[ptr] == 13))
ptr++;
const line = buf.slice(beg, ptr)
if (line.length)
this.processSerialLine(line);
beg = ptr
}
else
ptr++
}
buf = buf.slice(beg)
this.pendingSerial = buf.length ? buf : null
if (this.pendingSerial) {
this.lastPendingSerial = Date.now()
//logV(`pending serial ${this.pendingSerial.length}`)
}
} else if (this.pendingSerial) {
const d = Date.now() - this.lastPendingSerial
if (d > 500) {
this.processSerialLine(this.pendingSerial)
this.pendingSerial = null
}
}
return len
}
private startReadSerial() {
log(`start read serial`)
const rid = this.readSerialId;
const readSerial = () => {
const startTime = Date.now();
log(`start read serial ${rid}`)
const readSerialLoop = async () => {
try {
while (rid === this.readSerialId) {
const len = await this.readSerial()
const hasData = len > 0
//if (hasData)
// logV(`serial read ${len} bytes`)
await this.jacdacProcess(hasData)
}
log(`stopped serial reader ${rid}`)
} catch (err) {
log(`serial error ${rid}: ${err.message}`);
console.error(err)
if (rid != this.readSerialId) {
log(`stopped read serial ${rid}`)
return;
log(`stopped serial reader ${rid}`)
} else {
pxt.tickEvent("hid.flash.serial.error");
const timeRunning = Date.now() - startTime
await this.disconnectAsync(); // force disconnect
// if we've been running for a while, try reconnecting
if (timeRunning > 1000) {
log(`auto-reconnect`)
await this.reconnectAsync();
}
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();
readSerialLoop();
}
private stopSerialAsync() {
log(`stopping serial reader`)
log(`cancelling serial reader ${this.readSerialId}`)
this.readSerialId++;
return Promise.delay(200);
return pxt.Util.delay(200);
}
onSerial: (buf: Uint8Array, isStderr: boolean) => void;
private allocDAP() {
log(`alloc dap`);
const h = this.io;
this.dap = new DapJS.DAP({
write: writeAsync,
write: data => h.sendPacketAsync(new Uint8Array(data)),
close: this.disconnectAsync,
read: readAsync,
read: () => this.recvPacketAsync(),
//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();
}
get binName() {
return (this.usesCODAL ? "mbcodal-" : "mbdal-") + pxtc.BINARY_HEX;
}
reconnectAsync(): Promise<void> {
unsupportedParts() {
if (!this.usesCODAL) {
return ["logotouch", "builtinspeaker", "microphone", "flashlog"]
}
return [];
}
async reconnectAsync(): Promise<void> {
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());
this.flashAborted = false;
function stringResponse(buf: Uint8Array) {
return pxt.U.uint8ArrayToString(buf.slice(2, 2 + buf[1]))
}
await this.stopSerialAsync()
this.allocDAP(); // clean dap apis
await this.io.reconnectAsync()
// before calling into dapjs, we use our dapCmdNums() a few times, which which will make sure the responses
// to commends from previous sessions (if any) are flushed
const info = await this.dapCmdNums(0x00, 0x04) // info
const daplinkVersion = stringResponse(info)
log(`daplink version: ${daplinkVersion}`)
const r = await this.dapCmdNums(0x80)
this.usesCODAL = r[2] == 57 && r[3] == 57 && r[5] >= 51;
const binVersion = stringResponse(r);
log(`bin name: ${this.binName} v:${binVersion}`);
pxt.tickEvent("hid.flash.connect", { codal: this.usesCODAL ? 1 : 0, daplink: daplinkVersion, bin: binVersion });
const baud = new Uint8Array(5)
baud[0] = 0x82 // set baud
pxt.HF2.write32(baud, 1, 115200)
await this.dapCmd(baud)
// setting the baud rate on serial may reset NRF (depending on daplink version), so delay after
await pxt.Util.delay(200);
// only init after setting baud rate, in case we got reset
await this.cortexM.init()
const res = await this.readWords(0x10000010, 2);
this.pageSize = res[0]
this.numPages = res[1]
log(`page size ${this.pageSize}, num pages ${this.numPages}`);
await this.checkStateAsync(true);
await this.jacdacSetup();
this.startReadSerial();
}
private async checkStateAsync(resume?: boolean): Promise<void> {
const states = ["reset", "lockup", "sleeping", "halted", "running"]
try {
const state = await this.cortexM.getState();
log(`cortex state: ${states[state]}`)
if (resume && state == DapJS.CoreState.TARGET_HALTED)
await this.cortexM.resume();
} catch (e) {
log(`cortex state failed`)
pxt.tickEvent("hid.checkstate.error")
console.debug(e)
}
}
private checkAborted() {
if (this.flashAborted)
throw new Error(lf("Download cancelled"));
}
disconnectAsync() {
log(`disconnect`)
this.flashAborted = true;
return this.stopSerialAsync()
.then(() => this.io.disconnectAsync());
}
@ -180,72 +303,195 @@ class DAPWrapper implements pxt.packetio.PacketIOWrapper {
log("reflash")
startTime = 0
pxt.tickEvent("hid.flash.start");
this.flashAborted = false;
this.flashing = true;
return (this.io.isConnected() ? Promise.resolve() : this.io.reconnectAsync())
.then(() => this.stopSerialAsync())
.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) {
.then(() => this.checkStateAsync())
.then(() => this.readUICR())
.then(uicr => {
pxt.tickEvent("hid.flash.uicr", { uicr });
// shortcut, do a full flash
if (uicr != 0 || this.forceFullFlash) {
pxt.tickEvent("hid.flash.uicrfail");
return this.fullVendorCommandFlashAsync(resp);
}
return this.quickHidFlashAsync(resp);
// check flash checksums
return this.computeFlashChecksum(resp)
.then(chk => {
pxt.tickEvent("hid.flash.checksum", { quick: chk.quick ? 1 : 0, changed: chk.changed ? chk.changed.length : 0 });
// let's do a quick flash!
if (chk.quick)
return this.quickHidFlashAsync(chk.changed);
else
return this.fullVendorCommandFlashAsync(resp);
});
})
.then(() => this.checkStateAsync(true))
.then(() => pxt.tickEvent("hid.flash.success"))
.finally(() => { this.flashing = false })
.then(() => Promise.delay(100))
.then(() => this.disconnectAsync())
// don't disconnect here
// the micro:bit will automatically disconnect and reconnect
// via the webusb events
}
private recvPacketAsync() {
if (this.io.recvPacketAsync)
return this.io.recvPacketAsync()
else
return this.pbuf.shiftAsync()
}
private dapCmd(buf: Uint8Array) {
return this.io.sendPacketAsync(buf)
.then(() => this.recvPacketAsync())
.then(resp => {
if (resp[0] != buf[0]) {
pxt.tickEvent('hid.flash.cmderror', { req: buf[0], resp: resp[0] })
const msg = `bad dapCmd response: ${buf[0]} -> ${resp[0]}`
// in case we got an invalid response, try to get another response, in case the current
// response is a left-over from previous communications
log(msg + "; retrying")
return this.recvPacketAsync()
.then(resp => {
if (resp[0] == buf[0])
return resp
throw new Error(msg)
}, err => {
throw new Error(msg)
})
}
return resp
})
}
private dapCmdNums(...nums: number[]) {
return this.dapCmd(new Uint8Array(nums))
}
private fullVendorCommandFlashAsync(resp: pxtc.CompileResult): Promise<void> {
log("full flash")
pxt.tickEvent("hid.flash.full.start");
const chunkSize = 62;
let aborted = false;
return Promise.resolve()
.then(() => {
return this.cmsisdap.cmdNums(0x8A /* DAPLinkFlash.OPEN */, [1]);
})
let sentPages = 0;
return pxt.Util.promiseTimeout(
FULL_FLASH_TIMEOUT,
Promise.resolve()
.then(() => this.dapCmdNums(0x8A /* DAPLinkFlash.OPEN */, 1))
.then((res) => {
const hexUint8 = pxt.U.stringToUint8Array(resp.outfiles[this.binName]);
const hexArray: number[] = Array.prototype.slice.call(hexUint8);
log(`daplinkflash open: ${pxt.U.toHex(res)}`)
if (res[1] !== 0) {
pxt.tickEvent('hid.flash.full.error.open', { res: res[1] })
throw new Error(lf("Download failed, please try again"));
}
const binFile = resp.outfiles[this.binName];
log(`bin file ${this.binName} in ${Object.keys(resp.outfiles).join(', ')}, ${binFile?.length || -1}b`)
const hexUint8 = pxt.U.stringToUint8Array(binFile);
log(`hex ${hexUint8?.byteLength || -1}b, ~${(hexUint8.byteLength / chunkSize) | 0} chunks of ${chunkSize}b`)
const sendPages = (offset: number = 0): Promise<void> => {
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)
const end = Math.min(hexUint8.length, offset + chunkSize);
const nextPageData = hexUint8.slice(offset, end);
const cmdData = new Uint8Array(2 + nextPageData.length)
cmdData[0] = 0x8C /* DAPLinkFlash.WRITE */
cmdData[1] = nextPageData.length
cmdData.set(nextPageData, 2)
if (sentPages % 128 == 0) // reduce logging
log(`next page ${sentPages}: [${offset.toString(16)}, ${end.toString(16)}] (${Math.ceil((hexUint8.length - end) / 1000)}kb left)`)
return this.dapCmd(cmdData)
.then(() => {
if (!aborted && end < hexArray.length) {
this.checkAborted()
if (end < hexUint8.length) {
sentPages++;
return sendPages(end);
}
return Promise.resolve();
return Promise.resolve()
});
}
return sendPages();
})
.then((res) => {
return this.cmsisdap.cmdNums(0x8B /* DAPLinkFlash.CLOSE */, []);
.then(() => {
log(`close`)
return this.dapCmdNums(0x8B /* DAPLinkFlash.CLOSE */);
})
.timeout(60000, timeoutMessage)
.catch((e) => {
aborted = true;
return this.cmsisdap.cmdNums(0x89 /* DAPLinkFlash.RESET */, [])
.then(res => {
log(`daplinkclose: ${pxt.U.toHex(res)}`)
return this.dapCmdNums(0x89 /* DAPLinkFlash.RESET */);
})
.then((res) => {
log(`daplinkreset: ${pxt.U.toHex(res)}`)
log(`full flash done`);
pxt.tickEvent("hid.flash.full.success");
}),
timeoutMessage
).catch((e) => {
log(`error: abort`)
pxt.tickEvent("hid.flash.full.error");
this.flashAborted = true;
return this.resetAndThrowAsync(e);
});
}
private resetAndThrowAsync(e: any) {
log(`reset on error`)
pxt.tickEvent("hid.flash.reset");
console.debug(e)
// reset any pending daplink
return this.dapCmdNums(0x89 /* DAPLinkFlash.RESET */)
.catch((e2: any) => {
// Best effort reset, no-op if there's an error
})
.then(() => this.cortexM.reset(false))
.catch((e2: any) => {
// Best effort reset, no-op if there's an error
})
.then(() => {
return Promise.reject(e);
});
throw e;
});
}
private quickHidFlashAsync(resp: pxtc.CompileResult): Promise<void> {
private readUICR() {
return this.readWords(0x10001014, 1)
.then(v => {
const uicr = v[0] & 0xff;
log(`uicr: ${uicr.toString(16)} (${v[0].toString(16)})`);
return uicr;
});
}
private computeFlashChecksum(resp: pxtc.CompileResult) {
const binFile = resp.outfiles[this.binName];
if (!binFile)
throw new Error(`unable to find ${this.binName} in outfiles ${Object.keys(resp.outfiles).join(', ')}`);
return this.getFlashChecksumsAsync()
.then(checksums => {
log(`checksums ${pxt.Util.toHex(checksums)}`);
// TODO this is seriously inefficient (130ms on a fast machine)
const uf2 = ts.pxtc.UF2.newBlockFile();
ts.pxtc.UF2.writeHex(uf2, binFile.split(/\r?\n/));
const bytes = pxt.U.stringToUint8Array(ts.pxtc.UF2.serializeFile(uf2));
const parsed = ts.pxtc.UF2.parseFile(bytes);
const aligned = DAPWrapper.pageAlignBlocks(parsed, this.pageSize);
const changed = DAPWrapper.onlyChanged(aligned, checksums, this.pageSize);
const quick = changed.length < aligned.length / 2;
log(`pages: ${aligned.length}, changed ${changed.length}, ${quick ? "quick" : "full"}`);
return {
quick,
changed
}
});
}
private quickHidFlashAsync(changed: ts.pxtc.UF2.Block[]): Promise<void> {
log("quick flash")
let logV = (msg: string) => { }
//let logV = log
let aborted = false;
pxt.tickEvent("hid.flash.quick.start");
const runFlash = (b: ts.pxtc.UF2.Block, dataAddr: number) => {
const cmd = this.cortexM.prepareCommand();
@ -266,45 +512,39 @@ class DAPWrapper implements pxt.packetio.PacketIOWrapper {
return cmd.go()
})
.then(() => {
logV("dbg en")
// starts the program
logV(`cortex.debug.enable`)
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),
return pxt.Util.promiseTimeout(
PARTIAL_FLASH_TIMEOUT,
Promise.resolve()
.then(() => this.cortexM.memory.writeBlock(loadAddr, flashPageBIN))
.then(() => pxt.Util.promiseMapAllSeries(pxt.U.range(changed.length),
i => {
if (aborted) return Promise.resolve();
let b = aligned[i];
if (b.targetAddr >= 0x10000000)
this.checkAborted();
let b = changed[i];
if (b.targetAddr >= 0x10000000) {
log(`target address 0x${b.targetAddr.toString(16)} > 0x10000000`)
return Promise.resolve();
}
logV("about to write at 0x" + b.targetAddr.toString(16));
let writeBl = Promise.resolve();
log(`about to write at 0x${b.targetAddr.toString(16)}`);
let thisAddr = (i & 1) ? dataAddr : dataAddr + this.pageSize;
let nextAddr = (i & 1) ? dataAddr + this.pageSize : dataAddr;
let writeBl;
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);
}
if (i == 0) {
let u32data = new Uint32Array(b.data.length / 4);
@ -316,7 +556,7 @@ class DAPWrapper implements pxt.packetio.PacketIOWrapper {
return writeBl
.then(() => runFlash(b, thisAddr))
.then(() => {
let next = aligned[i + 1];
let next = changed[i + 1];
if (!next)
return Promise.resolve();
logV("write next");
@ -330,17 +570,20 @@ class DAPWrapper implements pxt.packetio.PacketIOWrapper {
.then(() => {
logV("done block");
});
}))
.then(() => {
log("quick flash done");
return this.cortexM.reset(false);
})
.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);
pxt.tickEvent("hid.flash.quick.success");
return this.checkStateAsync(true)
}),
timeoutMessage
).catch((e) => {
pxt.tickEvent("hid.flash.quick.error");
this.flashAborted = true;
return this.resetAndThrowAsync(e);
});
}
@ -352,6 +595,21 @@ class DAPWrapper implements pxt.packetio.PacketIOWrapper {
.then(() => this.cortexM.memory.readBlock(dataAddr, pages * 2, this.pageSize))
}
private readWords(addr: number, numWords: number) {
return this.cortexM.memory.readBlock(addr, numWords, this.pageSize)
// assume browser is little-endian
.then(u8 => new Uint32Array(u8.buffer))
}
private writeWords(addr: number, buf: Uint32Array) {
return this.cortexM.memory.writeBlock(addr, buf)
}
private readBytes(addr: number, numBytes: number) {
return this.cortexM.memory.readBlock(addr, (numBytes + 3) >> 2, this.pageSize)
.then(u8 => u8.length == numBytes ? u8 : u8.slice(0, numBytes))
}
static onlyChanged(blocks: ts.pxtc.UF2.Block[], checksums: Uint8Array, pageSize: number) {
return blocks.filter(b => {
let idx = b.targetAddr / pageSize
@ -392,6 +650,184 @@ class DAPWrapper implements pxt.packetio.PacketIOWrapper {
}
return res
}
//
// jacdac stuff starts here
//
private irqn: number
private xchgAddr: number = null
private lastXchg: number
private currSend: SendItem
private sendQ: SendItem[] = []
private lastSend: number
sendCustomEventAsync(type: string, buf: Uint8Array): Promise<void> {
if (type == "jacdac") {
if (this.xchgAddr == null)
return Promise.resolve()
if (buf.length & 3) {
const tmp = new Uint8Array((buf.length + 3) & ~3)
tmp.set(buf)
buf = tmp
}
return new Promise<void>(resolve => {
this.sendQ.push({
buf,
cb: resolve
})
})
}
return Promise.reject(new Error("invalid custom event type"))
}
private writeWord(addr: number, val: number) {
return this.cortexM.memory.write32(addr, val)
}
private async findJacdacXchgAddr() {
const memStart = 0x2000_0000
const memStop = memStart + 128 * 1024
const checkSize = 1024
let p0 = 0x20006000
let p1 = 0x20006000 + checkSize
const check = async (addr: number) => {
if (addr < memStart)
return null
if (addr + checkSize > memStop)
return null
const buf = await this.readWords(addr, checkSize >> 2)
for (let i = 0; i < buf.length; ++i) {
if (buf[i] == 0x786D444A && buf[i + 1] == 0xB0A6C0E9)
return addr + (i << 2)
}
return 0
}
while (true) {
const a0 = await check(p0)
if (a0) return a0
const a1 = await check(p1)
if (a1) return a1
if (a0 === null && a1 === null)
return null
p0 -= checkSize
p1 += checkSize
}
}
private async jacdacSetup() {
this.xchgAddr = null
if (!this.useJACDAC) {
log(`jacdac: disabled`)
return
}
await pxt.Util.delay(700); // wait for the program to start and setup memory correctly
const xchg = await this.findJacdacXchgAddr()
if (xchg == null) {
log("jacdac: xchg address not found")
pxt.tickEvent("hid.flash.jacdac.error.missingxchg");
return
}
const info = await this.readBytes(xchg, 16)
this.irqn = info[8]
if (info[12 + 2] != 0xff) {
log("jacdac: invalid memory; try power-cycling the micro:bit")
pxt.tickEvent("hid.flash.jacdac.error.invalidmemory");
console.debug({ info, xchg })
return
}
this.xchgAddr = xchg
// clear initial lock
await this.writeWord(xchg + 12, 0)
log(`jacdac: exchange address 0x${xchg.toString(16)}; irqn=${this.irqn}`)
pxt.tickEvent("hid.flash.jacdac.connected");
}
private async triggerIRQ(irqn: number) {
const addr = 0xE000E200 + (irqn >> 5) * 4
await this.writeWord(addr, 1 << (irqn & 31))
}
private async jacdacProcess(hadSerial: boolean) {
if (this.xchgAddr == null) {
if (!hadSerial)
await this.dapDelay(5000)
return
}
const now = Date.now()
if (this.lastXchg && now - this.lastXchg > 50) {
logV("slow xchg: " + (now - this.lastXchg) + "ms")
}
this.lastXchg = now
let numev = 0
// TODO only read say 32 bytes first, and more if needed
let inp = await this.readBytes(this.xchgAddr + 12, 256)
if (inp[2]) {
await this.writeWord(this.xchgAddr + 12, 0)
await this.triggerIRQ(this.irqn)
inp = inp.slice(0, inp[2] + 12)
this.onCustomEvent("jacdac", inp)
numev++
}
let sendFree = false
if (this.currSend) {
const send = await this.readBytes(this.xchgAddr + 12 + 256, 4)
if (!send[2]) {
this.currSend.cb()
this.currSend = null
sendFree = true
numev++
}
}
if (!this.currSend && this.sendQ.length) {
if (!sendFree) {
const send = await this.readBytes(this.xchgAddr + 12 + 256, 4)
if (!send[2])
sendFree = true
}
if (sendFree) {
this.currSend = this.sendQ.shift()
const bbody = this.currSend.buf.slice(4)
await this.writeWords(this.xchgAddr + 12 + 256 + 4, new Uint32Array(bbody.buffer))
const bhead = this.currSend.buf.slice(0, 4)
await this.writeWords(this.xchgAddr + 12 + 256, new Uint32Array(bhead.buffer))
await this.triggerIRQ(this.irqn)
this.lastSend = Date.now()
numev++
} else {
if (this.lastSend) {
const d = Date.now() - this.lastSend
if (d > 50) {
this.lastSend = 0
console.error("failed to send packet fast enough")
}
}
}
}
if (numev == 0 && !hadSerial)
await this.dapDelay(5000)
}
private dapDelay(micros: number) {
if (micros > 0xffff)
throw new Error("too large delay")
const cmd = new Uint8Array([0x09, 0, 0])
pxt.HF2.write16(cmd, 1, micros)
return this.dapCmd(cmd)
}
}
interface SendItem {
buf: Uint8Array
cb: () => void
}
export function mkDAPLinkPacketIOWrapper(io: pxt.packetio.PacketIO): pxt.packetio.PacketIOWrapper {

View File

@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "es2017",
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
@ -12,6 +12,13 @@
"rootDir": ".",
"newLine": "LF",
"sourceMap": false,
"jsx": "react"
"jsx": "react",
"lib": [
"dom",
"dom.iterable",
"scripthost",
"es2017",
"ES2018.Promise"
]
}
}

View File

@ -1,6 +1,6 @@
{
"masterPicture": "docs/static/microbit.simplified.svg",
"iconsPath": "/static/icons",
"iconsPath": "/docs/static/icons",
"design": {
"ios": {
"pictureAspect": "backgroundAndMargin",

View File

@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "es2017",
"noImplicitAny": false,
"noImplicitReturns": true,
"module": "commonjs",

View File

@ -1,8 +1,7 @@
{
"name": "{0} block",
"dependencies": {
"core": "file:../core",
"radio": "file:../radio"
"core": "file:../core"
},
"description": "",
"files": [

View File

@ -1,8 +1,58 @@
#include "MicroBitConfig.h"
#include "ble/UUID.h"
#include "BLEHF2Service.h"
#include "MicroBitEvent.h"
//================================================================
#if MICROBIT_CODAL
//================================================================
const uint8_t BLEHF2Service::service_base_uuid[ 16] =
{ 0xb1,0x12,0x00,0x00,0x26,0x79,0x30,0xda,0xa2,0x6e,0x02,0x73,0xb6,0x04,0x38,0x49 };
const uint8_t BLEHF2Service::char_base_uuid[ 16] =
{ 0xb1,0x12,0x00,0x00,0x26,0x79,0x30,0xda,0xa2,0x6e,0x02,0x73,0xb6,0x04,0x38,0x4a };
const uint16_t BLEHF2Service::serviceUUID = 0xf5e6;
const uint16_t BLEHF2Service::charUUID[ mbbs_cIdxCOUNT] = { 0xf5e6 };
BLEHF2Service::BLEHF2Service(BLEDevice &_ble) :
ble(_ble)
{
// Initialise our characteristic values.
memset(&txCharacteristicMessage, 0, sizeof(txCharacteristicMessage));
// Register the base UUID and create the service.
RegisterBaseUUID( service_base_uuid);
CreateService( serviceUUID);
RegisterBaseUUID( char_base_uuid);
CreateCharacteristic( mbbs_cIdxMESSAGE, charUUID[ mbbs_cIdxMESSAGE],
(uint8_t *)&txCharacteristicMessage,
sizeof(txCharacteristicMessage), sizeof(txCharacteristicMessage),
microbit_propNOTIFY);
}
void BLEHF2Service::sendSerial(const char *data, int len, bool isError) {
if (getConnected())
{
int32_t sent = 0;
while(sent < len) {
int32_t n = min(BLEHF2_DATA_LENGTH, len - sent);
txCharacteristicMessage.command = (isError ? BLEHF2_FLAG_SERIAL_OUT : BLEHF2_FLAG_SERIAL_ERR) | n;
memcpy(&txCharacteristicMessage.data, data + sent, n);
notifyChrValue(mbbs_cIdxMESSAGE,(uint8_t *)&txCharacteristicMessage, sizeof(txCharacteristicMessage));
sent += n;
}
}
}
//================================================================
#else // MICROBIT_CODAL
//================================================================
#include "ble/UUID.h"
BLEHF2Service::BLEHF2Service(BLEDevice &_ble) :
ble(_ble)
{
@ -48,3 +98,7 @@ const uint8_t BLEHF2ServiceUUID[] = {
const uint8_t BLEHF2TxCharacteristicUUID[] = {
0xb1,0x12,0xf5,0xe6,0x26,0x79,0x30,0xda,0xa2,0x6e,0x02,0x73,0xb6,0x04,0x38,0x4a
};
//================================================================
#endif // MICROBIT_CODAL
//================================================================

View File

@ -2,7 +2,6 @@
#define BLE_HF2_SERVICE_H
#include "MicroBitConfig.h"
#include "ble/BLE.h"
#include "MicroBitThermometer.h"
#include "EventModel.h"
#include "pxt.h"
@ -22,6 +21,65 @@ struct BLEHF2Packet {
uint8_t data[BLEHF2_DATA_LENGTH];
};
//================================================================
#if MICROBIT_CODAL
//================================================================
#include "MicroBitBLEManager.h"
#include "MicroBitBLEService.h"
class BLEHF2Service : public MicroBitBLEService
{
public:
/**
* Constructor.
* Create a representation of the TemperatureService
* @param _ble The instance of a BLE device that we're running on.
*/
BLEHF2Service(BLEDevice &_ble);
/**
* Sends text
*/
void sendSerial(const char *data, int len, bool isError);
private:
// Bluetooth stack we're running on.
BLEDevice &ble;
// memory for buffers.
BLEHF2Packet txCharacteristicMessage;
// Index for each charactersitic in arrays of handles and UUIDs
typedef enum mbbs_cIdx
{
mbbs_cIdxMESSAGE,
mbbs_cIdxCOUNT
} mbbs_cIdx;
// UUIDs for our service and characteristics
static const uint8_t service_base_uuid[ 16];
static const uint8_t char_base_uuid[ 16];
static const uint16_t serviceUUID;
static const uint16_t charUUID[ mbbs_cIdxCOUNT];
// Data for each characteristic when they are held by Soft Device.
MicroBitBLEChar chars[ mbbs_cIdxCOUNT];
public:
int characteristicCount() { return mbbs_cIdxCOUNT; };
MicroBitBLEChar *characteristicPtr( int idx) { return &chars[ idx]; };
};
//================================================================
#else // MICROBIT_CODAL
//================================================================
#include "ble/BLE.h"
class BLEHF2Service
{
public:
@ -50,5 +108,8 @@ class BLEHF2Service
GattAttribute::Handle_t txCharacteristicHandle;
};
//================================================================
#endif // MICROBIT_CODAL
//================================================================
#endif

View File

@ -14,7 +14,7 @@ namespace bluetooth {
BLEHF2Service* pHF2 = NULL;
//%
void __log(String msg) {
void __log(int priority, String msg) {
if (NULL == pHF2)
pHF2 = new BLEHF2Service(*uBit.ble);
pHF2->sendSerial(msg->getUTF8Data(), msg->getUTF8Size(), false);
@ -125,19 +125,18 @@ namespace bluetooth {
startUartService();
int bytes = uart->rxBufferedSize();
auto buffer = mkBuffer(NULL, bytes);
auto res = buffer;
registerGCObj(buffer);
int read = uart->read(buffer->data, buffer->length);
// read failed
if (read < 0) {
decrRC(buffer);
return mkBuffer(NULL, 0);
}
res = mkBuffer(NULL, 0);
} else if (read != buffer->length) {
// could not fill the buffer
if (read != buffer->length) {
auto tmp = mkBuffer(buffer->data, read);
decrRC(buffer);
buffer = tmp;
res = mkBuffer(buffer->data, read);
}
return buffer;
unregisterGCObj(buffer);
return res;
}
/**
@ -184,6 +183,7 @@ namespace bluetooth {
//% blockId=eddystone_advertise_url block="bluetooth advertise url %url|with power %power|connectable %connectable"
//% parts=bluetooth weight=11 blockGap=8
//% help=bluetooth/advertise-url blockExternalInputs=1
//% hidden=1 deprecated=1
void advertiseUrl(String url, int power, bool connectable) {
#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_URL)
power = min(MICROBIT_BLE_POWER_LEVELS-1, max(0, power));
@ -199,7 +199,7 @@ namespace bluetooth {
* @param power power level between 0 and 7, eg: 7
* @param connectable true to keep bluetooth connectable for other services, false otherwise.
*/
//% parts=bluetooth weight=12 advanced=true
//% parts=bluetooth weight=12 advanced=true deprecated=1
void advertiseUidBuffer(Buffer nsAndInstance, int power, bool connectable) {
#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_UID)
auto buf = nsAndInstance;
@ -227,6 +227,7 @@ namespace bluetooth {
//% blockId=eddystone_stop_advertising block="bluetooth stop advertising"
//% parts=bluetooth weight=10
//% help=bluetooth/stop-advertising advanced=true
//% hidden=1 deprecated=1
void stopAdvertising() {
uBit.bleManager.stopAdvertising();
}

View File

@ -10,10 +10,10 @@ namespace bluetooth {
* Internal use
*/
//% shim=bluetooth::__log
export function __log(msg: string) {
export function __log(priority: number, msg: string) {
return;
}
console.addListener(function (msg) { __log(msg) });
console.addListener(function (_pri, msg) { __log(_pri, msg) });
/**
* Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device.
@ -78,6 +78,7 @@ namespace bluetooth {
//% blockId=eddystone_advertise_uid block="bluetooth advertise UID|namespace (bytes 6-9)%ns|instance (bytes 2-6)%instance|with power %power|connectable %connectable"
//% parts=bluetooth weight=12 blockGap=8
//% help=bluetooth/advertise-uid blockExternalInputs=1
//% hidden=1 deprecated=1
export function advertiseUid(ns: number, instance: number, power: number, connectable: boolean) {
const buf = pins.createBuffer(16);
buf.setNumber(NumberFormat.Int32BE, 6, ns);

View File

@ -10,12 +10,13 @@
"BLEHF2Service.h",
"BLEHF2Service.cpp"
],
"weight": 10,
"searchOnly": true,
"icon": "./static/packages/bluetooth/icon.png",
"public": true,
"dependencies": {
"core": "file:../core"
},
"disablesVariants": ["mbcodal"],
"yotta": {
"config": {
"microbit-dal": {
@ -29,7 +30,8 @@
"stack_size": 1280,
"gatt_table_size": "0x700"
}
}
},
"installedVersion": "vzlhfd"
"userConfigs": [
]
}
}

View File

@ -109,7 +109,8 @@ declare namespace bluetooth {
*/
//% blockId=eddystone_advertise_url block="bluetooth advertise url %url|with power %power|connectable %connectable"
//% parts=bluetooth weight=11 blockGap=8
//% help=bluetooth/advertise-url blockExternalInputs=1 shim=bluetooth::advertiseUrl
//% help=bluetooth/advertise-url blockExternalInputs=1
//% hidden=1 deprecated=1 shim=bluetooth::advertiseUrl
function advertiseUrl(url: string, power: int32, connectable: boolean): void;
/**
@ -118,7 +119,7 @@ declare namespace bluetooth {
* @param power power level between 0 and 7, eg: 7
* @param connectable true to keep bluetooth connectable for other services, false otherwise.
*/
//% parts=bluetooth weight=12 advanced=true shim=bluetooth::advertiseUidBuffer
//% parts=bluetooth weight=12 advanced=true deprecated=1 shim=bluetooth::advertiseUidBuffer
function advertiseUidBuffer(nsAndInstance: Buffer, power: int32, connectable: boolean): void;
/**
@ -134,7 +135,8 @@ declare namespace bluetooth {
*/
//% blockId=eddystone_stop_advertising block="bluetooth stop advertising"
//% parts=bluetooth weight=10
//% help=bluetooth/stop-advertising advanced=true shim=bluetooth::stopAdvertising
//% help=bluetooth/stop-advertising advanced=true
//% hidden=1 deprecated=1 shim=bluetooth::stopAdvertising
function stopAdvertising(): void;
}

View File

@ -4,6 +4,7 @@
"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._pickRandom": "Return a random value from the array",
"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.",
@ -41,6 +42,7 @@
"Array.reverse": "Reverse the elements in an array. The first array element becomes the last, and the last array element becomes the first.",
"Array.set": "Store a value at a particular index",
"Array.set|param|index": "the zero-based position in the list to store the value, eg: 0",
"Array.set|param|value": "the value to insert, eg: 0",
"Array.shift": "Remove the first element from an array and return it. This method changes the length of the array.",
"Array.slice": "Return a section of an array.",
"Array.slice|param|end": "The end of the specified portion of the array. eg: 0",
@ -124,9 +126,15 @@
"Image.showFrame": "Show a particular frame of the image strip.",
"Image.showFrame|param|frame": "image frame to show",
"Image.showImage": "Shows an frame from the image at offset ``x offset``.",
"Image.showImage|param|interval": "time in milliseconds to pause after drawing",
"Image.showImage|param|xOffset": "column index to start displaying the image",
"Image.width": "Gets the width in columns",
"Infinity": "Constant representing positive infinity.",
"JSON.parse": "Converts a JavaScript Object Notation (JSON) string into an object.",
"JSON.stringify": "Converts a JavaScript value to a JavaScript Object Notation (JSON) string.",
"JSON.stringify|param|indent": "Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.",
"JSON.stringify|param|replacer": "Not supported; use null.",
"JSON.stringify|param|value": "A JavaScript value, usually an object or array, to be converted.",
"Math": "More complex operations with numbers.",
"Math.abs": "Returns the absolute value of a number (the value without regard to whether it is positive or negative).\nFor example, the absolute value of -5 is the same as the absolute value of 5.",
"Math.abs|param|x": "A numeric expression for which the absolute value is needed.",
@ -225,7 +233,7 @@
"String.split": "Splits the string according to the separators",
"String.split|param|separator": "@param limit",
"String.substr": "Return a substring of the current string.",
"String.substr|param|length": "number of characters to extract",
"String.substr|param|length": "number of characters to extract, eg: 10",
"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",
@ -245,30 +253,31 @@
"basic.pause|param|ms": "how long to pause for, eg: 100, 200, 500, 1000, 2000",
"basic.plotLeds": "Draws an image on the LED screen.",
"basic.plotLeds|param|leds": "pattern of LEDs to turn on/off",
"basic.rgb": "Converts red, green, blue channels into a RGB color",
"basic.rgbw": "Converts red, green, blue channels into a RGB color",
"basic.rgbw|param|blue": "value of the blue channel between 0 and 255. eg: 255",
"basic.rgbw|param|green": "value of the green channel between 0 and 255. eg: 255",
"basic.rgbw|param|red": "value of the red channel between 0 and 255. eg: 255",
"basic.rgbw|param|white": "value of the white channel between 0 and 255. eg: 0",
"basic.rgb|param|blue": "value of the blue channel between 0 and 255. eg: 255",
"basic.rgb|param|green": "value of the green channel between 0 and 255. eg: 255",
"basic.rgb|param|red": "value of the red channel between 0 and 255. eg: 255",
"basic.setLedColor": "Sets the color on the build-in LED. Set to 0 to turn off.",
"basic.showAnimation": "Shows a sequence of LED screens as an animation.",
"basic.showAnimation|param|interval": "time in milliseconds between each redraw",
"basic.showAnimation|param|leds": "pattern of LEDs to turn on/off",
"basic.showArrow": "Draws an arrow on the LED screen",
"basic.showArrow|param|direction": "the direction of the arrow",
"basic.showArrow|param|interval": "the amount of time (milliseconds) to show the icon. Default is 600.",
"basic.showCompass": "Draws needle on the screen which always points to north",
"basic.showCompass|param|interval": "the amount of time (milliseconds) to show the needle. Default is 600.",
"basic.showIcon": "Draws the selected icon on the LED screen",
"basic.showIcon|param|icon": "the predefined icon id",
"basic.showIcon|param|interval": "the amount of time (milliseconds) to show the icon. Default is 600.",
"basic.showIcon|param|interval": "the amount of time (milliseconds) to block the LED Matrix for showing the icon. Default is 200.",
"basic.showLeds": "Draws an image on the LED screen.",
"basic.showLeds|param|interval": "time in milliseconds to pause after drawing",
"basic.showLeds|param|leds": "the pattern of LED to turn on/off",
"basic.showNumber": "Scroll a number on the screen. If the number fits on the screen (i.e. is a single digit), do not scroll.",
"basic.showNumber|param|interval": "speed of scroll; eg: 150, 100, 200, -100",
"basic.showNumber|param|interval": "speed of scroll; eg: 50, 100, 150, 200",
"basic.showString": "Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll.",
"basic.showString|param|interval": "how fast to shift characters; eg: 150, 100, 200, -100",
"basic.showString|param|interval": "how fast to shift characters; eg: 50, 100, 150, 200",
"basic.showString|param|text": "the text to scroll on the screen, eg: \"hi!\"",
"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.",
@ -280,31 +289,48 @@
"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\"",
"console.logValue|param|value": "to write",
"console.log|param|value": "to send",
"console.minPriority": "Minimum priority to send messages to listeners",
"console.removeListener": "Removes a listener",
"control": "Runtime and event utilities.",
"control.allocateNotifyEvent": "Allocates the next user notification event",
"control.assert": "If the condition is false, display msg on serial console, and panic with code 098.",
"control.benchmark": "Runs the function and returns run time in microseconds.",
"control.createBuffer": "Create a new zero-initialized buffer.",
"control.createBufferFromUTF8": "Create a new buffer with UTF8-encoded string",
"control.createBufferFromUTF8|param|str": "the string to put in the buffer",
"control.createBuffer|param|size": "number of bytes in the buffer",
"control.deviceLongSerialNumber": "Derive a unique, consistent 64-bit serial number of this device from internal data.",
"control.deviceName": "Make a friendly name for the device based on its serial number",
"control.deviceSerialNumber": "Derive a unique, consistent serial number of this device from internal data.",
"control.dmesg": "Write a message to DMESG debugging buffer.",
"control.dmesgPerfCounters": "Dump values of profiling performance counters.",
"control.dmesgPtr": "Write a message and value (pointer) to DMESG debugging buffer.",
"control.enablePerfCounter": "Enable profiling for current function.",
"control.eventSourceId": "Returns the value of a C++ runtime constant",
"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.gc": "Force GC and dump basic information about heap.",
"control.gcStats": "Get various statistics about the garbage collector (GC)",
"control.heapDump": "Force GC and halt waiting for debugger to do a full heap dump.",
"control.heapSnapshot": "Record a heap snapshot to debug memory leaks.",
"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.",
"control.onEvent": "Registers an event handler.",
"control.panic": "Display specified error code and stop the program.",
"control.profilingEnabled": "Return true if profiling is enabled in the current build.",
"control.raiseEvent": "Raises an event in the event bus.",
"control.raiseEvent|param|mode": "optional definition of how the event should be processed after construction (default is CREATE_AND_FIRE).",
"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.ramSize": "Returns estimated size of memory in bytes.",
"control.reset": "Resets the BBC micro:bit.",
"control.runInParallel": "Run other code in the parallel.",
"control.runtimeWarning": "Display warning in the simulator.",
"control.setDebugFlags": "Set flags used when connecting an external debugger.",
"control.simmessages.onReceived": "Registers the handler for a message on a given channel",
"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",
@ -401,38 +427,39 @@
"input": "Events and data from sensors",
"input.acceleration": "Get the acceleration value in milli-gravitys (when the board is laying flat with the screen up, x=0, y=0 and z=-1024)",
"input.acceleration|param|dimension": "x, y, or z dimension, eg: Dimension.X",
"input.assumeCalibrationCompass": "Obsolete, compass calibration is automatic.",
"input.buttonEventValueId": "Returns the value of a C++ runtime constant",
"input.buttonIsPressed": "Get the button state (pressed or not) for ``A`` and ``B``.",
"input.buttonIsPressed|param|button": "the button to query the request, eg: Button.A",
"input.calibrate": "Obsolete, use input.calibrateCompass instead.",
"input.calibrateCompass": "Obsolete, compass calibration is automatic.",
"input.clearCalibrationCompass": "Obsolete, compass calibration is automatic.",
"input.compassHeading": "Get the current compass heading in degrees.",
"input.isCalibratedCompass": "Returns 'true' when the compass is calibrated. Otherwise returns 'false'.",
"input.isGesture": "Tests if a gesture is currently detected.",
"input.isGesture|param|gesture": "the type of gesture to detect, eg: Gesture.Shake",
"input.lightLevel": "Reads the light level applied to the LED screen in a range from ``0`` (dark) to ``255`` bright.",
"input.loudness": "gets the level of loudness from 0 (silent) to 255 (loud)",
"input.magneticForce": "Get the magnetic force value in ``micro-Teslas`` (``µT``). This function is not supported in the simulator.",
"input.magneticForce|param|dimension": "the x, y, or z dimension, eg: Dimension.X",
"input.onButtonEvent": "Do something when a button (A, B or both A+B) receives an event.",
"input.onButtonEvent|param|body": "code to run when event is raised",
"input.onButtonEvent|param|button": "the button",
"input.onButtonEvent|param|eventType": "event Type",
"input.onButtonPressed": "Do something when a button (A, B or both A+B) is pushed down and released again.",
"input.onButtonPressed|param|body": "code to run when event is raised",
"input.onButtonPressed|param|button": "the button that needs to be pressed",
"input.onGesture": "Do something when when a gesture is done (like shaking the micro:bit).",
"input.onGesture|param|body": "code to run when gesture is raised",
"input.onGesture|param|gesture": "the type of gesture to track, eg: Gesture.Shake",
"input.onLogoDown": "Attaches code to run when the logo is oriented downwards and the board is vertical.",
"input.onLogoDown|param|body": "TODO",
"input.onLogoUp": "Attaches code to run when the logo is oriented upwards and the board is vertical.",
"input.onLogoUp|param|body": "TODO",
"input.onPinPressed": "Do something when a pin is touched and released again (while also touching the GND pin).",
"input.onPinPressed|param|body": "the code to run when the pin is pressed",
"input.onPinPressed|param|name": "the pin that needs to be pressed, eg: TouchPin.P0",
"input.onPinReleased": "Do something when a pin is released.",
"input.onPinReleased|param|body": "the code to run when the pin is released",
"input.onPinReleased|param|name": "the pin that needs to be released, eg: TouchPin.P0",
"input.onScreenDown": "Attaches code to run when the screen is facing down.",
"input.onScreenDown|param|body": "TODO",
"input.onScreenUp": "Attaches code to run when the screen is facing up.",
"input.onScreenUp|param|body": "TODO",
"input.onShake": "Attaches code to run when the device is shaken.",
"input.onShake|param|body": "TODO",
"input.onPinTouchEvent": "Do something when a pin receives an touch event (while also touching the GND pin).",
"input.onPinTouchEvent|param|body": "the code to run when event is fired on pin",
"input.onPinTouchEvent|param|name": "the pin, eg: TouchPin.P0",
"input.pinIsPressed": "Get the pin state (pressed or not). Requires to hold the ground to close the circuit.",
"input.pinIsPressed|param|name": "pin used to detect the touch, eg: TouchPin.P0",
"input.rotation": "The pitch or roll of the device, rotation along the ``x-axis`` or ``y-axis``, in degrees.",
@ -441,7 +468,7 @@
"input.runningTimeMicros": "Gets the number of microseconds elapsed since power on.",
"input.setAccelerometerRange": "Sets the accelerometer sample range in gravities.",
"input.setAccelerometerRange|param|range": "a value describe the maximum strengh of acceleration measured",
"input.soundLevel": "gets the level of loudness in 0-100%",
"input.soundLevel": "gets the level of loudness from 0 (silent) to 255 (loud)",
"input.temperature": "Gets the temperature in Celsius degrees (°C).",
"led": "Control of the LED screen.",
"led.brightness": "Get the screen brightness from 0 (off) to 255 (full bright).",
@ -482,7 +509,10 @@
"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.sendWS2812BufferWithBrightness": "Sends a color buffer to a light strip",
"light.setMode": "Sets the light mode of a pin",
"loops.everyInterval": "Repeats the code forever in the background.\nAfter each iteration, allows other codes to run for a set duration\nso that it runs on a timer",
"loops.everyInterval|param|interval": "time (in ms) to wait between each iteration of the action.",
"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.",
@ -522,6 +552,7 @@
"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.stopAllSounds": "Stop all sounds and melodies currently playing.",
"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.",
@ -531,6 +562,9 @@
"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",
"pauseUntil": "Busy wait for a condition to be true",
"pauseUntil|param|condition": "condition to test for",
"pauseUntil|param|timeOut": "if positive, maximum duration to wait for 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",
@ -597,9 +631,12 @@
"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|value": "angle or rotation speed, eg:180,90,0",
"pins.setAudioPin": "Set the pin used when producing sounds and melodies. Default is P0.",
"pins.setAudioPin|param|name": "pin to modulate pitch from",
"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.setMatrixWidth": "Set the matrix width for Neopixel strip (already assigned to a pin).\nShould be used in conjunction with `set matrix width` from Neopixel package.",
"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",
@ -622,8 +659,8 @@
"serial.delimiters": "Return the corresponding delimiter string",
"serial.onDataReceived": "Register an event to be fired when one of the delimiter is matched.",
"serial.onDataReceived|param|delimiters": "the characters to match received characters against.",
"serial.readBuffer": "Read multiple characters from the receive buffer. Pause until enough characters are present.",
"serial.readBuffer|param|length": "default buffer length, eg: 64",
"serial.readBuffer": "Read multiple characters from the receive buffer. \nIf length is positive, pauses until enough characters are present.",
"serial.readBuffer|param|length": "default buffer length",
"serial.readLine": "Read a line of text from the serial port.",
"serial.readString": "Read the buffered received data as a string",
"serial.readUntil": "Read a line of text from the serial port and return the buffer when the delimiter is met.",
@ -647,5 +684,20 @@
"serial.writeString": "Send a piece of text through the serial connection.",
"serial.writeValue": "Write a name:value pair as a line to the serial port.",
"serial.writeValue|param|name": "name of the value stream, eg: x",
"serial.writeValue|param|value": "to write"
"serial.writeValue|param|value": "to write",
"storage": "Provides access to persistent storage functionality.\n\nProvides access to persistent storage functionality.",
"storage.getNumber": "Reads a key value pair from the non volatile storage as a number",
"storage.getNumber|param|key": "the key for accesing the value",
"storage.getValueInt": "Reads a key value pair from the non volatile storage",
"storage.getValueInt|param|key": "the key for accesing the value",
"storage.putNumber": "Saves a key value pair in the non volatile storage",
"storage.putNumber|param|key": "the key for accesing the value",
"storage.putNumber|param|value": "value to store",
"storage.putValueInt": "Saves a key value pair in the non volatile storage",
"storage.putValueInt|param|key": "the key for accesing the value",
"storage.putValueInt|param|value": "value to store",
"storage.remove": "Removes a key value pair from the non volatile storage",
"storage.removeKeyInt": "Deletes the key from the non volatile storage",
"storage.removeKeyInt|param|key": "the key for accesing the value",
"storage.remove|param|key": "the key for accesing the value"
}

View File

@ -7,6 +7,7 @@
"AcceleratorRange.OneG|block": "1g",
"AcceleratorRange.TwoG": "The accelerator measures forces up to 2 gravity",
"AcceleratorRange.TwoG|block": "2g",
"Array._pickRandom|block": "get random value from %list",
"Array._popStatement|block": "remove last value from %list",
"Array._removeAtStatement|block": "%list| remove value at %index",
"Array._shiftStatement|block": "remove first value from %list",
@ -21,14 +22,6 @@
"Array.shift|block": "get and remove first value from %list",
"Array.unshift|block": "%list| insert %value| at beginning",
"Array|block": "Array",
"ArrowNames.East|block": "East",
"ArrowNames.NorthEast|block": "North East",
"ArrowNames.NorthWest|block": "North West",
"ArrowNames.North|block": "North",
"ArrowNames.SouthEast|block": "South East",
"ArrowNames.SouthWest|block": "South West",
"ArrowNames.South|block": "South",
"ArrowNames.West|block": "West",
"BaudRate.BaudRate115200|block": "115200",
"BaudRate.BaudRate1200|block": "1200",
"BaudRate.BaudRate14400|block": "14400",
@ -49,6 +42,10 @@
"BeatFraction.Whole|block": "1",
"Buffer|block": "Buffer",
"Button.AB|block": "A+B",
"ButtonEvent.Click|block": "clicked",
"ButtonEvent.Down|block": "pressed down",
"ButtonEvent.LongClick|block": "long clicked",
"ButtonEvent.Up|block": "released up",
"Colors.Blue|block": "blue",
"Colors.Green|block": "green",
"Colors.Indigo|block": "indigo",
@ -112,46 +109,20 @@
"IconNames.ArrowSouth|block": "arrow south",
"IconNames.ArrowWest|block": "arrow west",
"IconNames.Asleep|block": "asleep",
"IconNames.Butterfly|block": "butterfly",
"IconNames.Chessboard|block": "chess board",
"IconNames.Confused|block": "confused",
"IconNames.Cow|block": "cow",
"IconNames.Diamond|block": "diamond",
"IconNames.Duck|block": "duck",
"IconNames.EigthNote|block": "eigth note",
"IconNames.Fabulous|block": "fabulous",
"IconNames.Ghost|block": "ghost",
"IconNames.Giraffe|block": "giraffe",
"IconNames.Happy|block": "happy",
"IconNames.Heart|block": "heart",
"IconNames.House|block": "house",
"IconNames.LeftTriangle|block": "left triangle",
"IconNames.Meh|block": "meh",
"IconNames.No|block": "no",
"IconNames.Pitchfork|block": "pitchfork",
"IconNames.QuarterNote|block": "quarter note",
"IconNames.Rabbit|block": "rabbit",
"IconNames.Rollerskate|block": "roller skate",
"IconNames.Sad|block": "sad",
"IconNames.Scissors|block": "scissors",
"IconNames.Silly|block": "silly",
"IconNames.Skull|block": "skull",
"IconNames.SmallDiamond|block": "small diamond",
"IconNames.SmallHeart|block": "small heart",
"IconNames.SmallSquare|block": "small square",
"IconNames.Snake|block": "snake",
"IconNames.Square|block": "square",
"IconNames.StickFigure|block": "stick figure",
"IconNames.Surprised|block": "surprised",
"IconNames.Sword|block": "sword",
"IconNames.TShirt|block": "t-shirt",
"IconNames.Target|block": "target",
"IconNames.Tortoise|block": "tortoise",
"IconNames.Triangle|block": "triangle",
"IconNames.Umbrella|block": "umbrella",
"IconNames.Yes|block": "yes",
"Image.scrollImage|block": "scroll image %sprite(myImage)|with offset %frameoffset|and interval (ms) %delay",
"Image.showImage|block": "show image %sprite(myImage)|at offset %offset",
"Image.scrollImage|block": "scroll image %sprite(myImage)|with offset %frameoffset|and interval (ms) %interval",
"Image.showImage|block": "show image %sprite(myImage)|at offset %offset ||and interval (ms) %interval",
"JSON|block": "JSON",
"LedSpriteProperty.Blink|block": "blink",
"LedSpriteProperty.Brightness|block": "brightness",
"LedSpriteProperty.Direction|block": "direction",
@ -248,6 +219,13 @@
"PulseValue.Low|block": "low",
"Rotation.Pitch|block": "pitch",
"Rotation.Roll|block": "roll",
"StorageSlots.s1|block": "Slot 1",
"StorageSlots.s2|block": "Slot 2",
"StorageSlots.s3|block": "Slot 3",
"StorageSlots.s4|block": "Slot 4",
"StorageSlots.s5|block": "Slot 5",
"StorageSlots.s6|block": "Slot 6",
"StorageSlots.s7|block": "Slot 7",
"String.charAt|block": "char from %this=text|at %pos",
"String.compare|block": "compare %this=text| to %that",
"String.fromCharCode|block": "text from char code %code",
@ -264,13 +242,13 @@
"basic.forever|block": "forever",
"basic.pause|block": "pause (ms) %pause",
"basic.rgbw|block": "red %red|green %green|blue %blue|white %white",
"basic.rgb|block": "red %red|green %green|blue %blue",
"basic.setLedColor|block": "set led to %color=colorNumberPicker",
"basic.showArrow|block": "show arrow %i=device_arrow",
"basic.showCompass|block": "show compass needle for $interval|ms",
"basic.showIcon|block": "show icon %i",
"basic.showIcon|block": "show icon %i || for %interval ms",
"basic.showLeds|block": "show leds",
"basic.showNumber|block": "show|number %number",
"basic.showString|block": "show|string %text",
"basic.showNumber|block": "show|number %number || in an interval of %interval ms",
"basic.showString|block": "show|string %text || in an interval of %interval ms",
"basic.turnRgbLedOff|block": "turn build-in LED off",
"basic|block": "basic",
"console|block": "console",
@ -314,29 +292,34 @@
"game.setScore|block": "set score %points",
"game.startCountdown|block": "start countdown|(ms) %duration",
"game|block": "game",
"images.arrowImage|block": "arrow image %i",
"images.arrowNumber|block": "%arrow",
"images.createBigImage|block": "create big image",
"images.createImage|block": "create image",
"images.iconImage|block": "icon image %i",
"images|block": "images",
"input.acceleration|block": "acceleration (mg)|%NAME",
"input.assumeCalibrationCompass|block": "assume calibration compass",
"input.buttonEventValueId|block": "%id",
"input.buttonIsPressed|block": "button|%NAME|is pressed",
"input.calibrateCompass|block": "calibrate compass",
"input.clearCalibrationCompass|block": "clear calibration compass",
"input.compassHeading|block": "compass heading (°)",
"input.isCalibratedCompass|block": "is compass calibrated",
"input.isGesture|block": "is %gesture gesture",
"input.lightLevel|block": "light level",
"input.loudness|block": "Loudness",
"input.magneticForce|block": "magnetic force (µT)|%NAME",
"input.onButtonEvent|block": "on button %NAME| %eventType=control_button_event_value_id",
"input.onButtonPressed|block": "on button|%NAME|pressed",
"input.onGesture|block": "on |%NAME",
"input.onPinPressed|block": "on pin %name|pressed",
"input.onPinReleased|block": "on pin %NAME|released",
"input.onPinTouchEvent|block": "on pin %name| %eventType=control_button_event_value_id",
"input.pinIsPressed|block": "pin %NAME|is pressed",
"input.rotation|block": "rotation (°)|%NAME",
"input.runningTimeMicros|block": "running time (micros)",
"input.runningTime|block": "running time (ms)",
"input.setAccelerometerRange|block": "set accelerometer|range %range",
"input.soundLevel|block": "Loudness",
"input.soundLevel|block": "soundLevel",
"input.temperature|block": "temperature (°C)",
"input|block": "input",
"led.brightness|block": "brightness",
@ -353,6 +336,8 @@
"led.unplot|block": "unplot|x %x|y %y",
"led|block": "led",
"light|block": "light",
"loops.everyInterval|block": "every $interval ms",
"loops|block": "loops",
"motors.dualMotorPower|block": "motor %motor|at %percent \\%",
"motors.motorCommand|block": "motor %command",
"motors.motorPower|block": "motor on at %percent \\%",
@ -371,6 +356,7 @@
"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.stopAllSounds|block": "stop all sounds",
"music.stopMelody|block": "stop melody $options",
"music.tempo|block": "tempo (bpm)",
"music.volume|block": "volume",
@ -394,7 +380,9 @@
"pins.pulseIn|block": "pulse in (µs)|pin %name|pulsed %value",
"pins.servoSetPulse|block": "servo set pulse|pin %value|to (µs) %micros",
"pins.servoWritePin|block": "servo write|pin %name|to %value",
"pins.setAudioPin|block": "set audio pin $name",
"pins.setEvents|block": "set pin %pin|to emit %type|events",
"pins.setMatrixWidth|block": "neopixel matrix width|pin %pin %width",
"pins.setPull|block": "set pull|pin %pin|to %pull",
"pins.spiFormat|block": "spi format|bits %bits|mode %mode",
"pins.spiFrequency|block": "spi frequency %frequency",
@ -421,6 +409,13 @@
"serial.writeString|block": "serial|write string %text",
"serial.writeValue|block": "serial|write value %name|= %value",
"serial|block": "serial",
"storage.getNumber|block": "read from number %key",
"storage.getValueInt|block": "get number from %key",
"storage.putNumber|block": "Save into number %key a value of %value",
"storage.putValueInt|block": "Put into %key a value of %value as Int",
"storage.removeKeyInt|block": "Clear number %key",
"storage.remove|block": "remove %key",
"storage|block": "storage",
"{id:category}AnalogInPin": "AnalogInPin",
"{id:category}AnalogOutPin": "AnalogOutPin",
"{id:category}Array": "Array",
@ -438,8 +433,10 @@
"{id:category}Image": "Image",
"{id:category}Images": "Images",
"{id:category}Input": "Input",
"{id:category}JSON": "JSON",
"{id:category}Led": "Led",
"{id:category}Light": "Light",
"{id:category}Loops": "Loops",
"{id:category}Math": "Math",
"{id:category}MicrobitPin": "MicrobitPin",
"{id:category}Motors": "Motors",
@ -450,15 +447,27 @@
"{id:category}Pins": "Pins",
"{id:category}PwmOnlyPin": "PwmOnlyPin",
"{id:category}Serial": "Serial",
"{id:category}Storage": "Storage",
"{id:category}String": "String",
"{id:category}Text": "Text",
"{id:category}_py": "_py",
"{id:group}Configuration": "Configuration",
"{id:group}Control": "Control",
"{id:group}Events": "Events",
"{id:group}Get": "Get",
"{id:group}LED matrix": "LED matrix",
"{id:group}Melody": "Melody",
"{id:group}Melody Advanced": "Melody Advanced",
"{id:group}Modify": "Modify",
"{id:group}Operations": "Operations",
"{id:group}Put": "Put",
"{id:group}RGB LED": "RGB LED",
"{id:group}Read": "Read",
"{id:group}Remove": "Remove",
"{id:group}Sensors": "Sensors",
"{id:group}Silence": "Silence",
"{id:group}States": "States",
"{id:group}System": "System",
"{id:group}Tempo": "Tempo",
"{id:group}Tone": "Tone",
"{id:group}Volume": "Volume"

View File

@ -39,6 +39,10 @@
"basic.rgbw|param|green": "Grünwert zwischen 0 und 255, z.B. 255",
"basic.rgbw|param|red": "Rotwert zwischen 0 und 255, z.B. 255",
"basic.rgbw|param|white": "Weißwert zwischen 0 und 255, z.B. 0",
"basic.rgb": "Konvertiert Rot-, Grün- und Blau-Kanäle in eine RGB-Farbe",
"basic.rgb|param|blue": "Blauwert zwischen 0 und 255, z.B. 255",
"basic.rgb|param|green": "Grünwert zwischen 0 und 255, z.B. 255",
"basic.rgb|param|red": "Rotwert zwischen 0 und 255, z.B. 255",
"basic.setLedColor": "Legt die Farbe der eingebauten LED fest. Setze auf 0, um diese abzuschalten.",
"basic.showAnimation": "Zeigt eine Abfolge von LED-Anzeigen als Animation.",
"basic.showAnimation|param|interval": "Zeit in Millisekunden zwischen jedem Neuzeichnen",

View File

@ -97,6 +97,7 @@
"basic.forever|block": "dauerhaft",
"basic.pause|block": "pausiere (ms) %pause",
"basic.rgbw|block": "Rot %red|Grün %green|Blau %blue|Weiß %white",
"basic.rgb|block": "Rot %red|Grün %green|Blau %blue",
"basic.setLedColor|block": "setze LED-Farbe auf %color=color_id",
"basic.showLeds|block": "zeige LEDs",
"basic.showNumber|block": "zeige|Nummer %number",

View File

@ -4,14 +4,122 @@
/**
* Provides access to basic micro:bit functionality.
*/
//% color=#1E90FF weight=116 icon="\uf00a"
namespace basic {
/**
* Draws an image on the LED screen.
* @param leds the pattern of LED to turn on/off
* @param interval time in milliseconds to pause after drawing
*/
//% help=basic/show-leds
//% weight=85 blockGap=8
//% imageLiteral=1 async
//% blockId=device_show_leds
//% block="show leds" icon="\uf00a"
//% parts="ledmatrix"
//% group="LED matrix"
void showLeds(ImageLiteral_ leds, int interval = 400) {
uBit.display.print(MicroBitImage(imageBytes(leds)), 0, 0, 0, interval);
}
/**
* Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll.
* @param text the text to scroll on the screen, eg: "hi!"
* @param interval how fast to shift characters; eg: 50, 100, 150, 200
*/
//% help=basic/show-string
//% weight=100 blockGap=16
//% block="show|string %text || in an interval of %interval ms"
//% async
//% blockId=device_print_message
//% parts="ledmatrix"
//% text.shadowOptions.toString=true
//% expandableArgumentMode="toggle"
//% interval.defl=80
//% group="LED matrix"
void showString(String text, int interval = 80) {
if (interval <= 0)
interval = 1;
int l = text ? text->getUTF8Size() : 0;
if (l == 0) {
uBit.display.clear();
fiber_sleep(interval * 5);
} else if (l > 1) {
uBit.display.scroll(MSTR(text), interval);
} else {
uBit.display.printChar(text->getUTF8Data()[0], interval * 5);
}
}
/**
* Shows a sequence of LED screens as an animation.
* @param leds pattern of LEDs to turn on/off
* @param interval time in milliseconds between each redraw
*/
//% help=basic/show-animation weight=83 imageLiteral=1 async
//% parts="ledmatrix"
//% group="LED matrix"
void showAnimation(ImageLiteral_ leds, int interval = 400) {
uBit.display.animate(MicroBitImage(imageBytes(leds)), interval, 5, 0, 0);
}
/**
* Draws an image on the LED screen.
* @param leds pattern of LEDs to turn on/off
*/
//% help=basic/plot-leds weight=80
//% parts="ledmatrix"
//% group="LED matrix"
void plotLeds(ImageLiteral_ leds) {
MicroBitImage i(imageBytes(leds));
uBit.display.print(i, 0, 0, 0, 0);
}
/**
* Turn off all LEDs
*/
//% help=basic/clear-screen weight=75
//% blockId=device_clear_display block="clear screen"
//% parts="ledmatrix"
//% group="LED matrix"
//% advanced=true
void clearScreen() {
uBit.display.image.clear();
}
/**
* Repeats the code forever in the background. On each iteration, allows other codes to run.
* @param body code to execute
*/
//% help=basic/forever weight=55 blockGap=16 blockAllowMultiple=1 afterOnStart=true
//% blockId=device_forever block="forever" icon="\uf01e"
//% group="Control"
void forever(Action a) {
runForever(a);
}
/**
* Pause for the specified time in milliseconds
* @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000
*/
//% help=basic/pause weight=50
//% async block="pause (ms) %pause" blockGap=16
//% blockId=device_pause icon="\uf110"
//% pause.shadow=timePicker
//% group="Control"
void pause(int ms) {
fiber_sleep(ms);
}
/**
* Sets the color on the build-in LED. Set to 0 to turn off.
*/
//% blockId=device_set_led_color
//% block="set led to %color=colorNumberPicker"
//% weight=50
//% weight=10
//% group="RGB LED"
void setLedColor(int color) {
if (!color) {
uBit.rgb.off();
@ -31,104 +139,12 @@ namespace basic {
* Sets the color on the build-in LED. Set to 0 to turn off.
*/
//% blockId=device_turn_rgb_led_off block="turn build-in LED off"
//% weight=50
//% weight=10
//% group="RGB LED"
//% advanced=true
void turnRgbLedOff() {
uBit.rgb.off();
}
/**
* Draws an image on the LED screen.
* @param leds the pattern of LED to turn on/off
* @param interval time in milliseconds to pause after drawing
*/
//% help=basic/show-leds
//% weight=95 blockGap=8
//% imageLiteral=1 async
//% blockId=device_show_leds
//% block="show leds" icon="\uf00a"
//% parts="ledmatrix"
void showLeds(ImageLiteral_ leds, int interval = 400) {
uBit.display.print(MicroBitImage(imageBytes(leds)), 0, 0, 0, interval);
}
/**
* Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll.
* @param text the text to scroll on the screen, eg: "hi!"
* @param interval how fast to shift characters; eg: 150, 100, 200, -100
*/
//% help=basic/show-string
//% weight=87 blockGap=16
//% block="show|string %text"
//% async
//% blockId=device_print_message
//% parts="ledmatrix"
//% text.shadowOptions.toString=true
void showString(String text, int interval = 150) {
if (interval <= 0)
interval = 1;
int l = text ? text->getUTF8Size() : 0;
if (l == 0) {
uBit.display.clear();
fiber_sleep(interval * 5);
} else if (l > 1) {
uBit.display.scroll(MSTR(text), interval);
} else {
uBit.display.printChar(text->getUTF8Data()[0], interval * 5);
}
}
/**
* Turn off all LEDs
*/
//% help=basic/clear-screen weight=79
//% blockId=device_clear_display block="clear screen"
//% parts="ledmatrix"
//% advanced=true
void clearScreen() {
uBit.display.image.clear();
}
/**
* Shows a sequence of LED screens as an animation.
* @param leds pattern of LEDs to turn on/off
* @param interval time in milliseconds between each redraw
*/
//% help=basic/show-animation imageLiteral=1 async
//% parts="ledmatrix"
void showAnimation(ImageLiteral_ leds, int interval = 400) {
uBit.display.animate(MicroBitImage(imageBytes(leds)), interval, 5, 0, 0);
}
/**
* Draws an image on the LED screen.
* @param leds pattern of LEDs to turn on/off
*/
//% help=basic/plot-leds weight=80
//% parts="ledmatrix"
void plotLeds(ImageLiteral_ leds) {
MicroBitImage i(imageBytes(leds));
uBit.display.print(i, 0, 0, 0, 0);
}
/**
* Repeats the code forever in the background. On each iteration, allows other codes to run.
* @param body code to execute
*/
//% help=basic/forever weight=55 blockGap=16 blockAllowMultiple=1 afterOnStart=true
//% blockId=device_forever block="forever" icon="\uf01e"
void forever(Action a) {
runForever(a);
}
/**
* Pause for the specified time in milliseconds
* @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000
*/
//% help=basic/pause weight=54
//% async block="pause (ms) %pause" blockGap=16
//% blockId=device_pause icon="\uf110"
//% pause.shadow=timePicker
void pause(int ms) {
fiber_sleep(ms);
}
}

View File

@ -37,17 +37,52 @@ enum Colors {
/**
* Provides access to basic micro:bit functionality.
*/
//% color=#54C9C9 weight=100
//% color=#54C9C9 weight=100 icon="\uf00a"
//% groups=['LED matrix', 'Control', 'RGB LED', 'others']
namespace basic {
/**
* Scroll a number on the screen. If the number fits on the screen (i.e. is a single digit), do not scroll.
* @param interval speed of scroll; eg: 50, 100, 150, 200
*/
//% help=basic/show-number
//% weight=95
//% blockId=device_show_number
//% block="show|number %number || in an interval of %interval ms" blockGap=8
//% async
//% parts="ledmatrix"
//% expandableArgumentMode="toggle"
//% interval.defl=80
//% group="LED matrix"
export function showNumber(value: number, interval?: number) {
showString(Math.roundWithPrecision(value, 2).toString(), interval);
}
/**
* Converts the color name to a number
*/
//% blockId=color_id block="%c" shim=TD_ID
//% group="RGB LED"
//% weight=1
//% deprecated=true
export function color(c: Colors): number {
return c;
}
/**
* Converts red, green, blue channels into a RGB color
* @param red value of the red channel between 0 and 255. eg: 255
* @param green value of the green channel between 0 and 255. eg: 255
* @param blue value of the blue channel between 0 and 255. eg: 255
*/
//% weight=3
//% blockId="core_rgb" block="red %red|green %green|blue %blue"
//% group="RGB LED"
export function rgb(red: number, green: number, blue: number): number {
return ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF);
}
/**
* Converts red, green, blue channels into a RGB color
* @param red value of the red channel between 0 and 255. eg: 255
@ -55,24 +90,14 @@ namespace basic {
* @param blue value of the blue channel between 0 and 255. eg: 255
* @param white value of the white channel between 0 and 255. eg: 0
*/
//% weight=1
//% blockId="core_rgb" block="red %red|green %green|blue %blue|white %white"
//% weight=2
//% blockId="core_rgbw" block="red %red|green %green|blue %blue|white %white"
//% group="RGB LED"
//% deprecated=true
export function rgbw(red: number, green: number, blue: number, white:number): number {
return ((white & 0xFF) << 24) | ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF);
}
/**
* Scroll a number on the screen. If the number fits on the screen (i.e. is a single digit), do not scroll.
* @param interval speed of scroll; eg: 150, 100, 200, -100
*/
//% help=basic/show-number
//% weight=96
//% blockId=device_show_number block="show|number %number" blockGap=8
//% async
//% parts="ledmatrix" interval.defl=150
export function showNumber(value: number, interval?: number) {
showString(Math.roundWithPrecision(value, 2).toString(), interval);
}
}
/**

View File

@ -1,10 +1,10 @@
<xml xmlns="http://www.w3.org/1999/xhtml">
<block type="pins_on_pulsed" x="-157" y="130">
<field name="pin">DigitalPin.C5</field>
<field name="pin">DigitalPin.P5</field>
<field name="pulse">PulseValue.Low</field>
<statement name="HANDLER">
<block type="device_set_analog_pin">
<field name="name">AnalogPin.C6</field>
<field name="name">AnalogPin.P9</field>
<value name="value">
<shadow type="math_number">
<field name="NUM">5</field>
@ -12,7 +12,7 @@
</value>
<next>
<block type="device_set_analog_period">
<field name="pin">AnalogPin.C6</field>
<field name="pin">AnalogPin.P10</field>
<value name="micros">
<shadow type="math_number">
<field name="NUM">20000</field>
@ -20,7 +20,7 @@
</value>
<next>
<block type="device_set_digital_pin">
<field name="name">DigitalPin.C6</field>
<field name="name">DigitalPin.P6</field>
<value name="value">
<shadow type="math_number">
<field name="NUM">5</field>
@ -28,7 +28,7 @@
</value>
<next>
<block type="device_set_servo_pin">
<field name="name">AnalogPin.C5</field>
<field name="name">AnalogPin.P13</field>
<value name="value">
<shadow type="math_number">
<field name="NUM">5</field>
@ -36,7 +36,7 @@
</value>
<next>
<block type="device_set_servo_pulse">
<field name="value">AnalogPin.C6</field>
<field name="value">AnalogPin.P8</field>
<value name="micros">
<shadow type="math_number" id="Hx4bpmg|8KSH=b_`+XtP">
<field name="NUM">1500</field>
@ -65,7 +65,7 @@
<field name="NUM">0</field>
</shadow>
<block type="pins_pulse_in">
<field name="name">DigitalPin.C9</field>
<field name="name">DigitalPin.P9</field>
<field name="value">PulseValue.Low</field>
</block>
</value>
@ -102,7 +102,7 @@
<field name="NUM">0</field>
</shadow>
<block type="device_get_digital_pin">
<field name="name">DigitalPin.C9</field>
<field name="name">DigitalPin.P9</field>
</block>
</value>
<value name="value">
@ -110,7 +110,7 @@
<field name="NUM">0</field>
</shadow>
<block type="device_get_analog_pin">
<field name="name">AnalogPin.C6</field>
<field name="name">AnalogPin.P9</field>
</block>
</value>
<value name="repeat">
@ -120,12 +120,12 @@
</value>
<next>
<block type="spi_pins">
<field name="mosi">DigitalPin.C11</field>
<field name="miso">DigitalPin.C9</field>
<field name="sck">DigitalPin.C10</field>
<field name="mosi">DigitalPin.P11</field>
<field name="miso">DigitalPin.P9</field>
<field name="sck">DigitalPin.P10</field>
<next>
<block type="device_set_pull">
<field name="pin">DigitalPin.C9</field>
<field name="pin">DigitalPin.P9</field>
<field name="pull">PinPullMode.PullDown</field>
<next>
<block type="device_analog_pitch">
@ -141,11 +141,11 @@
</value>
<next>
<block type="device_set_pin_events">
<field name="pin">DigitalPin.C8</field>
<field name="pin">DigitalPin.P8</field>
<field name="type">PinEventType.Touch</field>
<next>
<block type="device_analog_set_pitch_pin">
<field name="name">AnalogPin.C6</field>
<field name="name">AnalogPin.P9</field>
<next>
<block type="spi_format">
<value name="bits">

View File

@ -150,31 +150,31 @@
<field name="mode">DisplayMode.Greyscale</field>
<next>
<block type="device_set_analog_pin">
<field name="name">AnalogPin.C4</field>
<field name="name">AnalogPin.P4</field>
<value name="value">
<shadow type="math_number_minmax" id=",:%8N*FL3wa-zFQ[+^$9">
<mutation min="0" max="1023" label="Value"></mutation>
<field name="SLIDER">1023</field>
</shadow>
<block type="device_get_analog_pin">
<field name="name">AnalogPin.C5</field>
<field name="name">AnalogPin.P13</field>
</block>
</value>
<next>
<block type="device_set_digital_pin">
<field name="name">DigitalPin.C10</field>
<field name="name">DigitalPin.P10</field>
<value name="value">
<shadow type="math_number_minmax" id="W~pvdj%jFEj?EHmT{81Z">
<mutation min="0" max="1" label="Value"></mutation>
<field name="SLIDER">0</field>
</shadow>
<block type="device_get_digital_pin">
<field name="name">DigitalPin.C15</field>
<field name="name">DigitalPin.P15</field>
</block>
</value>
<next>
<block type="device_set_analog_period">
<field name="pin">AnalogPin.C6</field>
<field name="pin">AnalogPin.P9</field>
<value name="micros">
<shadow type="math_number" id="4a@.1MdG`n=p;34mQOpC">
<field name="NUM">1234</field>
@ -230,7 +230,7 @@
</value>
<next>
<block type="device_set_servo_pulse">
<field name="value">AnalogPin.C4</field>
<field name="value">AnalogPin.P14</field>
<value name="micros">
<shadow type="math_number" id="@*C3kzJkeeUQ@s$N5?K}">
<field name="NUM">1500</field>
@ -510,7 +510,7 @@
</statement>
</block>
<block type="pins_on_pulsed" x="1538" y="929">
<field name="pin">DigitalPin.C10</field>
<field name="pin">DigitalPin.P10</field>
<field name="pulse">PulseValue.Low</field>
<statement name="HANDLER">
<block type="i2c_writenumber">
@ -575,8 +575,8 @@
<next>
<block type="spi_pins">
<field name="mosi">DigitalPin.P9</field>
<field name="miso">DigitalPin.C14</field>
<field name="sck">DigitalPin.C16</field>
<field name="miso">DigitalPin.P14</field>
<field name="sck">DigitalPin.P16</field>
<next>
<block type="control_reset"></block>
</next>

View File

@ -8,6 +8,21 @@ PXT_ABI(__aeabi_dsub)
PXT_ABI(__aeabi_ddiv)
PXT_ABI(__aeabi_dmul)
#if MICROBIT_CODAL
namespace codal {
int list_fibers(Fiber **dest) {
int i = 0;
for (Fiber *fib = codal::get_fiber_list(); fib; fib = fib->next) {
if (dest)
dest[i] = fib;
i++;
}
return i;
}
} // namespace codal
#endif
extern "C" void target_panic(int error_code) {
#if !MICROBIT_CODAL
// wait for serial to flush
@ -28,6 +43,7 @@ namespace pxt {
MicroBit uBit;
MicroBitEvent lastEvent;
bool serialLoggingDisabled;
void platform_init() {
microbit_seed_random();
@ -152,6 +168,7 @@ int current_time_ms() {
}
static void logwriten(const char *msg, int l) {
if (!serialLoggingDisabled)
uBit.serial.send((uint8_t *)msg, l);
}

View File

@ -1,174 +1,4 @@
let compassImages = [
images.createImage(`
. . # . .
. . . . .
. . # . .
. . . . .
. . . . .
`),
images.createImage(`
. # . . .
. . . . .
. . # . .
. . . . .
. . . . .
`),
images.createImage(`
# . . . .
. . . . .
. . # . .
. . . . .
. . . . .
`),
images.createImage(`
. . . . .
# . . . .
. . # . .
. . . . .
. . . . .
`),
images.createImage(`
. . . . .
. . . . .
# . # . .
. . . . .
. . . . .
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
# . . . .
. . . . .
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . .
# . . . .
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . .
. # . . .
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . .
. . # . .
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . .
. . . # .
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . .
. . . . #
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . #
. . . . .
`),
images.createImage(`
. . . . .
. . . . .
. . # . #
. . . . .
. . . . .
`),
images.createImage(`
. . . . .
. . . . #
. . # . .
. . . . .
. . . . .
`),
images.createImage(`
. . . . #
. . . . .
. . # . .
. . . . .
. . . . .
`),
images.createImage(`
. . . # .
. . . . .
. . # . .
. . . . .
. . . . .
`)];
let compassImagesDownside = [
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . .
. . # . .
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . .
. . . # .
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . .
. . . . #
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . #
. . . . .
`),
images.createImage(`
. . . . .
. . . . .
. . # . #
. . . . .
. . . . .
`),
images.createImage(`
. . . . .
. . . . #
. . # . .
. . . . .
. . . . .
`),
images.createImage(`
. . . . #
. . . . .
. . # . .
. . . . .
. . . . .
`),
images.createImage(`
. . . # .
. . . . .
. . # . .
. . . . .
. . . . .
`),
const compassImagesLeft = [
images.createImage(`
. . # . .
. . . . .
@ -226,7 +56,66 @@ let compassImagesDownside = [
. # . . .
`)];
const compassImagesRight = [
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . .
. . # . .
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . .
. . . # .
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . .
. . . . #
`),
images.createImage(`
. . . . .
. . . . .
. . # . .
. . . . #
. . . . .
`),
images.createImage(`
. . . . .
. . . . .
. . # . #
. . . . .
. . . . .
`),
images.createImage(`
. . . . .
. . . . #
. . # . .
. . . . .
. . . . .
`),
images.createImage(`
. . . . #
. . . . .
. . # . .
. . . . .
. . . . .
`),
images.createImage(`
. . . # .
. . . . .
. . # . .
. . . . .
. . . . .
`)];
const compassImages = compassImagesLeft.concat(compassImagesRight);
const compassImagesDownside = compassImagesRight.concat(compassImagesLeft);
namespace basic {
@ -242,6 +131,7 @@ namespace basic {
//% interval.defl=600
//% parts="ledmatrix"
//% advanced=true
//% group="LED matrix"
export function showCompass(interval = 600) {
let i = 0
let startTime = input.runningTime()
@ -251,22 +141,15 @@ namespace basic {
while ((endTime) > (input.runningTime() + refreshRate)) {
i = Math.round((input.compassHeading() - 11.25) / 22.5)
if (input.isGesture(Gesture.ScreenDown)) {
compassImagesDownside[i].showImage(0, refreshRate)
} else {
compassImages[i].showImage(0, refreshRate)
}
let images = (input.isGesture(Gesture.ScreenDown)) ? compassImagesDownside : compassImages;
images[i].showImage(0, refreshRate)
}
rest = (endTime - input.runningTime())
if(rest > 0) {
i = Math.round((input.compassHeading() - 11.25) / 22.5)
if (input.isGesture(Gesture.ScreenDown)) {
compassImagesDownside[i].showImage(0, rest)
} else {
compassImages[i].showImage(0, rest)
}
let images = (input.isGesture(Gesture.ScreenDown)) ? compassImagesDownside : compassImages;
images[i].showImage(0, rest)
}
}

View File

@ -1,15 +1,51 @@
/// <reference no-default-lib="true"/>
enum ConsolePriority {
Debug = 0,
Log = 1,
Warning = 2,
Error = 3,
Silent = 4
}
/**
* Reading and writing data to the console output.
*/
//% weight=12 color=#002050 icon="\uf120"
//% advanced=true
namespace console {
type Listener = (text: string) => void;
type Listener = (priority: ConsolePriority, text: string) => void;
//% whenUsed
let listeners: Listener[] = undefined;
/**
* Minimum priority to send messages to listeners
*/
export let minPriority = ConsolePriority.Log;
let listeners: Listener[]
export function add(priority: ConsolePriority, message: any) {
if (priority < minPriority) return;
let text = inspect(message);
// add new line
text += "\n";
control.__log(priority, text)
// send to listeners
if (listeners)
for (let i = 0; i < listeners.length; ++i)
listeners[i](priority, text);
}
export function debug(text: any) {
add(ConsolePriority.Debug, text);
}
export function warn(text: any) {
add(ConsolePriority.Warning, text);
}
export function error(text: any) {
add(ConsolePriority.Error, text);
}
/**
* Write a line of text to the console output.
@ -17,15 +53,8 @@ namespace console {
*/
//% weight=90
//% help=console/log blockGap=8
export function log(text: any): void {
let stringified = inspect(text);
// pad text on the 32byte boundar
stringified += "\r\n";
control.__log(stringified);
// send to listeners
if (listeners)
for (let i = 0; i < listeners.length; ++i)
listeners[i](stringified);
export function log(value: any): void {
add(ConsolePriority.Log, value);
}
/**
@ -35,21 +64,8 @@ namespace console {
*/
//% weight=88 blockGap=8
//% help=console/log-value
export function logValue(name: any, value: number): void {
const nameText = inspect(name);
log(nameText ? `${nameText}: ${value}` : `${value}`)
}
/**
* Adds a listener for the log messages
* @param listener
*/
//%
export function addListener(listener: (text: string) => void) {
if (!listener) return;
if (!listeners)
listeners = [];
listeners.push(listener);
export function logValue(name: any, value: any): void {
log(name ? `${inspect(name)}: ${inspect(value)}` : `${inspect(value)}`)
}
/**
@ -82,8 +98,7 @@ namespace console {
keys = keys.slice(0, maxElements);
}
return `{${
keys.reduce(
return `{${keys.reduce(
(prev, currKey) => prev + `\n ${currKey}: ${obj[currKey]}`,
""
) + (snipped ? "\n ..." : "")
@ -91,4 +106,27 @@ namespace console {
}`;
}
}
/**
* Adds a listener for the log messages
* @param listener
*/
//%
export function addListener(listener: (priority: ConsolePriority, text: string) => void) {
if (!listeners) listeners = []
if (!listener || listeners.indexOf(listener) > -1) return;
listeners.push(listener);
}
/**
* Removes a listener
* @param listener
*/
//%
export function removeListener(listener: (priority: ConsolePriority, text: string) => void) {
if (!listener || !listeners) return;
const i = listeners.indexOf(listener);
if (i > -1)
listeners.splice(i, 1);
}
}

View File

@ -1,5 +1,7 @@
#include "pxt.h"
extern uint32_t __StackTop;
/**
* How to create the event.
*/
@ -271,8 +273,9 @@ namespace control {
* Blocks the current fiber for the given microseconds
* @param micros number of micro-seconds to wait. eg: 4
*/
//% help=control/wait-micros weight=29
//% help=control/wait-micros weight=29 async
//% blockId="control_wait_us" block="wait (µs)%micros"
//% micros.min=0 micros.max=6000
void waitMicros(int micros) {
sleep_us(micros);
}
@ -341,6 +344,15 @@ namespace control {
return microbit_serial_number();
}
/**
* Derive a unique, consistent 64-bit serial number of this device from internal data.
*/
//% help=control/device-long-serial-number
//% advanced=true
Buffer deviceLongSerialNumber() {
return mkBuffer((uint8_t*)&NRF_FICR->DEVICEID[0], sizeof(uint64_t));
}
/**
* Informs simulator/runtime of a MIDI message
* Internal function to support the simulator.
@ -354,8 +366,44 @@ namespace control {
*
*/
//%
void __log(String text) {
void __log(int priority, String text) {
if (NULL == text) return;
pxt::sendSerial(text->getUTF8Data(), text->getUTF8Size());
}
/**
* Allocates the next user notification event
*/
//% help=control/allocate-notify-event
int allocateNotifyEvent() {
#if MICROBIT_CODAL
return ::allocateNotifyEvent();
#else
static int notifyEv = 1024;
return ++notifyEv;
#endif
}
/** Write a message to DMESG debugging buffer. */
//%
void dmesg(String s) {
// this is no-op on v1
DMESG("# %s", s->getUTF8Data());
}
/** Write a message and value (pointer) to DMESG debugging buffer. */
//%
void dmesgPtr(String str, Object_ ptr) {
// this is no-op on v1
DMESG("# %s: %p", str->getUTF8Data(), ptr);
}
//%
uint32_t _ramSize()
{
return (uint32_t)&__StackTop & 0x1fffffff;
}
}

View File

@ -12,6 +12,11 @@ namespace control {
control.inBackground(a);
}
//% hidden=1 deprecated=1
export function runInBackground(a: () => void) {
control.inBackground(a);
}
/**
* Returns the value of a C++ runtime constant
*/
@ -31,6 +36,50 @@ namespace control {
return id;
}
export const enum PXT_PANIC {
CODAL_OOM = 20,
GC_OOM = 21,
GC_TOO_BIG_ALLOCATION = 22,
CODAL_HEAP_ERROR = 30,
CODAL_NULL_DEREFERENCE = 40,
CODAL_USB_ERROR = 50,
CODAL_HARDWARE_CONFIGURATION_ERROR = 90,
INVALID_BINARY_HEADER = 901,
OUT_OF_BOUNDS = 902,
REF_DELETED = 903,
SIZE = 904,
INVALID_VTABLE = 905,
INTERNAL_ERROR = 906,
NO_SUCH_CONFIG = 907,
NO_SUCH_PIN = 908,
INVALID_ARGUMENT = 909,
MEMORY_LIMIT_EXCEEDED = 910,
SCREEN_ERROR = 911,
MISSING_PROPERTY = 912,
INVALID_IMAGE = 913,
CALLED_FROM_ISR = 914,
HEAP_DUMPED = 915,
STACK_OVERFLOW = 916,
BLOCKING_TO_STRING = 917,
VM_ERROR = 918,
SETTINGS_CLEARED = 920,
SETTINGS_OVERLOAD = 921,
SETTINGS_SECRET_MISSING = 922,
DELETE_ON_CLASS = 923,
CAST_FIRST = 980,
CAST_FROM_UNDEFINED = 980,
CAST_FROM_BOOLEAN = 981,
CAST_FROM_NUMBER = 982,
CAST_FROM_STRING = 983,
CAST_FROM_OBJECT = 984,
CAST_FROM_FUNCTION = 985,
CAST_FROM_NULL = 989,
UNHANDLED_EXCEPTION = 999,
}
/**
* Display specified error code and stop the program.
*/
@ -61,6 +110,28 @@ namespace control {
*/
//% shim=pxtrt::runtimeWarning
export function runtimeWarning(message: string) { }
//% shim=pxt::programHash
export declare function programHash(): number;
//% shim=pxt::programName
export declare function programName(): string;
/** Returns estimated size of memory in bytes. */
//% shim=control::_ramSize
export function ramSize() {
return 32 * 1024 * 1024;
}
/** Runs the function and returns run time in microseconds. */
export function benchmark(f: () => void) {
const t0 = micros()
f()
let t = micros() - t0
if (t < 0)
t += 0x3fffffff
return t
}
}
/**

18
libs/core/enums.d.ts vendored
View File

@ -39,6 +39,22 @@ declare namespace basic {
}
declare const enum ButtonEvent {
//% blockIdentity="input.buttonEventValueId"
//% block="pressed down"
Down = 1, // MICROBIT_BUTTON_EVT_DOWN
//% blockIdentity="input.buttonEventValueId"
//% block="released up"
Up = 2, // MICROBIT_BUTTON_EVT_UP
//% blockIdentity="input.buttonEventValueId"
//% block="clicked"
Click = 3, // MICROBIT_BUTTON_EVT_CLICK
//% blockIdentity="input.buttonEventValueId"
//% block="long clicked"
LongClick = 4, // MICROBIT_BUTTON_EVT_LONG_CLICK
}
declare const enum Dimension {
//% block=x
X = 0,
@ -548,5 +564,7 @@ declare namespace motors {
}
declare namespace serial {
}
declare namespace storage {
}
// Auto-generated. Do not edit. Really.

View File

@ -65,87 +65,6 @@ enum IconNames {
//% block="meh"
//% jres=icons.meh
Meh,
//% block="t-shirt"
//% jres=icons.tshirt
TShirt,
//% block="roller skate"
//% jres=icons.rollerskate
Rollerskate,
//% block="duck"
//% jres=icons.duck
Duck,
//% block="house"
//% jres=icons.house
House,
//% block="tortoise"
//% jres=icons.tortoise
Tortoise,
//% block="butterfly"
//% jres=icons.butterfly
Butterfly,
//% block="stick figure"
//% jres=icons.stickfigure
StickFigure,
//% block="ghost"
//% jres=icons.ghost
Ghost,
//% block="sword"
//% jres=icons.sword
Sword,
//% block="giraffe"
//% jres=icons.giraffe
Giraffe,
//% block="skull"
//% jres=icons.skull
Skull,
//% block="umbrella"
//% jres=icons.umbrella
Umbrella,
//% block="snake"
//% jres=icons.snake
Snake,
//% block="rabbit"
//% jres=icons.rabbit
Rabbit,
//% block="cow"
//% jres=icons.cow
Cow,
//% block="quarter note"
//% jres=icons.quarternote
QuarterNote,
//% block="eigth note"
//% jres=icons.eigthnote
EigthNote,
//% block="pitchfork"
//% jres=icons.pitchfork
Pitchfork,
//% block="target"
//% jres=icons.target
Target,
//% block="triangle"
//% jres=icons.triangle
Triangle,
//% block="left triangle"
//% jres=icons.lefttriangle
LeftTriangle,
//% block="chess board"
//% jres=icons.chessboard
Chessboard,
//% block="diamond"
//% jres=icons.diamond
Diamond,
//% block="small diamond"
//% jres=icons.smalldiamond
SmallDiamond,
//% block="square"
//% jres=icons.square
Square,
//% block="small square"
//% jres=icons.smallsquare
SmallSquare,
//% block="scissors"
//% jres=icons.scissors
Scissors,
//% block="arrow north"
//% jres=icons.arrownorth
ArrowNorth,
@ -172,132 +91,36 @@ enum IconNames {
ArrowNorthWest
}
enum ArrowNames {
//% blockIdentity=images.arrowNumber block="North"
North = 0,
//% blockIdentity=images.arrowNumber block="North East"
NorthEast,
//% blockIdentity=images.arrowNumber block="East"
East,
//% blockIdentity=images.arrowNumber block="South East"
SouthEast,
//% blockIdentity=images.arrowNumber block="South"
South,
//% blockIdentity=images.arrowNumber block="South West"
SouthWest,
//% blockIdentity=images.arrowNumber block="West"
West,
//% blockIdentity=images.arrowNumber block="North West"
NorthWest
}
namespace basic {
/**
* Draws the selected icon on the LED screen
* @param icon the predefined icon id
* @param interval the amount of time (milliseconds) to show the icon. Default is 600.
* @param interval the amount of time (milliseconds) to block the LED Matrix for showing the icon. Default is 200.
*/
//% weight=90 blockGap=8
//% blockId=basic_show_icon
//% block="show icon %i" icon="\uf00a"
//% block="show icon %i || for %interval ms" icon="\uf00a"
//% parts="ledmatrix"
//% help=basic/show-icon
//% icon.fieldEditor="imagedropdown"
//% icon.fieldOptions.columns="5"
//% icon.fieldOptions.width="380"
//% icon.fieldOptions.maxRows=4
export function showIcon(icon: IconNames, interval = 600) {
//% expandableArgumentMode="toggle"
//% interval.defl=200
//% group="LED matrix"
export function showIcon(icon: IconNames, interval = 200) {
let res = images.iconImage(icon)
res.showImage(0, interval)
}
/**
* Draws an arrow on the LED screen
* @param direction the direction of the arrow
* @param interval the amount of time (milliseconds) to show the icon. Default is 600.
*/
//% weight=50 blockGap=8
//% blockId=basic_show_arrow
//% block="show arrow %i=device_arrow"
//% parts="ledmatrix"
//% advanced=true
//% help=basic/show-arrow
//% deprecated=true
export function showArrow(direction: number, interval = 600) {
let res = images.arrowImage(direction)
res.showImage(0, interval)
}
}
namespace images {
//% weight=50 blockGap=8
//% help=images/arrow-image
//% blockId=builtin_arrow_image block="arrow image %i"
//% deprecated=true
export function arrowImage(i: ArrowNames): Image {
switch (i) {
// compass directions
case ArrowNames.North: return images.createImage(`
. . # . .
. # # # .
# . # . #
. . # . .
. . # . .`);
case ArrowNames.NorthEast: return images.createImage(`
. . # # #
. . . # #
. . # . #
. # . . .
# . . . .`);
case ArrowNames.East: return images.createImage(`
. . # . .
. . . # .
# # # # #
. . . # .
. . # . .`);
case ArrowNames.SouthEast: return images.createImage(`
# . . . .
. # . . .
. . # . #
. . . # #
. . # # #`);
case ArrowNames.South: return images.createImage(`
. . # . .
. . # . .
# . # . #
. # # # .
. . # . .`);
case ArrowNames.SouthWest: return images.createImage(`
. . . . #
. . . # .
# . # . .
# # . . .
# # # . .`);
case ArrowNames.West: return images.createImage(`
. . # . .
. # . . .
# # # # #
. # . . .
. . # . .`);
case ArrowNames.NorthWest: return images.createImage(`
# # # . .
# # . . .
# . # . .
. . . # .
. . . . #`);
default: return images.createImage(`
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
`);
}
}
//% weight=50 blockGap=8
//% help=images/icon-image
//% blockId=builtin_image block="icon image %i"
@ -387,173 +210,6 @@ namespace images {
. . # . .
. # . # .
# . . . #`);
case IconNames.Triangle: return images.createImage(`
. . . . .
. . # . .
. # . # .
# # # # #
. . . . .`);
case IconNames.LeftTriangle: return images.createImage(`
# . . . .
# # . . .
# . # . .
# . . # .
# # # # #`);
case IconNames.Chessboard: return images.createImage(`
. # . # .
# . # . #
. # . # .
# . # . #
. # . # .`);
case IconNames.Diamond: return images.createImage(`
. . # . .
. # . # .
# . . . #
. # . # .
. . # . .`);
case IconNames.SmallDiamond: return images.createImage(`
. . . . .
. . # . .
. # . # .
. . # . .
. . . . .`);
case IconNames.Square: return images.createImage(`
# # # # #
# . . . #
# . . . #
# . . . #
# # # # #`);
case IconNames.SmallSquare: return images.createImage(`
. . . . .
. # # # .
. # . # .
. # # # .
. . . . .`);
case IconNames.Scissors: return images.createImage(`
# # . . #
# # . # .
. . # . .
# # . # .
# # . . #`);
// The following images were designed by Abbie Brooks.
case IconNames.TShirt: return images.createImage(`
# # . # #
# # # # #
. # # # .
. # # # .
. # # # .`);
case IconNames.Rollerskate: return images.createImage(`
. . . # #
. . . # #
# # # # #
# # # # #
. # . # .`);
case IconNames.Duck: return images.createImage(`
. # # . .
# # # . .
. # # # #
. # # # .
. . . . .`);
case IconNames.House: return images.createImage(`
. . # . .
. # # # .
# # # # #
. # # # .
. # . # .`);
case IconNames.Tortoise: return images.createImage(`
. . . . .
. # # # .
# # # # #
. # . # .
. . . . .`);
case IconNames.Butterfly: return images.createImage(`
# # . # #
# # # # #
. . # . .
# # # # #
# # . # #`);
case IconNames.StickFigure: return images.createImage(`
. . # . .
# # # # #
. . # . .
. # . # .
# . . . #`);
case IconNames.Ghost: return images.createImage(`
. # # # .
# . # . #
# # # # #
# # # # #
# . # . #`);
case IconNames.Sword: return images.createImage(`
. . # . .
. . # . .
. . # . .
. # # # .
. . # . .`);
case IconNames.Giraffe: return images.createImage(`
# # . . .
. # . . .
. # . . .
. # # # .
. # . # .`);
case IconNames.Skull: return images.createImage(`
. # # # .
# . # . #
# # # # #
. # # # .
. # # # .`);
case IconNames.Umbrella: return images.createImage(`
. # # # .
# # # # #
. . # . .
# . # . .
# # # . .`);
case IconNames.Snake: return images.createImage(`
# # . . .
# # . # #
. # . # .
. # # # .
. . . . .`);
// animals
case IconNames.Rabbit: return images.createImage(`
# . # . .
# . # . .
# # # # .
# # . # .
# # # # .`);
case IconNames.Cow: return images.createImage(`
# . . . #
# . . . #
# # # # #
. # # # .
. . # . .`);
// musical notes
case IconNames.QuarterNote: return images.createImage(`
. . # . .
. . # . .
. . # . .
# # # . .
# # # . .`);
case IconNames.EigthNote: return images.createImage(`
. . # . .
. . # # .
. . # . #
# # # . .
# # # . .`);
// other icons
case IconNames.Pitchfork: return images.createImage(`
# . # . #
# . # . #
# # # # #
. . # . .
. . # . .`);
case IconNames.Target: return images.createImage(`
. . # . .
. # # # .
# # . # #
. # # # .
. . # . .`);
// arrows
case IconNames.ArrowNorth: return images.createImage(`
. . # . .
@ -613,12 +269,4 @@ namespace images {
}
}
//% weight=50 blockGap=8
//% help=images/arrow-number
//% blockId=device_arrow block="%arrow"
//% shim=TD_ID
//% deprecated=true
export function arrowNumber(arrow: ArrowNames): number {
return arrow;
}
}

View File

@ -83,9 +83,11 @@ void plotImage(Image i, int xOffset = 0) {
/**
* Shows an frame from the image at offset ``x offset``.
* @param xOffset column index to start displaying the image
* @param interval time in milliseconds to pause after drawing
*/
//% help=images/show-image weight=80 blockNamespace=images
//% blockId=device_show_image_offset block="show image %sprite(myImage)|at offset %offset"
//% blockId=device_show_image_offset block="show image %sprite(myImage)|at offset %offset ||and interval (ms) %interval"
//% interval.defl=400
//% blockGap=8 parts="ledmatrix" async
void showImage(Image sprite, int xOffset, int interval = 400) {
uBit.display.print(MicroBitImage(sprite->img), -xOffset, 0, 0, interval);
@ -109,7 +111,7 @@ void plotFrame(Image i, int xOffset) {
*/
//% help=images/scroll-image weight=79 async blockNamespace=images
//% blockId=device_scroll_image
//% block="scroll image %sprite(myImage)|with offset %frameoffset|and interval (ms) %delay"
//% block="scroll image %sprite(myImage)|with offset %frameoffset|and interval (ms) %interval"
//% blockGap=8 parts="ledmatrix"
void scrollImage(Image id, int frameOffset, int interval) {
MicroBitImage i(id->img);

View File

@ -7,6 +7,21 @@ enum class Button {
AB = MICROBIT_ID_BUTTON_AB,
};
enum class ButtonEvent {
//% blockIdentity="input.buttonEventValueId"
//% block="pressed down"
Down = MICROBIT_BUTTON_EVT_DOWN,
//% blockIdentity="input.buttonEventValueId"
//% block="released up"
Up = MICROBIT_BUTTON_EVT_UP,
//% blockIdentity="input.buttonEventValueId"
//% block="clicked"
Click = MICROBIT_BUTTON_EVT_CLICK,
//% blockIdentity="input.buttonEventValueId"
//% block="long clicked"
LongClick = MICROBIT_BUTTON_EVT_LONG_CLICK,
};
enum class Dimension {
//% block=x
X = 0,
@ -161,6 +176,21 @@ enum class MesDpadButtonInfo {
//% color=#B4009E weight=99 icon="\uf192"
namespace input {
/**
* Do something when a button (A, B or both A+B) receives an event.
* @param button the button
* @param body code to run when event is raised
* @param eventType event Type
*/
//% help=input/on-button-event weight=100 blockGap=16
//% blockId=device_button_selected_event block="on button %NAME| %eventType=control_button_event_value_id"
//% parts="buttonpair"
//% group="Events"
void onButtonEvent(Button button, int eventType, Action body) {
registerWithDal((int)button, eventType, body);
}
/**
* Do something when a button (A, B or both A+B) is pushed down and released again.
* @param button the button that needs to be pressed
@ -169,6 +199,8 @@ namespace input {
//% help=input/on-button-pressed weight=85 blockGap=16
//% blockId=device_button_event block="on button|%NAME|pressed"
//% parts="buttonpair"
//% deprecated=true
//% group="Events"
void onButtonPressed(Button button, Action body) {
registerWithDal((int)button, MICROBIT_BUTTON_EVT_CLICK, body);
}
@ -178,10 +210,11 @@ namespace input {
* @param gesture the type of gesture to track, eg: Gesture.Shake
* @param body code to run when gesture is raised
*/
//% help=input/on-gesture weight=84 blockGap=16
//% help=input/on-gesture weight=98 blockGap=16
//% blockId=device_gesture_event block="on |%NAME"
//% parts="accelerometer"
//% NAME.fieldEditor="gestures" NAME.fieldOptions.columns=4
//% group="Events"
void onGesture(Gesture gesture, Action body) {
int gi = (int)gesture;
if (gi == MICROBIT_ACCELEROMETER_EVT_3G && uBit.accelerometer.getRange() < 3)
@ -195,10 +228,11 @@ namespace input {
* Tests if a gesture is currently detected.
* @param gesture the type of gesture to detect, eg: Gesture.Shake
*/
//% help=input/is-gesture weight=10 blockGap=8
//% help=input/is-gesture weight=86 blockGap=8
//% blockId=deviceisgesture block="is %gesture gesture"
//% parts="accelerometer"
//% gesture.fieldEditor="gestures" gesture.fieldOptions.columns=4
//% group="States"
bool isGesture(Gesture gesture) {
// turn on acceleration
uBit.accelerometer.getX();
@ -206,13 +240,33 @@ namespace input {
return uBit.accelerometer.getGesture() == gi;
}
/**
* Do something when a pin receives an touch event (while also touching the GND pin).
* @param name the pin, eg: TouchPin.P0
* @param body the code to run when event is fired on pin
*/
//% help=input/on-pin-touch weight=99 blockGap=16
//% blockId=device_pin_custom_event block="on pin %name| %eventType=control_button_event_value_id"
//% group="Events"
void onPinTouchEvent(TouchPin name, int eventType, Action body) {
auto pin = getPin((int)name);
if (!pin) return;
// Forces the PIN to switch to makey-makey style detection.
pin->isTouched();
registerWithDal((int)name, eventType, body);
}
/**
* Do something when a pin is touched and released again (while also touching the GND pin).
* @param name the pin that needs to be pressed, eg: TouchPin.P0
* @param body the code to run when the pin is pressed
*/
//% help=input/on-pin-pressed weight=83 blockGap=32
//% help=input/on-pin-pressed weight=83 blockGap=16
//% blockId=device_pin_event block="on pin %name|pressed"
//% group="Events"
//% deprecated=true
void onPinPressed(TouchPin name, Action body) {
auto pin = getPin((int)name);
if (!pin) return;
@ -230,6 +284,8 @@ namespace input {
//% help=input/on-pin-released weight=6 blockGap=16
//% blockId=device_pin_released block="on pin %NAME|released"
//% advanced=true
//% group="Events"
//% deprecated=true
void onPinReleased(TouchPin name, Action body) {
auto pin = getPin((int)name);
if (!pin) return;
@ -243,11 +299,12 @@ namespace input {
* Get the button state (pressed or not) for ``A`` and ``B``.
* @param button the button to query the request, eg: Button.A
*/
//% help=input/button-is-pressed weight=60
//% help=input/button-is-pressed weight=89
//% block="button|%NAME|is pressed"
//% blockId=device_get_button2
//% icon="\uf192" blockGap=8
//% parts="buttonpair"
//% group="States"
bool buttonIsPressed(Button button) {
if (button == Button::A)
return uBit.buttonA.isPressed();
@ -262,9 +319,10 @@ namespace input {
* Get the pin state (pressed or not). Requires to hold the ground to close the circuit.
* @param name pin used to detect the touch, eg: TouchPin.P0
*/
//% help=input/pin-is-pressed weight=58
//% help=input/pin-is-pressed weight=87
//% blockId="device_pin_is_pressed" block="pin %NAME|is pressed"
//% blockGap=8
//% group="States"
bool pinIsPressed(TouchPin name) {
auto pin = getPin((int)name);
return pin && pin->isTouched();
@ -284,6 +342,7 @@ namespace input {
//% help=input/acceleration weight=58
//% blockId=device_acceleration block="acceleration (mg)|%NAME" blockGap=8
//% parts="accelerometer"
//% group="Sensors"
int acceleration(Dimension dimension) {
switch (dimension) {
case Dimension::X: return uBit.accelerometer.getX();
@ -297,13 +356,37 @@ namespace input {
/**
* Reads the light level applied to the LED screen in a range from ``0`` (dark) to ``255`` bright.
*/
//% help=input/light-level weight=57
//% help=input/light-level weight=59
//% blockId=device_get_light_level block="light level" blockGap=8
//% parts="ledmatrix"
//% group="Sensors"
int lightLevel() {
return uBit.display.readLightLevel();
}
/**
* gets the level of loudness from 0 (silent) to 255 (loud)
*/
//% blockId="soundLevel" weight=58
//% block="soundLevel" blockGap=8
//% group="Sensors"
int soundLevel() {
int level = uBit.io.P21.getAnalogValue();
int min = level;
int max = level;
for (int i = 0; i < 32; i++) {
level = uBit.io.P21.getAnalogValue();
if (level > max) {
max = level;
} else if (level < min) {
min = level;
}
}
level = floor((max - min + 0.5) / 4); //max can be up to 1023; + 0,5 to prevent division by 0, floor to get rid of decimals, divide by 4 to get a value between 0 and 255
return level;
}
/**
* Get the current compass heading in degrees.
*/
@ -311,6 +394,7 @@ namespace input {
//% weight=56
//% blockId=device_heading block="compass heading (°)" blockGap=8
//% parts="compass"
//% group="Sensors"
int compassHeading() {
return uBit.compass.heading();
}
@ -319,10 +403,11 @@ namespace input {
/**
* Gets the temperature in Celsius degrees (°C).
*/
//% weight=55
//% weight=57
//% help=input/temperature
//% blockId=device_temperature block="temperature (°C)" blockGap=8
//% parts="thermometer"
//% group="Sensors"
int temperature() {
return uBit.thermometer.getTemperature();
}
@ -334,6 +419,7 @@ namespace input {
//% help=input/rotation weight=52
//% blockId=device_get_rotation block="rotation (°)|%NAME" blockGap=8
//% parts="accelerometer" advanced=true
//% group="Sensors"
int rotation(Rotation kind) {
switch (kind) {
case Rotation::Pitch: return uBit.accelerometer.getPitch();
@ -346,10 +432,11 @@ namespace input {
* Get the magnetic force value in ``micro-Teslas`` (``µT``). This function is not supported in the simulator.
* @param dimension the x, y, or z dimension, eg: Dimension.X
*/
//% help=input/magnetic-force weight=51
//% help=input/magnetic-force weight=49
//% blockId=device_get_magnetic_force block="magnetic force (µT)|%NAME" blockGap=8
//% parts="compass"
//% advanced=true
//% group="Sensors"
TNumber magneticForce(Dimension dimension) {
if (!uBit.compass.isCalibrated())
uBit.compass.calibrate();
@ -368,20 +455,58 @@ namespace input {
*/
//% help=input/calibrate-compass advanced=true
//% blockId="input_compass_calibrate" block="calibrate compass"
//% weight=45
//% weight=20 gap=8
//% group="Configuration"
void calibrateCompass() {
uBit.compass.calibrate();
}
/**
* Returns 'true' when the compass is calibrated. Otherwise returns 'false'.
*/
//% help=input/calibrate-compass advanced=true
//% blockId="input_compass_is_calibrated" block="is compass calibrated"
//% weight=19
//% group="System"
bool isCalibratedCompass() {
return (uBit.compass.isCalibrated() == 1);
}
/**
* Obsolete, compass calibration is automatic.
*/
//% help=input/calibrate-compass advanced=true
//% blockId="input_compass_clear_calibration" block="clear calibration compass"
//% weight=17
//% group="Configuration"
//% blockHidden=true
void clearCalibrationCompass() {
uBit.compass.clearCalibration();
}
/**
* Obsolete, compass calibration is automatic.
*/
//% help=input/calibrate-compass advanced=true
//% blockId="input_compass_assume_calibration" block="assume calibration compass"
//% weight=16
//% group="Configuration"
//% blockHidden=true
void assumeCalibrationCompass() {
uBit.compass.assumeCalibration();
}
/**
* Sets the accelerometer sample range in gravities.
* @param range a value describe the maximum strengh of acceleration measured
*/
//% help=input/set-accelerometer-range
//% blockId=device_set_accelerometer_range block="set accelerometer|range %range"
//% weight=5
//% weight=22 gap=8
//% parts="accelerometer"
//% advanced=true
//% group="Configuration"
void setAccelerometerRange(AcceleratorRange range) {
uBit.accelerometer.setRange((int)range);
}

View File

@ -1,69 +1,26 @@
/**
* Events and data from sensors
*/
//% color=#C90072 weight=99
//% color=#C90072 weight=99 icon="\uf192"
//% groups=['Events', 'States', 'Sensors', 'Configuration', 'System', 'others']
namespace input {
/**
* Attaches code to run when the screen is facing up.
* @param body TODO
* Returns the value of a C++ runtime constant
*/
//% help=input/on-screen-up
export function onScreenUp(body: () => void): void {
onGesture(Gesture.ScreenUp, body);
//% weight=1 weight=19 blockId="control_button_event_value_id" block="%id"
//% shim=TD_ID advanced=true
//% blockHidden=true
export function buttonEventValueId(id: ButtonEvent): number {
return id;
}
/**
* Attaches code to run when the screen is facing down.
* @param body TODO
*/
//% help=input/on-screen-down
export function onScreenDown(body: () => void): void {
onGesture(Gesture.ScreenDown, body);
}
/**
* 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);
}
/**
* Attaches code to run when the logo is oriented upwards and the board is vertical.
* @param body TODO
*/
//% help=input/on-logo-up
export function onLogoUp(body: () => void): void {
onGesture(Gesture.LogoUp, body);
}
/**
* Attaches code to run when the logo is oriented downwards and the board is vertical.
* @param body TODO
*/
//% help=input/on-logo-down
export function onLogoDown(body: () => void): void {
onGesture(Gesture.LogoDown, body);
}
/**
* Obsolete, use input.calibrateCompass instead.
*/
//% weight=0 help=input/calibrate-compass
export function calibrate() {
input.calibrateCompass();
}
/**
* Gets the number of milliseconds elapsed since power on.
*/
//% help=input/running-time weight=50 blockGap=8
//% blockId=device_get_running_time block="running time (ms)"
//% advanced=true
//% group="System"
export function runningTime() {
return control.millis();
}
@ -71,33 +28,12 @@ namespace input {
/**
* Gets the number of microseconds elapsed since power on.
*/
//% help=input/running-time-micros weight=49
//% help=input/running-time-micros weight=49 blockGap=8
//% blockId=device_get_running_time_micros block="running time (micros)"
//% advanced=true
//% group="System"
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
}
}

View File

@ -1,7 +1,41 @@
#include "pxt.h"
#if MICROBIT_CODAL
#include "neopixel.h"
// WS2812B timings, datasheet v1
// 0 - 0.25-0.55us hi 0.70-1.00us low
// 1 - 0.65-0.95us hi 0.30-0.60us low
// datasheet v5
// 0 - 0.22-0.38us hi 0.58-1.00us low
// 1 - 0.58-1.00us hi 0.58-1.00us low
// nrf52 asm timings:
// 0 0.34 - 0.78
// 1 0.80 - 0.59
extern "C" void __attribute__((long_call, section(".data")))
neopixel_send_buffer_nrf52(void *port500, uint32_t pinbr, const uint8_t *ptr, int numBytes);
__attribute__((noinline)) static void
neopixel_send_buffer_brightness(DevicePin &pin, const uint8_t *ptr, int numBytes, uint32_t br) {
if (br > 0x100)
br = 0x100;
pin.setDigitalValue(0);
target_wait_us(300); // initial reset
auto port = pin.name < 32 ? NRF_P0 : NRF_P1;
__disable_irq();
neopixel_send_buffer_nrf52((uint8_t *)(void *)port + 0x500, (pin.name & 31) | (br << 20), ptr,
numBytes);
__enable_irq();
}
static void neopixel_send_buffer(DevicePin &pin, const uint8_t *ptr, int numBytes) {
neopixel_send_buffer_brightness(pin, ptr, numBytes, 0x100);
}
#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,
@ -9,10 +43,24 @@ __attribute__((noinline)) static void neopixel_send_buffer(DevicePin &pin, const
// setup pin as digital
pin.setDigitalValue(0);
wait_us(300); // initial reset
__disable_irq();
neopixel_send_buffer_core(&pin, ptr, numBytes);
__enable_irq();
}
extern "C" void neopixel_send_buffer_brightness_core(DevicePin *pin, const uint8_t *ptr,
int numBytes, int br);
__attribute__((noinline)) static void
neopixel_send_buffer_brightness(DevicePin &pin, const uint8_t *ptr, int numBytes, int br) {
// setup pin as digital
pin.setDigitalValue(0);
wait_us(300); // initial reset
__disable_irq();
neopixel_send_buffer_brightness_core(&pin, ptr, numBytes, br);
__enable_irq();
}
#endif
namespace light {
@ -21,20 +69,28 @@ 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);
}
/**
* Sends a color buffer to a light strip
**/
//% advanced=true
void sendWS2812BufferWithBrightness(Buffer buf, int pin, int brightness) {
if (!buf || !buf->length)
return;
neopixel_send_buffer_brightness(*pxt::getPin(pin), buf->data, buf->length, brightness);
}
/**
* Sets the light mode of a pin
**/
//% advanced=true
//%
void setMode(int pin, int mode) {
}
void setMode(int pin, int mode) {}
} // namespace light

38
libs/core/loops.ts Normal file
View File

@ -0,0 +1,38 @@
namespace loops {
/**
* Repeats the code forever in the background.
* After each iteration, allows other codes to run for a set duration
* so that it runs on a timer
* @param interval time (in ms) to wait between each iteration of the action.
* @param body code to execute
*/
//% weight=45 blockAllowMultiple=1
//% interval.shadow=longTimePicker
//% afterOnStart=true help=loops/every-interval
//% blockId=every_interval block="every $interval ms"
export function everyInterval(interval: number, a: () => void): void {
control.runInParallel(() => {
let start = 0;
let now = 0;
while (true) {
start = control.millis();
a();
now = control.millis();
pause(Math.max(0, interval - (now - start)));
}
});
}
/**
* Get the time field editor
* @param ms time duration in milliseconds, eg: 500, 1000
*/
//% blockId=longTimePicker block="%ms"
//% blockHidden=true shim=TD_ID
//% colorSecondary="#FFFFFF"
//% ms.fieldEditor="numberdropdown" ms.fieldOptions.decompileLiterals=true
//% ms.fieldOptions.data='[["100 ms", 100], ["200 ms", 200], ["500 ms", 500], ["1 second", 1000], ["1 minute", 60000], ["1 hour", 3600000]]'
export function __timePicker(ms: number): number {
return ms;
}
}

27
libs/core/microphone.ts Normal file
View File

@ -0,0 +1,27 @@
/**
* Events and data from sensors
*/
//% color=#C90072 weight=99
namespace input {
/**
* gets the level of loudness from 0 (silent) to 255 (loud)
*/
//% blockId="loudness"
//% block="Loudness"
//% deprecated=true
export function loudness(): number {
let value = 0
let max = pins.analogReadPin(AnalogPin.MIC)
let min = max
for (let index = 0; index < 32; index++) {
value = pins.analogReadPin(AnalogPin.MIC)
if (value > max) {
max = value
} else if (value < min) {
min = value
}
}
value = Math.floor((max - min) / 4)
return value
}
}

View File

@ -28,6 +28,7 @@ namespace motors {
//% blockId=motor_on block="motor on at %percent \\%"
//% parts=dcmotor weight=90 blockGap=8
//% percent.shadow="speedPicker"
//% power.defl=100
void motorPower(int power) {
uBit.soundmotor.motorOn(power);
}
@ -51,13 +52,19 @@ namespace motors {
//% blockId=block_dual_motor block="motor %motor|at %percent \\%"
//% percent.shadow="speedPicker"
//% weight=80
//% duty_percent.defl=100
void dualMotorPower(Motor motor, int duty_percent) {
switch(motor) {
case Motor::A: if (duty_percent <= 0) uBit.soundmotor.motorAOff();
else uBit.soundmotor.motorAOn(duty_percent); break;
case Motor::B: if (duty_percent <= 0) uBit.soundmotor.motorBOff();
else uBit.soundmotor.motorBOn(duty_percent); break;
case Motor::AB: if (duty_percent <= 0) {
case Motor::A:
if (duty_percent <= 0) uBit.soundmotor.motorAOff();
else uBit.soundmotor.motorAOn(duty_percent);
break;
case Motor::B:
if (duty_percent <= 0) uBit.soundmotor.motorBOff();
else uBit.soundmotor.motorBOn(duty_percent);
break;
case Motor::AB:
if (duty_percent <= 0) {
uBit.soundmotor.motorAOff();
uBit.soundmotor.motorBOff();
} else {

View File

@ -1,5 +1,10 @@
#include "pxt.h"
namespace pins {
void analogSetPitchVolume(int volume);
int analogPitchVolume();
}
namespace music {
/**
* Plays a tone through ``speaker`` for the given duration.
@ -18,4 +23,41 @@ namespace music {
}
/**
* Set the default output volume of the sound synthesizer.
* @param volume the volume 0...255
*/
//% blockId=synth_set_volume block="set volume %volume"
//% volume.min=0 volume.max=255
//% volume.defl=127
//% help=music/set-volume
//% weight=70
//% group="Volume"
//% blockGap=8
//% blockHidden=true
void setVolume(int volume) {
#if MICROBIT_CODAL
uBit.audio.setVolume(max(0, min(255, volume)));
#else
pins::analogSetPitchVolume(volume);
#endif
}
/**
* Returns the current output volume of the sound synthesizer.
*/
//% blockId=synth_get_volume block="volume"
//% help=music/volume
//% weight=69
//% group="Volume"
//% blockGap=8
//% blockHidden=true
int volume() {
#if MICROBIT_CODAL
return uBit.audio.getVolume();
#else
return pins::analogPitchVolume();
#endif
}
}

View File

@ -223,7 +223,7 @@ namespace music {
//% help=music/rest weight=79
//% blockId=device_rest block="rest(ms)|%duration=device_beat"
//% parts="speaker"
//% group="Tone"
//% group="Silence"
export function rest(ms: number): void {
playTone(0, ms);
}
@ -233,7 +233,7 @@ namespace music {
* Gets the frequency of a note.
* @param name the note name
*/
//% weight=50 help=music/note-frequency
//% weight=50
//% blockId=device_note block="%name"
//% shim=TD_ID color="#FFFFFF" colorSecondary="#FFFFFF"
//% name.fieldEditor="note" name.defl="262"
@ -241,6 +241,7 @@ namespace music {
//% useEnumVal=1
//% group="Tone"
//% blockGap=8
//% blockHidden=true
export function noteFrequency(name: Note): number {
return name;
}
@ -289,6 +290,7 @@ namespace music {
//% help=music/change-tempo-by weight=39
//% blockId=device_change_tempo block="change tempo by (bpm)|%value" blockGap=8
//% group="Tempo"
//% weight=100
export function changeTempoBy(bpm: number): void {
init();
setTempo(beatsPerMinute + bpm);
@ -302,6 +304,7 @@ namespace music {
//% blockId=device_set_tempo block="set tempo to (bpm)|%value"
//% bpm.min=4 bpm.max=400
//% group="Tempo"
//% weight=99
export function setTempo(bpm: number): void {
init();
if (bpm > 0) {
@ -330,6 +333,7 @@ namespace music {
//% blockId=melody_on_event block="music on %value"
//% help=music/on-event weight=59 blockGap=32
//% group="Melody Advanced"
//% blockHidden=true
export function onEvent(value: MusicEvent, handler: () => void) {
control.onEvent(MICROBIT_MELODY_ID, value, handler);
}
@ -354,6 +358,7 @@ namespace music {
//% blockId=device_start_melody block="start melody %melody=device_builtin_melody| repeating %options"
//% parts="speaker"
//% group="Melody Advanced"
//% blockHidden=true
export function startMelody(melodyArray: string[], options: MelodyOptions = 1) {
init();
if (currentMelody != undefined) {
@ -453,7 +458,7 @@ namespace music {
//% help=music/stop-melody weight=59 blockGap=16
//% blockId=device_stop_melody block="stop melody $options"
//% parts="speaker"
//% group="Melody Advanced"
//% group="Silence"
export function stopMelody(options: MelodyStopOptions) {
if (options & MelodyStopOptions.Background)
startMelody([], MelodyOptions.OnceInBackground);
@ -461,6 +466,19 @@ namespace music {
startMelody([], MelodyOptions.Once);
}
/**
* Stop all sounds and melodies currently playing.
*/
//% help=music/stop-all-sounds
//% blockId=music_stop_all_sounds block="stop all sounds"
//% weight=10
//% group="Silence"
export function stopAllSounds() {
rest(0);
stopMelody(MelodyStopOptions.All);
}
/**
* Sets a custom playTone function for playing melodies
*/
@ -471,35 +489,6 @@ namespace music {
_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"
//% deprecated=true
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"
//% deprecated=true
export function volume(): number {
return pins.analogPitchVolume();
}
function playNextNote(melody: Melody): void {
// cache elements
let currNote = melody.nextNote();

View File

@ -1,5 +1,12 @@
#include "pxt.h"
#if MICROBIT_CODAL
#include "Pin.h"
#define PinCompat codal::Pin
#else
#define PinCompat MicroBitPin
#endif
enum class DigitalPin {
P0 = MICROBIT_ID_IO_P12, // edge connector 0
P1 = MICROBIT_ID_IO_P0, // edge connector 1
@ -217,6 +224,17 @@ namespace pins {
MicroBitPin* pin = getPin((int)name);
if (!pin) return 0;
#if MICROBIT_CODAL
// set polarity
pin->setPolarity(PulseValue::High == value ? 1 : 0);
// record pulse
int period = pin->getPulseUs(maxDuration);
// timeout
if (DEVICE_CANCELLED == period)
return 0;
// success!
return period;
#else
int pulse = value == PulseValue::High ? 1 : 0;
uint64_t tick = system_timer_current_time_us();
uint64_t maxd = (uint64_t)maxDuration;
@ -232,6 +250,7 @@ namespace pins {
}
uint64_t end = system_timer_current_time_us();
return end - start;
#endif
}
// TODO FIX THIS IN THE DAL!
@ -257,7 +276,6 @@ namespace pins {
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250"
void servoWritePin(AnalogPin name, int value) {
fixMotorIssue(name);
PINOP(setServoValue(value));
}
@ -284,9 +302,10 @@ namespace pins {
}
MicroBitPin* pitchPin = NULL;
MicroBitPin* pitchPin2 = NULL;
PinCompat* pitchPin = NULL;
PinCompat* pitchPin2 = NULL;
uint8_t pitchVolume = 0xff;
bool analogTonePlaying = false;
/**
* Set the pin used when using analog pitch or music.
@ -296,12 +315,13 @@ namespace pins {
//% help=pins/analog-set-pitch-pin weight=3 advanced=true
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250"
//% blockHidden=true
void analogSetPitchPin(AnalogPin name) {
pitchPin = getPin((int)name);
pitchPin2 = NULL;
}
void pinAnalogSetPitch(MicroBitPin* pin, int frequency, int ms) {
void pinAnalogSetPitch(PinCompat* pin, int frequency, int ms) {
if (frequency <= 0 || pitchVolume == 0) {
pin->setAnalogValue(0);
} else {
@ -318,8 +338,15 @@ namespace pins {
//% 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
//% blockHidden=true
void analogSetPitchVolume(int volume) {
pitchVolume = max(0, min(0xff, volume));
if (analogTonePlaying) {
int v = pitchVolume == 0 ? 0 : 1 << (pitchVolume >> 5);
if (NULL != pitchPin)
pitchPin->setAnalogValue(v);
}
}
/**
@ -327,6 +354,7 @@ namespace pins {
*/
//% blockId=device_analog_pitch_volume block="analog pitch volume"
//% help=pins/analog-pitch-volume weight=3 advanced=true
//% blockHidden=true
int analogPitchVolume() {
return pitchVolume;
}
@ -338,6 +366,7 @@ namespace pins {
*/
//% blockId=device_analog_pitch block="analog pitch %frequency|for (ms) %ms"
//% help=pins/analog-pitch weight=4 async advanced=true blockGap=8
//% blockHidden=true
void analogPitch(int frequency, int ms) {
// init pins if needed
if (NULL == pitchPin) {
@ -347,6 +376,7 @@ namespace pins {
#endif
}
// set pitch
analogTonePlaying = true;
if (NULL != pitchPin)
pinAnalogSetPitch(pitchPin, frequency, ms);
if (NULL != pitchPin2)
@ -356,9 +386,9 @@ namespace pins {
fiber_sleep(ms);
if (NULL != pitchPin)
pitchPin->setAnalogValue(0);
if (NULL != pitchPin2)
pitchPin2->setAnalogValue(0);
fiber_sleep(5);
analogTonePlaying = false;
// causes issues with v2 DMA.
// fiber_sleep(5);
}
}
@ -412,6 +442,21 @@ namespace pins {
return mkBuffer(NULL, size);
}
/**
* Set the matrix width for Neopixel strip (already assigned to a pin).
* Should be used in conjunction with `set matrix width` from Neopixel package.
* @param name pin of Neopixel strip, eg: DigitalPin.P1
* @param value width of matrix (at least ``2``)
*/
//% help=pins/neopixel-matrix-width weight=3 advanced=true
//% blockId=pin_neopixel_matrix_width block="neopixel matrix width|pin %pin %width" blockGap=8
//% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4
//% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="250"
//% width.defl=5 width.min=2
//% blockHidden=true
void setMatrixWidth(DigitalPin pin, int width) {}
#if MICROBIT_CODAL
#define BUFFER_TYPE uint8_t*
#else
@ -534,10 +579,26 @@ namespace pins {
*/
//% help=pins/push-button advanced=true
void pushButton(DigitalPin pin) {
new MicroBitButton((PinName)getPin((int)(pin))->name, (int)pin, MICROBIT_BUTTON_ALL_EVENTS, PinMode::PullUp);
}
/**
* Set the pin used when producing sounds and melodies. Default is P0.
* @param name pin to modulate pitch from
*/
//% blockId=pin_set_audio_pin block="set audio pin $name"
//% help=pins/set-audio-pin weight=3
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250"
//% weight=1
//% blockHidden=true
void setAudioPin(AnalogPin name) {
#if MICROBIT_CODAL
new MicroBitButton(PIN_ARG(pin), (int)pin, DEVICE_BUTTON_ALL_EVENTS, ACTIVE_LOW, codal::PullMode::Up);
uBit.audio.setPin(*getPin((int)name));
uBit.audio.setPinEnabled(true);
#else
new MicroBitButton(PIN_ARG(pin), PinMode::PullUp);
// v1 behavior
pins::analogSetPitchPin(name);
#endif
}
}

View File

@ -45,6 +45,7 @@ typedef RefMImage *Image;
extern MicroBit uBit;
extern MicroBitEvent lastEvent;
extern bool serialLoggingDisabled;
MicroBitPin *getPin(int id);

View File

@ -33,12 +33,16 @@
"gestures.jres",
"control.ts",
"control.cpp",
"controlgc.cpp",
"perfcounters.ts",
"interval.ts",
"gcstats.ts",
"console.ts",
"game.ts",
"led.cpp",
"led.ts",
"loops.ts",
"microphone.ts",
"motors.cpp",
"music.cpp",
"music.ts",
@ -49,12 +53,19 @@
"serial.ts",
"buffer.cpp",
"buffer.ts",
"json.ts",
"poll.ts",
"controlmessage.ts",
"pxtparts.json",
"advmath.cpp",
"trig.cpp",
"fixed.ts",
"templates.ts",
"sendbuffer.s",
"sendbuffernrf52.s",
"sendbufferbrightness.s",
"storage.cpp",
"storage.ts",
"light.cpp",
"compass.ts",
"parts/speaker.svg",
@ -94,63 +105,63 @@
"yotta": {
"config": {
"microbit-dal": {
"fiber_user_data": 1
"fiber_user_data": 1,
"pxt": 1
}
},
"optionalConfig": {
"microbit-dal": {
"bluetooth": {
"enabled": 1,
"pairing_mode": 1,
"private_addressing": 0,
"open": 1,
"security_level": null,
"whitelist": 1,
"advertising_timeout": 0,
"tx_power": 6,
"dfu_service": 1,
"event_service": 1,
"device_info_service": 1,
"eddystone_url": 1,
"eddystone_uid": 1,
"open": 0,
"pairing_mode": 1,
"whitelist": 1,
"security_level": "SECURITY_MODE_ENCRYPTION_NO_MITM",
"partial_flashing": 1
}
}
"event_service": 0,
"device_info_service": 0
},
"stack_size": 2048,
"gatt_table_size": "0x600",
"panic_on_heap_full": 0,
"debug": 0,
"heap_debug": 0,
"sram_end": "0x20008000"
},
"RAM_SIZE": "\"32K\""
},
"userConfigs": [
{
"description": "No Pairing Required: Anyone can connect via Bluetooth.",
"description": "Limit bluetooth access to BLE mode (A + B + Reset)",
"config": {
"microbit-dal": {
"bluetooth": {
"open": 1,
"whitelist": 0,
"security_level": null
"enabled": 0
}
}
}
},
{
"description": "JustWorks pairing (default): Pairing is automatic once the pairing is initiated.",
"description": "32K RAM (mini v2 and some v1.3)",
"config": {
"microbit-dal": {
"bluetooth": {
"open": 0,
"whitelist": 1,
"security_level": "SECURITY_MODE_ENCRYPTION_NO_MITM"
}
}
"stack_size": 2048,
"sram_end": "0x20008000"
},
"RAM_SIZE": "\"32K\""
}
},
{
"description": "Passkey pairing: Pairing requires 6 digit key to pair.",
"description": "16K RAM (mini v1.3 and below)",
"config": {
"microbit-dal": {
"bluetooth": {
"open": 0,
"whitelist": 1,
"security_level": "SECURITY_MODE_ENCRYPTION_WITH_MITM"
}
}
"stack_size": 1280,
"sram_end": "0x20004000"
},
"RAM_SIZE": "\"16K\""
}
}
]

View File

@ -16,14 +16,13 @@ void debuglog(const char *format, ...);
#define GC_MAX_ALLOC_SIZE 9000
#define GC_BLOCK_SIZE 256
#define NON_GC_HEAP_RESERVATION 1024
#ifdef CODAL_CONFIG_H
#define MICROBIT_CODAL 1
#else
#define MICROBIT_CODAL 0
#define GC_BLOCK_SIZE 256
#endif
#if !MICROBIT_CODAL

View File

@ -0,0 +1,53 @@
.syntax unified
.section .text.neopixel_send_buffer_brightness_core
.global neopixel_send_buffer_brightness_core
neopixel_send_buffer_brightness_core:
push {r4,r5,r6,r7,lr}
mov r4, r1 // ptr
mov r5, r2 // len
mov r7, r3 // get the brightness figure
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
ldrb r0, [r4, #0] // r0 := *r4
muls r0, r7 // hope we have single cycle multiplier...
lsrs r0, r0, #8 // r0 >>= 8 following multiplication
.common: // C13
str r1, [r2, #0] // pin := lo C15
nop // twiddle
nop // twaddle
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}

View File

@ -0,0 +1,82 @@
.syntax unified
#ifndef NRF51
// put it in RAM
.section .data.neopixel_send_buffer_nrf52
.global neopixel_send_buffer_nrf52
.thumb
.type neopixel_send_buffer_nrf52, %function
neopixel_send_buffer_nrf52:
push {r4,r5,r6,r7,lr}
lsrs r7, r1, #20 // r7 - brightness
ands r1, #0xff
movs r4, #1
lsls r1, r4, r1 // r1 - mask
mov r4, r2 // ptr
mov r5, r3 // len
mov r3, r0 // port+0x500
b .start
.nextbit:
str r1, [r3, #0x8] // pin := hi
movs r2, #8
tst r6, r0
it eq
movseq r2, #3
.d1:
subs r2, #1
bne .d1
str r1, [r3, #0xC] // pin := lo
movs r2, #4
tst r6, r0
it eq
movseq r2, #6
lsrs r6, r6, #1 // r6 >>= 1
beq .reload
nop
nop
nop
.d0:
subs r2, #1
bne .d0
b .nextbit
.reload:
subs r2, #2 // offset following operations
.d2:
subs r2, #1
bne .d2
// not just a bit - need new byte
adds r4, #1 // r4++
subs r5, #1 // r5--
ble .stop // if (r5<=0) goto .stop
.start:
movs r6, #0x80 // reset mask
ldrb r0, [r4, #0] // r0 := *r4
muls r0, r7
lsrs r0, r0, #8 // r0 >>= 8
str r1, [r3, #0xC] // pin := lo
b .nextbit //
.stop:
str r1, [r3, #0xC] // pin := lo
pop {r4,r5,r6,r7,pc}
#endif

View File

@ -106,24 +106,29 @@ namespace serial {
}
/**
* Read multiple characters from the receive buffer. Pause until enough characters are present.
* @param length default buffer length, eg: 64
* Read multiple characters from the receive buffer.
* If length is positive, pauses until enough characters are present.
* @param length default buffer length
*/
//% blockId=serial_readbuffer block="serial|read buffer %length"
//% help=serial/read-buffer advanced=true weight=5
Buffer readBuffer(int length) {
if (length <= 0)
length = MICROBIT_SERIAL_READ_BUFFER_LENGTH;
auto buf = mkBuffer(NULL, length);
int read = uBit.serial.read(buf->data, buf->length);
if (read != length) {
auto prev = buf;
buf = mkBuffer(buf->data, read);
decrRC(prev);
auto mode = SYNC_SLEEP;
if (length <= 0) {
length = uBit.serial.getRxBufferSize();
mode = ASYNC;
}
return buf;
auto buf = mkBuffer(NULL, length);
auto res = buf;
registerGCObj(buf); // make sure buffer is pinned, while we wait for data
int read = uBit.serial.read(buf->data, buf->length, mode);
if (read != length) {
res = mkBuffer(buf->data, read);
}
unregisterGCObj(buf);
return res;
}
bool tryResolvePin(SerialPin p, PinName& name) {

407
libs/core/shims.d.ts vendored
View File

@ -37,9 +37,11 @@ declare interface Image {
/**
* Shows an frame from the image at offset ``x offset``.
* @param xOffset column index to start displaying the image
* @param interval time in milliseconds to pause after drawing
*/
//% help=images/show-image weight=80 blockNamespace=images
//% blockId=device_show_image_offset block="show image %sprite(myImage)|at offset %offset"
//% blockId=device_show_image_offset block="show image %sprite(myImage)|at offset %offset ||and interval (ms) %interval"
//%
//% blockGap=8 parts="ledmatrix" async interval.defl=400 shim=ImageMethods::showImage
showImage(xOffset: int32, interval?: int32): void;
@ -58,7 +60,7 @@ declare interface Image {
*/
//% help=images/scroll-image weight=79 async blockNamespace=images
//% blockId=device_scroll_image
//% block="scroll image %sprite(myImage)|with offset %frameoffset|and interval (ms) %delay"
//% block="scroll image %sprite(myImage)|with offset %frameoffset|and interval (ms) %interval"
//% blockGap=8 parts="ledmatrix" shim=ImageMethods::scrollImage
scrollImage(frameOffset: int32, interval: int32): void;
@ -127,67 +129,48 @@ declare interface Image {
/**
* Provides access to basic micro:bit functionality.
*/
//% color=#1E90FF weight=116 icon="\uf00a"
declare namespace basic {
/**
* Sets the color on the build-in LED. Set to 0 to turn off.
*/
//% blockId=device_set_led_color
//% block="set led to %color=colorNumberPicker"
//% weight=50 shim=basic::setLedColor
function setLedColor(color: int32): void;
/**
* Sets the color on the build-in LED. Set to 0 to turn off.
*/
//% blockId=device_turn_rgb_led_off block="turn build-in LED off"
//% weight=50 shim=basic::turnRgbLedOff
function turnRgbLedOff(): void;
/**
* Draws an image on the LED screen.
* @param leds the pattern of LED to turn on/off
* @param interval time in milliseconds to pause after drawing
*/
//% help=basic/show-leds
//% weight=95 blockGap=8
//% weight=85 blockGap=8
//% imageLiteral=1 async
//% blockId=device_show_leds
//% block="show leds" icon="\uf00a"
//% parts="ledmatrix" interval.defl=400 shim=basic::showLeds
//% parts="ledmatrix"
//% group="LED matrix" interval.defl=400 shim=basic::showLeds
function showLeds(leds: string, interval?: int32): void;
/**
* Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll.
* @param text the text to scroll on the screen, eg: "hi!"
* @param interval how fast to shift characters; eg: 150, 100, 200, -100
* @param interval how fast to shift characters; eg: 50, 100, 150, 200
*/
//% help=basic/show-string
//% weight=87 blockGap=16
//% block="show|string %text"
//% weight=100 blockGap=16
//% block="show|string %text || in an interval of %interval ms"
//% async
//% blockId=device_print_message
//% parts="ledmatrix"
//% text.shadowOptions.toString=true interval.defl=150 shim=basic::showString
//% text.shadowOptions.toString=true
//% expandableArgumentMode="toggle"
//%
//% group="LED matrix" interval.defl=80 shim=basic::showString
function showString(text: string, interval?: int32): void;
/**
* Turn off all LEDs
*/
//% help=basic/clear-screen weight=79
//% blockId=device_clear_display block="clear screen"
//% parts="ledmatrix"
//% advanced=true shim=basic::clearScreen
function clearScreen(): void;
/**
* Shows a sequence of LED screens as an animation.
* @param leds pattern of LEDs to turn on/off
* @param interval time in milliseconds between each redraw
*/
//% help=basic/show-animation imageLiteral=1 async
//% parts="ledmatrix" interval.defl=400 shim=basic::showAnimation
//% help=basic/show-animation weight=83 imageLiteral=1 async
//% parts="ledmatrix"
//% group="LED matrix" interval.defl=400 shim=basic::showAnimation
function showAnimation(leds: string, interval?: int32): void;
/**
@ -195,26 +178,57 @@ declare namespace basic {
* @param leds pattern of LEDs to turn on/off
*/
//% help=basic/plot-leds weight=80
//% parts="ledmatrix" imageLiteral=1 shim=basic::plotLeds
//% parts="ledmatrix"
//% group="LED matrix" imageLiteral=1 shim=basic::plotLeds
function plotLeds(leds: string): void;
/**
* Turn off all LEDs
*/
//% help=basic/clear-screen weight=75
//% blockId=device_clear_display block="clear screen"
//% parts="ledmatrix"
//% group="LED matrix"
//% advanced=true shim=basic::clearScreen
function clearScreen(): void;
/**
* Repeats the code forever in the background. On each iteration, allows other codes to run.
* @param body code to execute
*/
//% help=basic/forever weight=55 blockGap=16 blockAllowMultiple=1 afterOnStart=true
//% blockId=device_forever block="forever" icon="\uf01e" shim=basic::forever
//% blockId=device_forever block="forever" icon="\uf01e"
//% group="Control" shim=basic::forever
function forever(a: () => void): void;
/**
* Pause for the specified time in milliseconds
* @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000
*/
//% help=basic/pause weight=54
//% help=basic/pause weight=50
//% async block="pause (ms) %pause" blockGap=16
//% blockId=device_pause icon="\uf110"
//% pause.shadow=timePicker shim=basic::pause
//% pause.shadow=timePicker
//% group="Control" shim=basic::pause
function pause(ms: int32): void;
/**
* Sets the color on the build-in LED. Set to 0 to turn off.
*/
//% blockId=device_set_led_color
//% block="set led to %color=colorNumberPicker"
//% weight=10
//% group="RGB LED" shim=basic::setLedColor
function setLedColor(color: int32): void;
/**
* Sets the color on the build-in LED. Set to 0 to turn off.
*/
//% blockId=device_turn_rgb_led_off block="turn build-in LED off"
//% weight=10
//% group="RGB LED"
//% advanced=true shim=basic::turnRgbLedOff
function turnRgbLedOff(): void;
}
@ -222,6 +236,18 @@ declare namespace basic {
//% color=#B4009E weight=99 icon="\uf192"
declare namespace input {
/**
* Do something when a button (A, B or both A+B) receives an event.
* @param button the button
* @param body code to run when event is raised
* @param eventType event Type
*/
//% help=input/on-button-event weight=100 blockGap=16
//% blockId=device_button_selected_event block="on button %NAME| %eventType=control_button_event_value_id"
//% parts="buttonpair"
//% group="Events" shim=input::onButtonEvent
function onButtonEvent(button: Button, eventType: int32, body: () => void): void;
/**
* Do something when a button (A, B or both A+B) is pushed down and released again.
* @param button the button that needs to be pressed
@ -229,7 +255,9 @@ declare namespace input {
*/
//% help=input/on-button-pressed weight=85 blockGap=16
//% blockId=device_button_event block="on button|%NAME|pressed"
//% parts="buttonpair" shim=input::onButtonPressed
//% parts="buttonpair"
//% deprecated=true
//% group="Events" shim=input::onButtonPressed
function onButtonPressed(button: Button, body: () => void): void;
/**
@ -237,29 +265,43 @@ declare namespace input {
* @param gesture the type of gesture to track, eg: Gesture.Shake
* @param body code to run when gesture is raised
*/
//% help=input/on-gesture weight=84 blockGap=16
//% help=input/on-gesture weight=98 blockGap=16
//% blockId=device_gesture_event block="on |%NAME"
//% parts="accelerometer"
//% NAME.fieldEditor="gestures" NAME.fieldOptions.columns=4 shim=input::onGesture
//% NAME.fieldEditor="gestures" NAME.fieldOptions.columns=4
//% group="Events" shim=input::onGesture
function onGesture(gesture: Gesture, body: () => void): void;
/**
* Tests if a gesture is currently detected.
* @param gesture the type of gesture to detect, eg: Gesture.Shake
*/
//% help=input/is-gesture weight=10 blockGap=8
//% help=input/is-gesture weight=86 blockGap=8
//% blockId=deviceisgesture block="is %gesture gesture"
//% parts="accelerometer"
//% gesture.fieldEditor="gestures" gesture.fieldOptions.columns=4 shim=input::isGesture
//% gesture.fieldEditor="gestures" gesture.fieldOptions.columns=4
//% group="States" shim=input::isGesture
function isGesture(gesture: Gesture): boolean;
/**
* Do something when a pin receives an touch event (while also touching the GND pin).
* @param name the pin, eg: TouchPin.P0
* @param body the code to run when event is fired on pin
*/
//% help=input/on-pin-touch weight=99 blockGap=16
//% blockId=device_pin_custom_event block="on pin %name| %eventType=control_button_event_value_id"
//% group="Events" shim=input::onPinTouchEvent
function onPinTouchEvent(name: TouchPin, eventType: int32, body: () => void): void;
/**
* Do something when a pin is touched and released again (while also touching the GND pin).
* @param name the pin that needs to be pressed, eg: TouchPin.P0
* @param body the code to run when the pin is pressed
*/
//% help=input/on-pin-pressed weight=83 blockGap=32
//% blockId=device_pin_event block="on pin %name|pressed" shim=input::onPinPressed
//% help=input/on-pin-pressed weight=83 blockGap=16
//% blockId=device_pin_event block="on pin %name|pressed"
//% group="Events"
//% deprecated=true shim=input::onPinPressed
function onPinPressed(name: TouchPin, body: () => void): void;
/**
@ -269,27 +311,31 @@ declare namespace input {
*/
//% help=input/on-pin-released weight=6 blockGap=16
//% blockId=device_pin_released block="on pin %NAME|released"
//% advanced=true shim=input::onPinReleased
//% advanced=true
//% group="Events"
//% deprecated=true shim=input::onPinReleased
function onPinReleased(name: TouchPin, body: () => void): void;
/**
* Get the button state (pressed or not) for ``A`` and ``B``.
* @param button the button to query the request, eg: Button.A
*/
//% help=input/button-is-pressed weight=60
//% help=input/button-is-pressed weight=89
//% block="button|%NAME|is pressed"
//% blockId=device_get_button2
//% icon="\uf192" blockGap=8
//% parts="buttonpair" shim=input::buttonIsPressed
//% parts="buttonpair"
//% group="States" shim=input::buttonIsPressed
function buttonIsPressed(button: Button): boolean;
/**
* Get the pin state (pressed or not). Requires to hold the ground to close the circuit.
* @param name pin used to detect the touch, eg: TouchPin.P0
*/
//% help=input/pin-is-pressed weight=58
//% help=input/pin-is-pressed weight=87
//% blockId="device_pin_is_pressed" block="pin %NAME|is pressed"
//% blockGap=8 shim=input::pinIsPressed
//% blockGap=8
//% group="States" shim=input::pinIsPressed
function pinIsPressed(name: TouchPin): boolean;
/**
@ -298,33 +344,45 @@ declare namespace input {
*/
//% help=input/acceleration weight=58
//% blockId=device_acceleration block="acceleration (mg)|%NAME" blockGap=8
//% parts="accelerometer" shim=input::acceleration
//% parts="accelerometer"
//% group="Sensors" shim=input::acceleration
function acceleration(dimension: Dimension): int32;
/**
* Reads the light level applied to the LED screen in a range from ``0`` (dark) to ``255`` bright.
*/
//% help=input/light-level weight=57
//% help=input/light-level weight=59
//% blockId=device_get_light_level block="light level" blockGap=8
//% parts="ledmatrix" shim=input::lightLevel
//% parts="ledmatrix"
//% group="Sensors" shim=input::lightLevel
function lightLevel(): int32;
/**
* gets the level of loudness from 0 (silent) to 255 (loud)
*/
//% blockId="soundLevel" weight=58
//% block="soundLevel" blockGap=8
//% group="Sensors" shim=input::soundLevel
function soundLevel(): int32;
/**
* Get the current compass heading in degrees.
*/
//% help=input/compass-heading
//% weight=56
//% blockId=device_heading block="compass heading (°)" blockGap=8
//% parts="compass" shim=input::compassHeading
//% parts="compass"
//% group="Sensors" shim=input::compassHeading
function compassHeading(): int32;
/**
* Gets the temperature in Celsius degrees (°C).
*/
//% weight=55
//% weight=57
//% help=input/temperature
//% blockId=device_temperature block="temperature (°C)" blockGap=8
//% parts="thermometer" shim=input::temperature
//% parts="thermometer"
//% group="Sensors" shim=input::temperature
function temperature(): int32;
/**
@ -333,17 +391,19 @@ declare namespace input {
*/
//% help=input/rotation weight=52
//% blockId=device_get_rotation block="rotation (°)|%NAME" blockGap=8
//% parts="accelerometer" advanced=true shim=input::rotation
//% parts="accelerometer" advanced=true
//% group="Sensors" shim=input::rotation
function rotation(kind: Rotation): int32;
/**
* Get the magnetic force value in ``micro-Teslas`` (``µT``). This function is not supported in the simulator.
* @param dimension the x, y, or z dimension, eg: Dimension.X
*/
//% help=input/magnetic-force weight=51
//% help=input/magnetic-force weight=49
//% blockId=device_get_magnetic_force block="magnetic force (µT)|%NAME" blockGap=8
//% parts="compass"
//% advanced=true shim=input::magneticForce
//% advanced=true
//% group="Sensors" shim=input::magneticForce
function magneticForce(dimension: Dimension): number;
/**
@ -351,18 +411,49 @@ declare namespace input {
*/
//% help=input/calibrate-compass advanced=true
//% blockId="input_compass_calibrate" block="calibrate compass"
//% weight=45 shim=input::calibrateCompass
//% weight=20 gap=8
//% group="Configuration" shim=input::calibrateCompass
function calibrateCompass(): void;
/**
* Returns 'true' when the compass is calibrated. Otherwise returns 'false'.
*/
//% help=input/calibrate-compass advanced=true
//% blockId="input_compass_is_calibrated" block="is compass calibrated"
//% weight=19
//% group="System" shim=input::isCalibratedCompass
function isCalibratedCompass(): boolean;
/**
* Obsolete, compass calibration is automatic.
*/
//% help=input/calibrate-compass advanced=true
//% blockId="input_compass_clear_calibration" block="clear calibration compass"
//% weight=17
//% group="Configuration"
//% blockHidden=true shim=input::clearCalibrationCompass
function clearCalibrationCompass(): void;
/**
* Obsolete, compass calibration is automatic.
*/
//% help=input/calibrate-compass advanced=true
//% blockId="input_compass_assume_calibration" block="assume calibration compass"
//% weight=16
//% group="Configuration"
//% blockHidden=true shim=input::assumeCalibrationCompass
function assumeCalibrationCompass(): void;
/**
* Sets the accelerometer sample range in gravities.
* @param range a value describe the maximum strengh of acceleration measured
*/
//% help=input/set-accelerometer-range
//% blockId=device_set_accelerometer_range block="set accelerometer|range %range"
//% weight=5
//% weight=22 gap=8
//% parts="accelerometer"
//% advanced=true shim=input::setAccelerometerRange
//% advanced=true
//% group="Configuration" shim=input::setAccelerometerRange
function setAccelerometerRange(range: AcceleratorRange): void;
}
@ -410,8 +501,9 @@ declare namespace control {
* Blocks the current fiber for the given microseconds
* @param micros number of micro-seconds to wait. eg: 4
*/
//% help=control/wait-micros weight=29
//% blockId="control_wait_us" block="wait (µs)%micros" shim=control::waitMicros
//% help=control/wait-micros weight=29 async
//% blockId="control_wait_us" block="wait (µs)%micros"
//% micros.min=0 micros.max=6000 shim=control::waitMicros
function waitMicros(micros: int32): void;
/**
@ -465,6 +557,13 @@ declare namespace control {
//% advanced=true shim=control::deviceSerialNumber
function deviceSerialNumber(): int32;
/**
* Derive a unique, consistent 64-bit serial number of this device from internal data.
*/
//% help=control/device-long-serial-number
//% advanced=true shim=control::deviceLongSerialNumber
function deviceLongSerialNumber(): Buffer;
/**
* Informs simulator/runtime of a MIDI message
* Internal function to support the simulator.
@ -476,7 +575,53 @@ declare namespace control {
*
*/
//% shim=control::__log
function __log(text: string): void;
function __log(priority: int32, text: string): void;
/**
* Allocates the next user notification event
*/
//% help=control/allocate-notify-event shim=control::allocateNotifyEvent
function allocateNotifyEvent(): int32;
/** Write a message to DMESG debugging buffer. */
//% shim=control::dmesg
function dmesg(s: string): void;
/** Write a message and value (pointer) to DMESG debugging buffer. */
//% shim=control::dmesgPtr
function dmesgPtr(str: string, ptr: Object): void;
}
declare namespace control {
/**
* Force GC and dump basic information about heap.
*/
//% shim=control::gc
function gc(): void;
/**
* Force GC and halt waiting for debugger to do a full heap dump.
*/
//% shim=control::heapDump
function heapDump(): void;
/**
* Set flags used when connecting an external debugger.
*/
//% shim=control::setDebugFlags
function setDebugFlags(flags: int32): void;
/**
* Record a heap snapshot to debug memory leaks.
*/
//% shim=control::heapSnapshot
function heapSnapshot(): void;
/**
* Return true if profiling is enabled in the current build.
*/
//% shim=control::profilingEnabled
function profilingEnabled(): boolean;
}
@ -607,8 +752,9 @@ declare namespace motors {
*/
//% blockId=motor_on block="motor on at %percent \\%"
//% parts=dcmotor weight=90 blockGap=8
//% percent.shadow="speedPicker" shim=motors::motorPower
function motorPower(power: int32): void;
//% percent.shadow="speedPicker"
//% power.defl=100 shim=motors::motorPower
function motorPower(power?: int32): void;
/**
* Send break, coast or sleep commands to the motor. Has no effect in dual-motor mode.
@ -622,8 +768,9 @@ declare namespace motors {
*/
//% blockId=block_dual_motor block="motor %motor|at %percent \\%"
//% percent.shadow="speedPicker"
//% weight=80 shim=motors::dualMotorPower
function dualMotorPower(motor: Motor, duty_percent: int32): void;
//% weight=80
//% duty_percent.defl=100 shim=motors::dualMotorPower
function dualMotorPower(motor: Motor, duty_percent?: int32): void;
}
declare namespace music {
@ -635,6 +782,31 @@ declare namespace music {
//%
//% parts="speaker" async useEnumVal=1 shim=music::speakerPlayTone
function speakerPlayTone(frequency: int32, ms: int32): void;
/**
* Set the default output volume of the sound synthesizer.
* @param volume the volume 0...255
*/
//% blockId=synth_set_volume block="set volume %volume"
//% volume.min=0 volume.max=255
//%
//% help=music/set-volume
//% weight=70
//% group="Volume"
//% blockGap=8
//% blockHidden=true volume.defl=127 shim=music::setVolume
function setVolume(volume?: int32): void;
/**
* Returns the current output volume of the sound synthesizer.
*/
//% blockId=synth_get_volume block="volume"
//% help=music/volume
//% weight=69
//% group="Volume"
//% blockGap=8
//% blockHidden=true shim=music::volume
function volume(): int32;
}
declare namespace pins {
@ -763,7 +935,8 @@ declare namespace pins {
//% blockId=device_analog_set_pitch_pin block="analog set pitch pin %name"
//% help=pins/analog-set-pitch-pin weight=3 advanced=true
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" shim=pins::analogSetPitchPin
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250"
//% blockHidden=true shim=pins::analogSetPitchPin
function analogSetPitchPin(name: AnalogPin): void;
/**
@ -772,14 +945,16 @@ declare namespace pins {
*/
//% 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
//% volume.min=0 volume.max=255
//% blockHidden=true 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
//% help=pins/analog-pitch-volume weight=3 advanced=true
//% blockHidden=true shim=pins::analogPitchVolume
function analogPitchVolume(): int32;
/**
@ -788,7 +963,8 @@ declare namespace pins {
* @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 shim=pins::analogPitch
//% help=pins/analog-pitch weight=4 async advanced=true blockGap=8
//% blockHidden=true shim=pins::analogPitch
function analogPitch(frequency: int32, ms: int32): void;
/**
@ -821,6 +997,20 @@ declare namespace pins {
//% shim=pins::createBuffer
function createBuffer(size: int32): Buffer;
/**
* Set the matrix width for Neopixel strip (already assigned to a pin).
* Should be used in conjunction with `set matrix width` from Neopixel package.
* @param name pin of Neopixel strip, eg: DigitalPin.P1
* @param value width of matrix (at least ``2``)
*/
//% help=pins/neopixel-matrix-width weight=3 advanced=true
//% blockId=pin_neopixel_matrix_width block="neopixel matrix width|pin %pin %width" blockGap=8
//% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4
//% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="250"
//% width.min=2
//% blockHidden=true width.defl=5 shim=pins::setMatrixWidth
function setMatrixWidth(pin: DigitalPin, width?: int32): void;
/**
* Read `size` bytes from a 7-bit I2C `address`.
*/
@ -885,6 +1075,18 @@ declare namespace pins {
*/
//% help=pins/push-button advanced=true shim=pins::pushButton
function pushButton(pin: DigitalPin): void;
/**
* Set the pin used when producing sounds and melodies. Default is P0.
* @param name pin to modulate pitch from
*/
//% blockId=pin_set_audio_pin block="set audio pin $name"
//% help=pins/set-audio-pin weight=3
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250"
//% weight=1
//% blockHidden=true shim=pins::setAudioPin
function setAudioPin(name: AnalogPin): void;
}
@ -935,8 +1137,9 @@ declare namespace serial {
function writeBuffer(buffer: Buffer): void;
/**
* Read multiple characters from the receive buffer. Pause until enough characters are present.
* @param length default buffer length, eg: 64
* Read multiple characters from the receive buffer.
* If length is positive, pauses until enough characters are present.
* @param length default buffer length
*/
//% blockId=serial_readbuffer block="serial|read buffer %length"
//% help=serial/read-buffer advanced=true weight=5 shim=serial::readBuffer
@ -1105,15 +1308,63 @@ declare namespace control {
//% deprecated=1 shim=control::createBufferFromUTF8
function createBufferFromUTF8(str: string): Buffer;
}
/**
* Provides access to persistent storage functionality.
*/
declare namespace storage {
/**
* Saves a key value pair in the non volatile storage
* @param key the key for accesing the value
* @param value value to store
*/
//% weight=100 blockGap=16
//% block="Put into %key a value of %value as Int"
//% blockId=storage_put_value_int
//%
//% group="Put"
//% blockHidden=true value.defl=0 shim=storage::putValueInt
function putValueInt(key: string, value?: int32): void;
/**
* Reads a key value pair from the non volatile storage
* @param key the key for accesing the value
*/
//% weight=100 blockGap=16
//% block="get number from %key"
//% blockId=storage_get_value_int
//% group="Get"
//% blockHidden=true shim=storage::getValueInt
function getValueInt(key: string): int32;
/**
* Removes a key value pair from the non volatile storage
* @param key the key for accesing the value
*/
//% weight=100 blockGap=16
//% block="remove %key"
//% blockId=storage_remove
//% group="Remove"
//% blockHidden=true shim=storage::remove
function remove(key: string): void;
}
declare namespace light {
/**
* Sends a color buffer to a light strip
**/
//% advanced=true
//% shim=light::sendWS2812Buffer
//% advanced=true shim=light::sendWS2812Buffer
function sendWS2812Buffer(buf: Buffer, pin: int32): void;
/**
* Sends a color buffer to a light strip
**/
//% advanced=true shim=light::sendWS2812BufferWithBrightness
function sendWS2812BufferWithBrightness(buf: Buffer, pin: int32, brightness: int32): void;
/**
* Sets the light mode of a pin
**/

View File

@ -0,0 +1,28 @@
#include "pxt.h"
namespace music {
/**
* Internal use only
**/
//% async
void __playSoundExpression(String nodes, bool waitTillDone) {
#if MICROBIT_CODAL
if (waitTillDone)
uBit.audio.soundExpressions.play(MSTR(nodes));
else
uBit.audio.soundExpressions.playAsync(MSTR(nodes));
#else
target_panic(PANIC_VARIANT_NOT_SUPPORTED);
#endif
}
/**
* Internal use only
*/
//%
void __stopSoundExpressions() {
#if MICROBIT_CODAL
uBit.audio.soundExpressions.stop();
#endif
}
}

View File

@ -0,0 +1,59 @@
/**
* A sound expression.
*/
//% fixedInstances
//% blockNamespace=music
//% group="micro:bit (V2)"
class SoundExpression {
constructor(private notes: string) {
}
/**
* Starts to play a sound expression.
*/
//% block="play sound $this"
//% weight=80
//% blockGap=8
//% help=music/play
//% group="micro:bit (V2)"
//% parts=builtinspeaker
play() {
music.__playSoundExpression(this.notes, false)
}
/**
* Plays a sound expression until finished
*/
//% block="play sound $this until done"
//% weight=81
//% blockGap=8
//% help=music/play-until-done
//% group="micro:bit (V2)"
//% parts=builtinspeaker
playUntilDone() {
music.__playSoundExpression(this.notes, true)
}
}
namespace soundExpression {
//% fixedInstance whenUsed block="{id:soundexpression}giggle"
export const giggle = new SoundExpression("giggle");
//% fixedInstance whenUsed block="{id:soundexpression}happy"
export const happy = new SoundExpression("happy");
//% fixedInstance whenUsed block="{id:soundexpression}hello"
export const hello = new SoundExpression("hello");
//% fixedInstance whenUsed block="{id:soundexpression}mysterious"
export const mysterious = new SoundExpression("mysterious");
//% fixedInstance whenUsed block="{id:soundexpression}sad"
export const sad = new SoundExpression("sad");
//% fixedInstance whenUsed block="{id:soundexpression}slide"
export const slide = new SoundExpression("slide");
//% fixedInstance whenUsed block="{id:soundexpression}soaring"
export const soaring = new SoundExpression("soaring");
//% fixedInstance whenUsed block="{id:soundexpression}spring"
export const spring = new SoundExpression("spring");
//% fixedInstance whenUsed block="{id:soundexpression}twinkle"
export const twinkle = new SoundExpression("twinkle");
//% fixedInstance whenUsed block="{id:soundexpression}yawn"
export const yawn = new SoundExpression("yawn");
}

57
libs/core/storage.cpp Normal file
View File

@ -0,0 +1,57 @@
#include "pxt.h"
/**
* Provides access to persistent storage functionality.
*/
namespace storage {
/**
* Saves a key value pair in the non volatile storage
* @param key the key for accesing the value
* @param value value to store
*/
//% weight=100 blockGap=16
//% block="Put into %key a value of %value as Int"
//% blockId=storage_put_value_int
//% value.defl=0
//% group="Put"
//% blockHidden=true
void putValueInt(String key, int value) {
ManagedString managedKey = MSTR(key);
uBit.storage.put(managedKey, (uint8_t *)&value, sizeof(int));
}
/**
* Reads a key value pair from the non volatile storage
* @param key the key for accesing the value
*/
//% weight=100 blockGap=16
//% block="get number from %key"
//% blockId=storage_get_value_int
//% group="Get"
//% blockHidden=true
int getValueInt(String key) {
KeyValuePair* data = uBit.storage.get(MSTR(key));
int stored;
if(data == NULL) {
return 0;
} else {
memcpy(&stored, data->value, sizeof(int));
delete data;
return stored;
}
}
/**
* Removes a key value pair from the non volatile storage
* @param key the key for accesing the value
*/
//% weight=100 blockGap=16
//% block="remove %key"
//% blockId=storage_remove
//% group="Remove"
//% blockHidden=true
void remove(String key) {
uBit.storage.remove(MSTR(key));
}
}

68
libs/core/storage.ts Normal file
View File

@ -0,0 +1,68 @@
enum StorageSlots {
//% block="Slot 1"
s1 = 0,
//% block="Slot 2"
s2 = 1,
//% block="Slot 3"
s3 = 2,
//% block="Slot 4"
s4 = 3,
//% block="Slot 5"
s5 = 4,
//% block="Slot 6"
s6 = 5,
//% block="Slot 7"
s7 = 6,
}
// let storagesStr = ['s1', 's2', 's3', 's4', 's5', 's6', 's7'];
let storagesInt = ['i1', 'i2', 'i3', 'i4', 'i5', 'i6', 'i7'];
/**
* Provides access to persistent storage functionality.
*/
//% color=#FFBB00 weight=10 icon="\uf187"
//% advanced=true
namespace storage {
/**
* Saves a key value pair in the non volatile storage
* @param key the key for accesing the value
* @param value value to store
*/
//% weight=90 blockGap=16
//% block="Save into number %key a value of %value"
//% blockId=storage_put_number
//% group="Put"
export function putNumber(key: StorageSlots, value: number) : void {
let managedValue = Math.floor(value * 100);
putValueInt(storagesInt[key], managedValue);
}
/**
* Reads a key value pair from the non volatile storage as a number
* @param key the key for accesing the value
*/
//% weight=70 blockGap=16
//% block="read from number %key"
//% blockId=storage_get_number
//% group="Get"
export function getNumber(key: StorageSlots) : number {
let value = getValueInt(storagesInt[key]);
return value / 100;
}
/**
* Deletes the key from the non volatile storage
* @param key the key for accesing the value
*/
//% weight=50 blockGap=16
//% block="Clear number %key"
//% blockId=storage_remove_key_int
//% group="Remove"
export function removeKeyInt(key: StorageSlots) : void {
remove(storagesInt[key]);
}
}

53
libs/core/touchmode.cpp Normal file
View File

@ -0,0 +1,53 @@
#include "pxt.h"
#if MICROBIT_CODAL
#else
#define MICROBIT_ID_LOGO 121
#endif
enum class TouchTargetMode {
//% block="capacitive"
Capacitive = 1,
//% block="resistive"
Resistive = 0
};
enum class TouchTarget {
//% block="P0"
P0 = MICROBIT_ID_IO_P0,
//% block="P1"
P1 = MICROBIT_ID_IO_P1,
//% block="P2"
P2 = MICROBIT_ID_IO_P2,
//% block="logo"
LOGO = MICROBIT_ID_LOGO
};
namespace pins {
/**
* Configure the touch detection for the pins and logo.
* P0, P1, P2 use resistive touch by default.
* The logo uses capacitative touch by default.
* @param name target to change the touch mode for
* @param mode the touch mode to use
*/
//% weight=60
//% blockId=device_touch_set_type block="set %name to touch mode %mode"
//% advanced=true
//% group="micro:bit (V2)"
//% help=pins/touch-set-mode
void touchSetMode(TouchTarget name, TouchTargetMode mode) {
#if MICROBIT_CODAL
const auto pin = name == TouchTarget::LOGO
? &uBit.io.logo : getPin((int)name);
if (pin) {
pin->isTouched(mode == TouchTargetMode::Capacitive
? codal::TouchMode::Capacitative : codal::TouchMode::Resistive);
}
#else
target_panic(PANIC_VARIANT_NOT_SUPPORTED);
#endif
}
}

View File

@ -9,6 +9,7 @@
"devices.ts"
],
"icon": "./static/packages/devices/icon.png",
"hidden": true,
"public": true,
"dependencies": {
"core": "file:../core",

View File

@ -2,5 +2,5 @@
"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": "gets the level of loudness in 0-100%\n\nReads the loudness through the microphone from 0 (silent) to 255 (loud)"
"input.soundLevel": "gets the level of loudness from 0 (silent) to 255 (loud)\n\nReads the loudness through the microphone from 0 (silent) to 255 (loud)"
}

View File

@ -6,5 +6,6 @@
"input.soundLevel|block": "sound level",
"input|block": "input",
"{id:category}Input": "Input",
"{id:group}More": "More"
"{id:group}More": "More",
"{id:group}Sensors": "Sensors"
}

8753
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "pxt-calliopemini",
"version": "3.0.36",
"version": "4.0.18",
"description": "calliope mini target for Microsoft MakeCode (PXT)",
"keywords": [
"JavaScript",
@ -33,19 +33,19 @@
"docs/static/icons/favicon.ico"
],
"devDependencies": {
"@types/bluebird": "2.0.33",
"@types/marked": "0.3.0",
"@types/node": "8.0.53",
"@types/react": "16.0.25",
"@types/node": "8.10.66",
"@types/react": "16.4.7",
"@types/react-dom": "16.0.3",
"@types/web-bluetooth": "0.0.4",
"less": "2.7.3",
"react": "16.8.3",
"react-dom": "16.11.0",
"semantic-ui-less": "2.2.14",
"typescript": "^3.7.5"
"typescript": "4.2.3"
},
"dependencies": {
"pxt-common-packages": "7.0.4",
"pxt-core": "6.0.24"
"pxt-common-packages": "9.0.1",
"pxt-core": "7.0.14"
}
}

View File

@ -42,10 +42,10 @@
"gc": true,
"imageRefTag": 9,
"shimRenames": {
"sendBufferAsm": "light::sendWS2812Buffer"
},
"patches": {
"0.0.0 - 1.0.0": [
{
"0.0.0 - 1.0.0": [{
"type": "package",
"map": {
"microbit": "core",
@ -92,31 +92,27 @@
}
}
],
"0.0.0 - 1.4.12": [
{
"0.0.0 - 1.4.12": [{
"type": "api",
"map": {
"DisplayMode\\s*\\.\\s*BackAndWhite": "DisplayMode.BlackAndWhite"
}
}
]
}]
},
"hidSelectors": [
{
"hidSelectors": [{
"usagePage": "0xFF00",
"usageId": "0x0001",
"vid": "0x1366",
"pid": "0x1025"
}
],
}],
"webUSB": false,
"useNewFunctions": true
},
"compileService": {
"yottaTarget": "calliope-mini-classic-gcc",
"yottaTarget": "calliope-mini-classic-gcc@https://github.com/calliope-mini/target-calliope-mini-classic-gcc#v1.2.3",
"yottaCorePackage": "microbit",
"githubCorePackage": "calliope-mini/microbit",
"gittag": "v2.2.0-rc6-calliope.rc3",
"gittag": "v2.2.0-rc6-calliope.rc3-iss0.3",
"serviceId": "calliope",
"dockerImage": "pext/yotta:latest"
},
@ -132,8 +128,7 @@
"continueBlock": true,
"functionsOptions": {
"useNewFunctions": true,
"extraFunctionEditorTypes": [
{
"extraFunctionEditorTypes": [{
"typeName": "game.LedSprite",
"label": "LedSprite",
"icon": "send",
@ -149,7 +144,8 @@
},
"onStartColor": "#54C9C9",
"onStartNamespace": "basic",
"onStartWeight": 54
"onStartWeight": 60,
"onStartGroup": "Control"
},
"simulator": {
"autoRun": true,
@ -299,7 +295,14 @@
"organizationUrl": "https://makecode.com/",
"organizationLogo": "./static/Microsoft-logo_rgb_c-gray-square.png",
"organizationWideLogo": "./static/Microsoft-logo_rgb_c-white.png",
"homeScreenHero": "./static/hero.jpg",
"homeScreenHero": {
"imageUrl": "./static/hero.jpg",
"name": "Flashing Heart",
"url": "/calliope/firststeps/firstSteps",
"description": "Let's go start your first tutorial with Calliope mini",
"cardType": "tutorial"
},
"homeScreenHeroGallery": "/hero-banner",
"homeUrl": "https://makecode.calliope.cc/",
"embedUrl": "https://makecode.calliope.cc/",
"shareUrl": "https://makecode.calliope.cc/",
@ -309,26 +312,27 @@
"boardName": "Calliope mini",
"driveDisplayName": "MINI",
"appStoreID": "1309545545",
"crowdinProject": "kindscript",
"crowdinProject": "makecode",
"extendEditor": true,
"extendFieldEditors": true,
"enableTrace": true,
"ignoreDocsErrors": false,
"errorList": true,
"allowPackageExtensions": true,
"addNewTypeScriptFile": true,
"experiments": [
"allowPackageExtensions",
"instructions",
"accessibleBlocks",
"debugExtensionCode",
"bluetoothUartConsole",
"bluetoothPartialFlashing",
"simScreenshot",
"simGif"
"simGif",
"blocksErrorList"
],
"bluetoothUartFilters": [
{
"bluetoothUartFilters": [{
"namePrefix": "Calliope mini"
}
],
"docMenu": [
{
}],
"docMenu": [{
"name": "Support",
"path": "https://calliope.cc/en/impressum"
},
@ -395,6 +399,7 @@
"ar",
"bg",
"cs",
"cy",
"da",
"de",
"el",
@ -416,6 +421,7 @@
"ru",
"si-LK",
"sk",
"sr",
"sv-SE",
"tr",
"uk",
@ -428,7 +434,8 @@
"browserDbPrefixes": {
"1": "v1",
"2": "v2",
"3": "v3"
"3": "v3",
"4": "v4"
},
"editorVersionPaths": {
"0": "v0"
@ -447,15 +454,46 @@
"chooseLanguageRestrictionOnNewProject": true,
"openProjectNewTab": true,
"python": true,
"appFlashingTroubleshoot": "/device/windows-app/troubleshoot"
"appFlashingTroubleshoot": "/device/windows-app/troubleshoot",
"immersiveReader": true,
"tutorialCodeValidation": true,
"downloadDialogTheme": {
"webUSBDeviceNames": ["Calliope mini CMSIS-DAP", "DAPLink CMSIS-DAP"],
"minimumFirmwareVersion": "0249",
"deviceIcon": "xicon microbit",
"deviceSuccessIcon": "xicon microbit-check",
"downloadMenuHelpURL": "/device/usb",
"downloadHelpURL": "/device/usb",
"firmwareHelpURL": "/device/usb/webusb/troubleshoot",
"troubleshootWebUSBHelpURL": "/device/usb/webusb/troubleshoot",
"incompatibleHardwareHelpURL": "/device/v2",
"dragFileImage": "./static/download/transfer.png",
"connectDeviceImage": "./static/download/connect.png",
"selectDeviceImage": "./static/download/pair.png",
"connectionSuccessImage": "/static/download/connected.png",
"checkFirmwareVersionImage": "./static/download/firmware.png",
"checkUSBCableImage": "./static/download/connect.pn",
"incompatibleHardwareImage": "/static/download/incompatible.png"
},
"winAppDeprImage": "/static/winapp.PNG",
"showWinAppDeprBanner": false
},
"queryVariants": {
"hidemenu": {
"appTheme": {
"hideMenuBar": true
}
},
"androidapp": {
"compile": {
"webUSB": false
},
"appTheme": {
"disableBlobObjectDownload": true
}
}
},
"uploadDocs": true,
"ignoreDocsErrors": true
"uploadDocs": true
}

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" IgnorableNamespaces="uap uap3 mp">
<Identity Name="MicrobitEducationalFounda.196216C47839B" Version="1.1.0.0" Publisher="CN=DA0852B7-E38D-4F10-9429-7A96575322FD" />
<mp:PhoneIdentity PhoneProductId="5ddd542e-5ab4-48bc-b116-0782dc08ab97" PhonePublisherId="00000000-0000-0000-0000-000000000000" />

7
sim/compat.ts Normal file
View File

@ -0,0 +1,7 @@
namespace pxsim {
export interface CommonBoard extends CoreBoard
, EventBusBoard {
bus: EventBus;
edgeConnectorState: EdgeConnectorState;
}
}

View File

@ -4,7 +4,11 @@
namespace pxsim {
export class DalBoard extends CoreBoard
implements RadioBoard, LightBoard {
implements CommonBoard
, RadioBoard
, LightBoard
, MicrophoneBoard
, ControlMessageBoard {
// state & update logic for component services
ledMatrixState: LedMatrixState;
edgeConnectorState: EdgeConnectorState;
@ -20,17 +24,24 @@ namespace pxsim {
rgbLedState: number;
speakerState: SpeakerState;
fileSystem: FileSystemState;
logoTouch: Button;
speakerEnabled: boolean = true;
controlMessageState: ControlMessageState;
// visual
viewHost: visuals.BoardHost;
view: SVGElement;
// board hardware version
hardwareVersion = 1;
constructor() {
super()
// components
this.lightState = {};
this.fileSystem = new FileSystemState();
this.controlMessageState = new ControlMessageState(this);
this.builtinParts["ledmatrix"] = this.ledMatrixState = new LedMatrixState(runtime);
this.builtinParts["buttonpair"] = this.buttonPairState = new ButtonPairState({
ID_BUTTON_A: DAL.MICROBIT_ID_BUTTON_A,
@ -41,8 +52,10 @@ namespace pxsim {
});
this.builtinParts["edgeconnector"] = this.edgeConnectorState = new EdgeConnectorState({
pins: [
DAL.MICROBIT_ID_IO_P12,
DAL.MICROBIT_ID_IO_P0,
DAL.MICROBIT_ID_IO_P1,
DAL.MICROBIT_ID_IO_P16,
DAL.MICROBIT_ID_IO_P2,
DAL.MICROBIT_ID_IO_P3,
DAL.MICROBIT_ID_IO_P4,
@ -53,11 +66,9 @@ namespace pxsim {
DAL.MICROBIT_ID_IO_P9,
DAL.MICROBIT_ID_IO_P10,
DAL.MICROBIT_ID_IO_P11,
DAL.MICROBIT_ID_IO_P12,
DAL.MICROBIT_ID_IO_P13,
DAL.MICROBIT_ID_IO_P14,
DAL.MICROBIT_ID_IO_P15,
DAL.MICROBIT_ID_IO_P16,
0,
0,
DAL.MICROBIT_ID_IO_P19,
@ -71,13 +82,13 @@ namespace pxsim {
"P3": DAL.MICROBIT_ID_IO_P16
}
});
this.builtinParts["radio"] = this.radioState = new RadioState(runtime, {
this.builtinParts["radio"] = this.radioState = new RadioState(runtime, this, {
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["microphone"] = this.microphoneState = new AnalogSensorState(3001 /* DEVICE_ID_MICROPHONE */, 0, 255, 75, 180);
this.builtinParts["accelerometer"] = this.accelerometerState = new AccelerometerState(runtime);
this.builtinParts["serial"] = this.serialState = new SerialState();
this.builtinParts["serial"] = this.serialState = new SerialState(runtime, this);
this.builtinParts["thermometer"] = this.thermometerState = new ThermometerState();
this.builtinParts["lightsensor"] = this.lightSensorState = new LightSensorState();
this.builtinParts["compass"] = this.compassState = new CompassState();
@ -97,24 +108,13 @@ namespace pxsim {
this.builtinPartVisuals["microservo"] = (xy: visuals.Coord) => visuals.mkMicroServoPart(xy);
}
receiveMessage(msg: SimulatorMessage) {
if (!runtime || runtime.dead) return;
ensureHardwareVersion(version: number) {
if (version > this.hardwareVersion) {
this.hardwareVersion = version;
this.updateView();
}
}
switch (msg.type || "") {
case "eventbus":
const ev = <SimulatorEventBusMessage>msg;
this.bus.queue(ev.id, ev.eventid, ev.value);
break;
case "serial":
const data = (<SimulatorSerialMessage>msg).data || "";
this.serialState.receiveData(data);
break;
case "radiopacket":
const packet = <SimulatorRadioPacketMessage>msg;
this.radioState.receivePacket(packet);
break;
}
}
initAsync(msg: SimulatorRunMessage): Promise<void> {
super.initAsync(msg);
@ -124,6 +124,21 @@ namespace pxsim {
const cmpDefs = msg.partDefinitions || {};
const fnArgs = msg.fnArgs;
const v2Parts: pxt.Map<boolean> = {
"microphone": true,
"logotouch": true,
"builtinspeaker": true,
"v2": true
};
if (msg.builtinParts) {
const v2PartsUsed = msg.builtinParts.filter(k => v2Parts[k])
if (v2PartsUsed.length) {
console.log(`detected v2 feature`, v2PartsUsed);
cmpsList.push(...v2PartsUsed);
this.hardwareVersion = 2;
}
}
const opts: visuals.BoardHostOpts = {
state: this,
boardDef: boardDef,
@ -134,6 +149,7 @@ namespace pxsim {
maxHeight: "100%",
highContrast: msg.highContrast
};
this.viewHost = new visuals.BoardHost(pxsim.visuals.mkBoardView({
visual: boardDef.visual,
boardDef: boardDef,

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="#009900" stroke="none" d="M13.922 2.495V19.3a2.35 2.35 0 11-3.845 0V2.495c0-.826.67-1.495 1.495-1.495h.855c.825 0 1.495.67 1.495 1.495zm-1.923 16.723a1.431 1.431 0 100 2.863 1.431 1.431 0 000-2.863zm5.426.001a1.431 1.431 0 100 2.863 1.431 1.431 0 000-2.863zm1.922-14.587V19.3a2.35 2.35 0 11-3.844 0V4.632c0-.826.67-1.495 1.495-1.495h.854c.826 0 1.495.67 1.495 1.495zM7.002 1.002c.826 0 1.495.669 1.495 1.494V19.3a2.35 2.35 0 11-3.848.006l.004-.006V2.496C4.653 1.67 5.323 1 6.148 1zM6.575 19.22a1.431 1.431 0 100 2.862 1.431 1.431 0 000-2.862z"/></svg>

After

Width:  |  Height:  |  Size: 646 B

View File

@ -1,9 +1,19 @@
CACHE MANIFEST
CACHE:
/cdn/bluebird.min.js
/cdn/pxtsim.js
/sim/sim.js
/sim/sounds/giggle.wav
/sim/sounds/happy.wav
/sim/sounds/hello.wav
/sim/sounds/mysterious.wav
/sim/sounds/sad.wav
/sim/sounds/slide.wav
/sim/sounds/soaring.wav
/sim/sounds/spring.wav
/sim/sounds/twinkle.wav
/sim/sounds/yawn.wav
NETWORK:
*

View File

@ -19,10 +19,22 @@ body {
margin: 0;
}
</style>
<script src="/cdn/bluebird.min.js"></script>
<script src="/cdn/pxtsim.js"></script>
<script src="/sim/sim.js"></script>
<script>
pxsim.soundExpressionFiles = {
"giggle": "/sim/sounds/giggle.wav",
"happy": "/sim/sounds/happy.wav",
"hello": "/sim/sounds/hello.wav",
"mysterious": "/sim/sounds/mysterious.wav",
"sad": "/sim/sounds/sad.wav",
"slide": "/sim/sounds/slide.wav",
"soaring": "/sim/sounds/soaring.wav",
"spring": "/sim/sounds/spring.wav",
"twinkle": "/sim/sounds/twinkle.wav",
"yawn": "/sim/sounds/yawn.wav"
}
</script>
</head>
<body>
</body>

Binary file not shown.

BIN
sim/public/sounds/happy.wav Normal file

Binary file not shown.

BIN
sim/public/sounds/hello.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
sim/public/sounds/sad.wav Normal file

Binary file not shown.

BIN
sim/public/sounds/slide.wav Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More