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>
8
.github/lock.yml
vendored
@ -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
@ -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
|
@ -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 }}
|
@ -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
@ -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
@ -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
|
7
.github/workflows/testghpkgs.yml
vendored
@ -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
|
||||
|
27
.travis.yml
@ -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
|
||||
|
1
.vscode/settings.json
vendored
@ -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
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "../pxt"
|
||||
},
|
||||
{
|
||||
"path": "../pxt-common-packages"
|
||||
},
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
]
|
||||
}
|
131
compiler/combiner.ts
Normal 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
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
2
docfiles/offline-app-trademarks.html
Normal file
@ -0,0 +1,2 @@
|
||||
Micro:bit and micro:bit logo are trademarks and/ or copyrights of the Micro:bit
|
||||
Educational Foundation. © Micro:bit Educational Foundation. All rights reserved.
|
@ -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)
|
||||
|
||||
|
BIN
docs/calliope/02_Hero_CalliopEO.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
docs/calliope/03_Hero_KidsLab.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
docs/calliope/calliopeo-header.png
Normal file
After Width: | Height: | Size: 220 KiB |
21
docs/hero-banner.md
Normal 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
|
||||
### ~
|
@ -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
After Width: | Height: | Size: 17 KiB |
BIN
docs/skillmap/img/spacet4.gif
Normal file
After Width: | Height: | Size: 84 KiB |
37
docs/skillmap/mini.md
Normal 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
@ -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
|
172
docs/skillmap/space/activity1.md
Normal 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!
|
BIN
docs/skillmap/space/img/space.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
docs/skillmap/space/img/spacet4.gif
Normal file
After Width: | Height: | Size: 84 KiB |
19
docs/skillmaps.md
Normal 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
|
||||
}
|
||||
]
|
||||
```
|
@ -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">
|
||||
|
@ -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);
|
||||
}
|
||||
|
710
editor/flash.ts
@ -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 {
|
||||
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"masterPicture": "docs/static/microbit.simplified.svg",
|
||||
"iconsPath": "/static/icons",
|
||||
"iconsPath": "/docs/static/icons",
|
||||
"design": {
|
||||
"ios": {
|
||||
"pictureAspect": "backgroundAndMargin",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"target": "es2017",
|
||||
"noImplicitAny": false,
|
||||
"noImplicitReturns": true,
|
||||
"module": "commonjs",
|
||||
|
@ -1,8 +1,7 @@
|
||||
{
|
||||
"name": "{0} block",
|
||||
"dependencies": {
|
||||
"core": "file:../core",
|
||||
"radio": "file:../radio"
|
||||
"core": "file:../core"
|
||||
},
|
||||
"description": "",
|
||||
"files": [
|
||||
|
@ -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
|
||||
//================================================================
|
||||
|
@ -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
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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": [
|
||||
]
|
||||
}
|
||||
}
|
8
libs/bluetooth/shims.d.ts
vendored
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
}
|
@ -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"
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
@ -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
@ -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
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@ typedef RefMImage *Image;
|
||||
|
||||
extern MicroBit uBit;
|
||||
extern MicroBitEvent lastEvent;
|
||||
extern bool serialLoggingDisabled;
|
||||
|
||||
MicroBitPin *getPin(int id);
|
||||
|
||||
|
@ -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\""
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
|
53
libs/core/sendbufferbrightness.s
Normal 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}
|
82
libs/core/sendbuffernrf52.s
Normal 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
|
@ -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
@ -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
|
||||
**/
|
||||
|
28
libs/core/soundexpressions.cpp
Normal 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
|
||||
}
|
||||
}
|
59
libs/core/soundexpressions.ts
Normal 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
@ -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
@ -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
@ -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
|
||||
}
|
||||
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
"devices.ts"
|
||||
],
|
||||
"icon": "./static/packages/devices/icon.png",
|
||||
"hidden": true,
|
||||
"public": true,
|
||||
"dependencies": {
|
||||
"core": "file:../core",
|
||||
|
@ -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)"
|
||||
}
|
@ -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
14
package.json
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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
@ -0,0 +1,7 @@
|
||||
namespace pxsim {
|
||||
export interface CommonBoard extends CoreBoard
|
||||
, EventBusBoard {
|
||||
bus: EventBus;
|
||||
edgeConnectorState: EdgeConnectorState;
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
1
sim/public/icons/jacdac.svg
Normal 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 |
@ -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:
|
||||
*
|
||||
|
@ -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>
|
||||
|