Compare commits

..

38 Commits

Author SHA1 Message Date
Dmitriy Antipov
6d222c50cb
Enable some features to improve the programming experience (#1022)
* Update pxtarget.json

Enable addNewTypeScriptFile so that you can split your code into multiple files. Enable blocksCollapsing to collapse blocks for convenience. Turn off highContrast it doesn't work now. We'll see later...

* enable-errorlist-option

* Update pxtarget.json

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

---------

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>
2023-05-18 10:24:11 -07:00
Dmitriy Antipov
af263c8183
change-gray-ti-brown (#1021)
A typo that hadn't been noticed before. Does not affect the operation of the simulator.
2023-05-06 09:47:27 -07:00
Joey Wunderlich
dd18007035 1.4.32 2023-05-05 16:18:41 -07:00
Dmitriy Antipov
fba924d125
Add a none option to the simulator for the color sensor and colorEnumPicker extension (#1018)
* Update colorGrid.ts

* Update ns.ts

Added option to select emptiness (nothing) for the colorEnumPicker block.

* set-new-names-for-color-cells

Set new names for colored cells that pops up when hovering over an element. So the user will understand the color.

* Update sim/visuals/controls/colorGrid.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

---------

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>
2023-05-05 16:04:13 -07:00
Dmitriy Antipov
76257775c3
Extended show screen blocks options (#1019)
* Update targetoverrides.ts

Convert old blocks to obsolete ones, new blocks differ in that you can specify the place to start printing along the horizontal axis of the screen (column). And also added a print style. These are the standard black text on a white background and the new white text on a black background. These two parameters are optionally expanded and optional, by default column = 1 and the print style is the same as before, black text on white.

* Update targetoverrides.ts

* Update libs/screen/targetoverrides.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

* Update libs/screen/targetoverrides.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

* Update libs/screen/targetoverrides.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

* Update libs/screen/targetoverrides.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

* Update libs/screen/targetoverrides.ts

---------

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>
2023-05-05 15:58:52 -07:00
Dmitriy Antipov
9be35a1034
Added support for Reflection Raw mode for the color sensor to the simulator (#1017)
* redesigned-code-to-support-ref-raw

Code that adds reflection raw support for the color sensor. The range of values for this is from 0 to 1023, because analog to digital converter is 10 bits. In fact, the color sensor gives values ​​of about 400 - 700, but I decided to leave the range, which could theoretically be. For other cases (reflections and ambient lighting), the range remains from 0 to 100. The average value when setting the mode in the simulator is displayed as 512, for other modes 50%.

* block-description-update

Block description update, as it did not take into account the mode of raw reflection values.
2023-05-05 15:54:56 -07:00
Dmitriy Antipov
2ca706df70
Fix music images items in other languages (#1014)
* correction-of-displaying-pictures-in-different languages

Correction of displaying pictures in different languages. The category options values were translated into different languages and the translated values could not be checked against the values from icon.jres.

* element-layout-fixes

Уlement layout fixes, for more readable blocks

* Update fieldeditors/field_music.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

* Update fieldeditors/field_music.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

* tag-lang-tag-for-languages-other-than-en

The tag is not needed for English, because in the html tag it is already always set.

---------

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>
2023-05-05 15:50:04 -07:00
Dmitriy Antipov
dd415019c4
renderPorts-extra-checks-before-print (#1020)
When the program starts, when the showBoot() function is launched, the screenMode is checked and the showPorts function is launched, which in turn executes the renderPorts() function in a loop. While renderPorts is running, the screenMode may change, for example to ShowLines (when showString() was run). It may turn out that the mode has changed, and the renderPorts method has not been fully executed ... in the future, it will draw its own graphics on the screen, although we do not expect to see them already, because. a regime change has occurred. I added checks inside the function before displaying.
2023-05-05 15:46:43 -07:00
Joey Wunderlich
20581513b1 1.4.31 2023-04-29 17:22:20 -07:00
Dmitriy Antipov
1652fc5ffa
fix-bg-color (#1016) 2023-04-29 17:21:48 -07:00
Joey Wunderlich
8a1b6452bd
unpin beta (#1015) 2023-04-28 14:26:34 -07:00
Joey Wunderlich
a6712960db 1.4.30 2023-04-26 09:30:55 -07:00
Joey Wunderlich
bac70eb177 bump to pick up in ctx translations fix 2023-04-26 09:30:05 -07:00
Joey Wunderlich
830f5ffd77 1.4.29 2023-04-25 16:35:05 -07:00
Joey Wunderlich
aac5edd64b bump pxt to latest 7.2.* to pick up crowdin / build fixes 2023-04-25 16:25:21 -07:00
Joey Wunderlich
a54007d9ae 1.4.28 2023-04-25 14:56:21 -07:00
Joey Wunderlich
3952cb4858 1.4.27 2023-04-25 12:21:03 -07:00
Joey Wunderlich
0226888441
Change crowdin project to new name (kindscript->makecode) (#1013) 2023-04-25 12:20:42 -07:00
Joey Wunderlich
1373e9c0bc 1.4.26 2023-04-25 12:08:04 -07:00
Dmitriy Antipov
cabcb048e3
Troubleshooting updates v1.4.25 (#1012)
* sim_fix

ES version update

* fieldeditors-es-upgrade-to-es2017

Update es to fix issue with fieldeditors.

* editor-es-upgrade-to-es2017

Update es that fixes an issue with the editor.

* editor-download-dialog-fix

Solving a download error that arose due to problems with the buttons in the dialog box.

* return_field_motors

We return the fieldmotors field, because it is necessary about the choice of types of motors: medium, large, one or two.

* update-fields-for-motor-blocks

Set the blocks to the fieldmotors field. Change the name of the blocks for the motors.

* enable-debugger

Instead of the slowmo mode, which was before, a debugger was added, in which slowmo is present.

* fix-field-music

It turned out to update the fieldmusic menu. The menu is now displayed in the correct position.

* Update field_music.ts

* fix-field-brickbutton

Fixed issue with button select menu position from ev3 brick.

* Update dialogs.tsx

* Update field_motors.ts

Repartition of Label for fieldmotos, now it's more readable, it's better.

* motors-new-icon

Created new icons for motors for dropdown image.

* remove-ai-files-for-motors-icon

Remove ai image files for motors
2023-04-25 12:06:54 -07:00
microsoft-github-policy-service[bot]
512a441bca
Microsoft mandatory file (#1007)
Co-authored-by: microsoft-github-policy-service[bot] <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com>
2022-08-30 10:35:02 -07:00
pelikhan
b4a18f260d lock beta to 1.4.24 2022-01-29 13:29:33 -08:00
pelikhan
6b3f2da72c 1.4.25 2022-01-29 12:05:31 -08:00
Dmitriy Antipov
b9b21328b1
return_blocks (#1003)
These blocks are present in the stable version, but not in the beta.
2021-11-29 09:57:33 -08:00
Richard Knoll
bef4ebac43
Updating npm dependencies and getting the build to work (#1001)
* Updating npm dependencies and getting the build to work

* update node in github actions to 14.x
2021-09-22 15:51:32 -07:00
pelikhan
617fdeb747 1.4.24 2021-09-10 11:21:42 -07:00
Dmitriy Antipov
c1aead1aa9
fix invert motor angle metod (#999) 2021-09-09 14:11:06 -07:00
Richard Knoll
bd0cf05693
Adding gh-actions workflows (#995)
* Adding gh-actions workflows

* Removing travis

* Handle tags also
2021-01-27 14:57:14 -08:00
Galen Nickel
faae7133f5
Word changes to reduce policheck hits (#992) 2020-11-06 13:09:53 -08:00
Peli de Halleux
5289850351 bump to v1.2.31 2020-10-02 23:42:38 +02:00
Peli de Halleux
ba6e2f7174 enable french 2020-10-02 23:13:04 +02:00
peli
7c5dfc474f update version to v1.2.30 2020-09-20 23:47:53 -07:00
peli
5ab3a6ae96 1.4.23 2020-09-10 23:40:51 -07:00
Maciej Mroziński
ed2e1f23e9
Change timeout 1s -> 5s to reduce Timeout errors (#988) 2020-09-11 08:25:12 +02:00
Maciej Mroziński
a157943bf7
Read default volume from device settings at start (#987) 2020-09-09 12:06:33 -07:00
peli
40aaf0fb18 1.4.22 2020-09-08 23:54:42 -07:00
Maciej Mroziński
b26cf289c3
Change sound volume to level (#986) 2020-09-08 23:53:33 -07:00
Peli de Halleux
f0821f8d6c cherry-pick Cooperate (#985)
* cooperate pause

* fix math

* update lastPause before pausing

* faster cooperation

Co-authored-by: Peli de Halleux <peli@DESKTOP-5B7QRAM.corp.microsoft.com>
2020-08-21 06:09:01 +02:00
58 changed files with 730 additions and 710 deletions

40
.github/workflows/pxt-buildmain.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: pxt-buildmain
on:
push:
branches:
- 'master'
- 'main'
create:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install
run: |
sudo apt-get install xvfb
sudo npm install -g pxt
npm install
- name: pxt ci
run: |
pxt ci
env:
CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
PXT_ACCESS_TOKEN: ${{ secrets.PXT_ACCESS_TOKEN }}
PXT_RELEASE_REPO: ${{ secrets.PXT_RELEASE_REPO }}
NPM_ACCESS_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}
CHROME_BIN: chromium-browser
DISPLAY: :99.0
CI: true

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

@ -0,0 +1,31 @@
name: pxt-buildpr
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install
run: |
sudo apt-get install xvfb
sudo npm install -g pxt
npm install
- name: pxt ci
run: |
pxt ci
env:
CHROME_BIN: chromium-browser
DISPLAY: :99.0
CI: true

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

@ -0,0 +1,39 @@
name: pxt-buildpush
on:
push:
# main/master has its own build that includes the crowdin key
branches-ignore:
- 'main'
- 'master'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install
run: |
sudo apt-get install xvfb
sudo npm install -g pxt
npm install
- name: pxt ci
run: |
pxt ci
env:
PXT_ACCESS_TOKEN: ${{ secrets.PXT_ACCESS_TOKEN }}
PXT_RELEASE_REPO: ${{ secrets.PXT_RELEASE_REPO }}
NPM_ACCESS_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}
CHROME_BIN: chromium-browser
DISPLAY: :99.0
CI: true

View File

@ -1,9 +0,0 @@
language: node_js
node_js:
- "8.9.0"
script:
- "node node_modules/pxt-core/built/pxt.js travis"
sudo: false
cache:
directories:
- node_modules

41
SECURITY.md Normal file
View File

@ -0,0 +1,41 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->

View File

@ -1,3 +1,3 @@
{ {
"appref": "v" "appref": "v1.4"
} }

View File

@ -27,7 +27,6 @@ while (true) {
music.playSoundEffectUntilDone(sounds.mechanicalMotorStart) music.playSoundEffectUntilDone(sounds.mechanicalMotorStart)
music.playSoundEffectUntilDone(sounds.mechanicalMotorIdle); music.playSoundEffectUntilDone(sounds.mechanicalMotorIdle);
} }
pause(1);
} }
``` ```
@ -43,6 +42,5 @@ while (true) {
music.playSoundEffectUntilDone(sounds.mechanicalMotorStart) music.playSoundEffectUntilDone(sounds.mechanicalMotorStart)
music.playSoundEffectUntilDone(sounds.mechanicalMotorIdle); music.playSoundEffectUntilDone(sounds.mechanicalMotorIdle);
} }
pause(1);
} }
``` ```

View File

@ -1,3 +1,3 @@
{ {
"appref": "v1.2.27" "appref": "v1.2.31"
} }

View File

@ -2,16 +2,16 @@
## Example #example ## Example #example
Use the a wait and the timer to generate a crazy number. Use a wait and the timer to generate a number.
```blocks ```blocks
let crazy = 0 let something = 0
for (let i = 0; i < 100; i++) { for (let i = 0; i < 100; i++) {
control.waitMicros(100) control.waitMicros(100)
crazy = control.millis() something = control.millis()
crazy += control.deviceSerialNumber() something += control.deviceSerialNumber()
if (crazy != 0) { if (something != 0) {
crazy = crazy / 1000000 something = something / 1000000
} }
} }
``` ```

View File

@ -49,7 +49,7 @@ declare interface Serial extends EventTarget {
requestPort(options: SerialPortRequestOptions): Promise<SerialPort>; requestPort(options: SerialPortRequestOptions): Promise<SerialPort>;
} }
class WebSerialPackageIO implements pxt.HF2.PacketIO { class WebSerialPackageIO implements pxt.packetio.PacketIO {
onData: (v: Uint8Array) => void; onData: (v: Uint8Array) => void;
onError: (e: Error) => void; onError: (e: Error) => void;
onEvent: (v: Uint8Array) => void; onEvent: (v: Uint8Array) => void;
@ -87,7 +87,7 @@ class WebSerialPackageIO implements pxt.HF2.PacketIO {
} }
static portIos: WebSerialPackageIO[] = []; static portIos: WebSerialPackageIO[] = [];
static async mkPacketIOAsync(): Promise<pxt.HF2.PacketIO> { static async mkPacketIOAsync(): Promise<pxt.packetio.PacketIO> {
const serial = (<any>navigator).serial; const serial = (<any>navigator).serial;
if (serial) { if (serial) {
try { try {
@ -130,7 +130,7 @@ class WebSerialPackageIO implements pxt.HF2.PacketIO {
private async closeAsync() { private async closeAsync() {
// don't close port // don't close port
return Promise.delay(500); return pxt.U.delay(500);
} }
reconnectAsync(): Promise<void> { reconnectAsync(): Promise<void> {
@ -146,11 +146,33 @@ class WebSerialPackageIO implements pxt.HF2.PacketIO {
this._writer = this.port.writable.getWriter(); this._writer = this.port.writable.getWriter();
return this._writer.write(pkt); return this._writer.write(pkt);
} }
onDeviceConnectionChanged(connect: boolean) {
throw new Error("onDeviceConnectionChanged not implemented");
}
onConnectionChanged() {
throw new Error("onConnectionChanged not implemented");
}
isConnecting() {
throw new Error("isConnecting not implemented");
return false;
}
isConnected() {
throw new Error("isConnected not implemented");
return false;
}
disposeAsync() {
return Promise.reject("disposeAsync not implemented")
}
} }
function hf2Async() { function hf2Async() {
const pktIOAsync: Promise<pxt.HF2.PacketIO> = useWebSerial const pktIOAsync: Promise<pxt.packetio.PacketIO> = useWebSerial
? WebSerialPackageIO.mkPacketIOAsync() : pxt.HF2.mkPacketIOAsync() ? WebSerialPackageIO.mkPacketIOAsync() : pxt.packetio.mkPacketIOAsync()
return pktIOAsync.then(h => { return pktIOAsync.then(h => {
let w = new Ev3Wrapper(h) let w = new Ev3Wrapper(h)
ev3 = w ev3 = w
@ -190,14 +212,19 @@ export function enableWebSerialAsync() {
else return Promise.resolve(); else return Promise.resolve();
} }
function cleanupAsync() { async function cleanupAsync() {
if (ev3) { if (ev3) {
console.log('cleanup previous port') console.log('cleanup previous port')
return ev3.disconnectAsync() try {
.catch(e => { }) await ev3.disconnectAsync()
.finally(() => { ev3 = undefined; }); }
catch (e) {
}
finally {
ev3 = undefined;
}
} }
return Promise.resolve();
} }
let initPromise: Promise<Ev3Wrapper> let initPromise: Promise<Ev3Wrapper>
@ -207,7 +234,7 @@ function initHidAsync() { // needs to run within a click handler
if (useHID) { if (useHID) {
initPromise = cleanupAsync() initPromise = cleanupAsync()
.then(() => hf2Async()) .then(() => hf2Async())
.catch(err => { .catch((err: any) => {
console.error(err); console.error(err);
initPromise = null initPromise = null
useHID = false; useHID = false;
@ -284,7 +311,7 @@ export function deployCoreAsync(resp: pxtc.CompileResult) {
.catch(e => { .catch(e => {
// user easily forgets to stop robot // user easily forgets to stop robot
bluetoothTryAgainAsync().then(() => w.disconnectAsync()) bluetoothTryAgainAsync().then(() => w.disconnectAsync())
.then(() => Promise.delay(1000)) .then(() => pxt.U.delay(1000))
.then(() => w.reconnectAsync()); .then(() => w.reconnectAsync());
// nothing we can do // nothing we can do
@ -296,7 +323,7 @@ export function deployCoreAsync(resp: pxtc.CompileResult) {
.then(() => w.flashAsync(elfPath, UF2.readBytes(origElfUF2, 0, origElfUF2.length * 256))) .then(() => w.flashAsync(elfPath, UF2.readBytes(origElfUF2, 0, origElfUF2.length * 256)))
.then(() => w.flashAsync(rbfPath, rbfBIN)) .then(() => w.flashAsync(rbfPath, rbfBIN))
.then(() => w.runAsync(rbfPath)) .then(() => w.runAsync(rbfPath))
.then(() => Promise.delay(500)) .then(() => pxt.U.delay(500))
.then(() => { .then(() => {
pxt.tickEvent("webserial.success"); pxt.tickEvent("webserial.success");
return w.disconnectAsync() return w.disconnectAsync()

View File

@ -1,4 +1,5 @@
import * as React from "react"; import * as React from "react";
import { canUseWebSerial, enableWebSerialAsync } from "./deploy"; import { canUseWebSerial, enableWebSerialAsync } from "./deploy";
import { projectView } from "./extension"; import { projectView } from "./extension";
@ -21,7 +22,7 @@ export function bluetoothTryAgainAsync(): Promise<void> {
function enableWebSerialAndCompileAsync() { function enableWebSerialAndCompileAsync() {
return enableWebSerialAsync() return enableWebSerialAsync()
.then(() => Promise.delay(500)) .then(() => pxt.U.delay(500))
.then(() => projectView.compile()); .then(() => projectView.compile());
} }
@ -52,11 +53,12 @@ function explainWebSerialPairingAsync(): Promise<void> {
export function showUploadDialogAsync(fn: string, url: string, _confirmAsync: (options: any) => Promise<number>): Promise<void> { export function showUploadDialogAsync(fn: string, url: string, _confirmAsync: (options: any) => Promise<number>): Promise<void> {
confirmAsync = _confirmAsync; confirmAsync = _confirmAsync;
// https://msdn.microsoft.com/en-us/library/cc848897.aspx // https://msdn.microsoft.com/en-us/library/cc848897.aspx
// "For security reasons, data URIs are restricted to downloaded resources. // "For security reasons, data URIs are restricted to downloaded resources.
// Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements" // Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements"
const downloadAgain = !pxt.BrowserUtils.isIE() && !pxt.BrowserUtils.isEdge(); const downloadAgain = !pxt.BrowserUtils.isIE() && !pxt.BrowserUtils.isEdge();
const docUrl = pxt.appTarget.appTheme.usbDocs; const docUrl = (pxt.appTarget.appTheme.usbDocs ? pxt.appTarget.appTheme.usbDocs : false);
const jsx = const jsx =
<div className="ui grid stackable"> <div className="ui grid stackable">
@ -118,7 +120,7 @@ export function showUploadDialogAsync(fn: string, url: string, _confirmAsync: (o
hideAgree: false, hideAgree: false,
agreeLbl: lf("I got it"), agreeLbl: lf("I got it"),
className: 'downloaddialog', className: 'downloaddialog',
buttons: [canUseWebSerial() ? { buttons: [canUseWebSerial() && {
label: lf("Bluetooth"), label: lf("Bluetooth"),
icon: "bluetooth", icon: "bluetooth",
className: "bluetooth focused", className: "bluetooth focused",
@ -126,20 +128,19 @@ export function showUploadDialogAsync(fn: string, url: string, _confirmAsync: (o
pxt.tickEvent("bluetooth.enable"); pxt.tickEvent("bluetooth.enable");
explainWebSerialPairingAsync() explainWebSerialPairingAsync()
.then(() => enableWebSerialAndCompileAsync()) .then(() => enableWebSerialAndCompileAsync())
.done();
} }
} : undefined, downloadAgain ? { }, downloadAgain && {
label: fn, label: fn,
icon: "download", icon: "download",
className: "lightgrey focused", className: "lightgrey focused",
url, url,
fileName: fn fileName: fn
} : undefined, docUrl ? { }, docUrl && {
label: lf("Help"), label: lf("Help"),
icon: "help", icon: "help",
className: "lightgrey", className: "lightgrey",
url: docUrl url: docUrl
} : undefined] }]
//timeout: 20000 //timeout: 20000
}).then(() => { }); }).then(() => { });
} }

View File

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

View File

@ -26,7 +26,7 @@ export class Ev3Wrapper {
isStreaming = false; isStreaming = false;
dataDump = /talkdbg=1/.test(window.location.href); dataDump = /talkdbg=1/.test(window.location.href);
constructor(public io: pxt.HF2.PacketIO) { constructor(public io: pxt.packetio.PacketIO) {
io.onData = buf => { io.onData = buf => {
buf = buf.slice(0, HF2.read16(buf, 0) + 2) buf = buf.slice(0, HF2.read16(buf, 0) + 2)
if (HF2.read16(buf, 4) == usbMagic) { if (HF2.read16(buf, 4) == usbMagic) {
@ -81,7 +81,7 @@ export class Ev3Wrapper {
log(`stopping PXT app`) log(`stopping PXT app`)
let buf = this.allocCustom(2) let buf = this.allocCustom(2)
return this.justSendAsync(buf) return this.justSendAsync(buf)
.then(() => Promise.delay(500)) .then(() => pxt.U.delay(500))
}) })
} }
@ -116,7 +116,7 @@ export class Ev3Wrapper {
if (this.dataDump) if (this.dataDump)
log("TALK: " + U.toHex(buf)) log("TALK: " + U.toHex(buf))
return this.io.sendPacketAsync(buf) return this.io.sendPacketAsync(buf)
.then(() => this.msgs.shiftAsync(1000)) .then(() => this.msgs.shiftAsync(5000))
.then(resp => { .then(resp => {
if (resp[2] != buf[2] || resp[3] != buf[3]) if (resp[2] != buf[2] || resp[3] != buf[3])
U.userError("msg count de-sync") U.userError("msg count de-sync")
@ -236,7 +236,7 @@ export class Ev3Wrapper {
let contFileReq = this.allocSystem(1 + 2, 0x97) let contFileReq = this.allocSystem(1 + 2, 0x97)
HF2.write16(contFileReq, 7, 1000) // maxRead HF2.write16(contFileReq, 7, 1000) // maxRead
contFileReq[6] = handle contFileReq[6] = handle
return Promise.delay(data.length > 0 ? 0 : 500) return pxt.U.delay(data.length > 0 ? 0 : 500)
.then(() => this.talkAsync(contFileReq, -1)) .then(() => this.talkAsync(contFileReq, -1))
.then(resp) .then(resp)
} }
@ -251,7 +251,7 @@ export class Ev3Wrapper {
let loop = (): Promise<void> => let loop = (): Promise<void> =>
this.lock.enqueue("file", () => this.lock.enqueue("file", () =>
this.streamFileOnceAsync(path, cb)) this.streamFileOnceAsync(path, cb))
.then(() => Promise.delay(500)) .then(() => pxt.U.delay(500))
.then(loop) .then(loop)
return loop() return loop()
} }

View File

@ -120,20 +120,17 @@ export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly.
Blockly.DropDownDiv.setColour('#ffffff', '#dddddd'); Blockly.DropDownDiv.setColour('#ffffff', '#dddddd');
// Calculate positioning based on the field position. // Position based on the field position.
let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale; Blockly.DropDownDiv.showPositionedByField(this, this.onHide_.bind(this));
let bBox = { width: this.size_.width, height: this.size_.height };
bBox.width *= scale; // Update colour to look selected.
bBox.height *= scale; let source = this.sourceBlock_ as Blockly.BlockSvg;
let position = this.fieldGroup_.getBoundingClientRect(); this.savedPrimary_ = source?.getColour();
let primaryX = position.left + bBox.width / 2; if (source?.isShadow()) {
let primaryY = position.top + bBox.height; source.setColour(source.getColourTertiary());
let secondaryX = primaryX; } else if (this.borderRect_) {
let secondaryY = position.top; this.borderRect_.setAttribute('fill', (this.sourceBlock_ as Blockly.BlockSvg).getColourTertiary());
// Set bounds to workspace; show the drop-down. }
(Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode);
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
this.onHide_.bind(this));
} }
/** /**
@ -157,5 +154,12 @@ export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly.
content.removeAttribute('aria-haspopup'); content.removeAttribute('aria-haspopup');
content.removeAttribute('aria-activedescendant'); content.removeAttribute('aria-activedescendant');
(content as HTMLElement).style.width = ''; (content as HTMLElement).style.width = '';
// Update color (deselect) on dropdown hide
let source = this.sourceBlock_ as Blockly.BlockSvg;
if (source?.isShadow()) {
source.setColour(this.savedPrimary_);
} else if (this.borderRect_) {
this.borderRect_.setAttribute('fill', this.savedPrimary_);
}
}; };
} }

View File

@ -5,10 +5,14 @@ export interface FieldColorEnumOptions extends pxtblockly.FieldColourNumberOptio
} }
export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Blockly.FieldCustom { export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Blockly.FieldCustom {
public isFieldCustom_ = true; public isFieldCustom_ = true;
private paramsData: any[];
constructor(text: string, params: FieldColorEnumOptions, opt_validator?: Function) { constructor(text: string, params: FieldColorEnumOptions, opt_validator?: Function) {
super(text, params, opt_validator); super(text, params, opt_validator);
this.paramsData = params["data"];
} }
mapColour(enumString: string) { mapColour(enumString: string) {
@ -33,11 +37,21 @@ export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Block
case 'ColorSensorColor.Red': return '#f12a21'; case 'ColorSensorColor.Red': return '#f12a21';
case 'ColorSensorColor.White': return '#ffffff'; case 'ColorSensorColor.White': return '#ffffff';
case 'ColorSensorColor.Brown': return '#6c2d00'; case 'ColorSensorColor.Brown': return '#6c2d00';
case 'ColorSensorColor.None': return '#dfe6e9'; // Grey case 'ColorSensorColor.None': return '#dfe6e9';
default: return colorString; default: return colorString;
} }
} }
showEditor_() {
super.showEditor_();
const colorCells = document.querySelectorAll('.legoColorPicker td');
colorCells.forEach((cell) => {
const titleName = this.mapColour(cell.getAttribute("title"));
const index = this.paramsData.findIndex(item => item[1] === titleName);
cell.setAttribute("title", this.paramsData[index][0]);
});
}
/** /**
* Return the current colour. * Return the current colour.
* @param {boolean} opt_asHex optional field if the returned value should be a hex * @param {boolean} opt_asHex optional field if the returned value should be a hex
@ -64,7 +78,7 @@ export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Block
} }
this.value_ = colour; this.value_ = colour;
if (this.sourceBlock_) { if (this.sourceBlock_) {
this.sourceBlock_.setColour(colour, colour, colour); this.sourceBlock_.setColour(colour);
} }
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -11,6 +11,7 @@ declare const pxtTargetBundle: any;
let soundCache: any; let soundCache: any;
let soundIconCache: any; let soundIconCache: any;
let soundIconCacheArray: any;
export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldCustom { export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldCustom {
public isFieldCustom_ = true; public isFieldCustom_ = true;
@ -23,17 +24,17 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
super(text, { blocksInfo: options.blocksInfo, sort: true, data: options.data }, validator); super(text, { blocksInfo: options.blocksInfo, sort: true, data: options.data }, validator);
this.columns_ = parseInt(options.columns) || 4; this.columns_ = parseInt(options.columns) || 4;
this.width_ = parseInt(options.width) || 380; this.width_ = parseInt(options.width) || 450;
this.setText = Blockly.FieldDropdown.prototype.setText; this.setText = Blockly.FieldDropdown.prototype.setText;
this.updateSize_ = (Blockly.Field as any).prototype.updateSize_; this.updateSize_ = (Blockly.Field as any).prototype.updateSize_;
this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_;
if (!pxt.BrowserUtils.isIE() && !soundCache) { if (!pxt.BrowserUtils.isIE() && !soundCache) {
soundCache = JSON.parse(pxtTargetBundle.bundledpkgs['music']['sounds.jres']); soundCache = JSON.parse(pxtTargetBundle.bundledpkgs['music']['sounds.jres']);
} }
if (!soundIconCache) { if (!soundIconCache) {
soundIconCache = JSON.parse(pxtTargetBundle.bundledpkgs['music']['icons.jres']); soundIconCache = JSON.parse(pxtTargetBundle.bundledpkgs['music']['icons.jres']);
soundIconCacheArray = Object.entries(soundIconCache).filter(el => el[0] !== "*");
} }
} }
@ -50,14 +51,17 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
Blockly.DropDownDiv.hideWithoutAnimation(); Blockly.DropDownDiv.hideWithoutAnimation();
Blockly.DropDownDiv.clearContent(); Blockly.DropDownDiv.clearContent();
// Populate the drop-down with the icons for this field. // Populate the drop-down with the icons for this field.
let dropdownDiv = Blockly.DropDownDiv.getContentDiv(); let dropdownDiv = Blockly.DropDownDiv.getContentDiv() as HTMLElement;
let contentDiv = document.createElement('div'); let contentDiv = document.createElement('div');
// Accessibility properties // Accessibility properties
contentDiv.setAttribute('role', 'menu'); contentDiv.setAttribute('role', 'menu');
contentDiv.setAttribute('aria-haspopup', 'true'); contentDiv.setAttribute('aria-haspopup', 'true');
contentDiv.className = 'blocklyMusicFieldOptions'; contentDiv.className = 'blocklyMusicFieldOptions';
contentDiv.style.display = "flex";
contentDiv.style.flexWrap = "wrap";
contentDiv.style.float = "none";
const options = this.getOptions(); const options = this.getOptions();
options.sort(); //options.sort(); // Do not need to use to not apply sorting in different languages
// Create categoies // Create categoies
const categories = this.getCategories(options); const categories = this.getCategories(options);
@ -68,7 +72,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
// Accessibility properties // Accessibility properties
categoriesDiv.setAttribute('role', 'menu'); categoriesDiv.setAttribute('role', 'menu');
categoriesDiv.setAttribute('aria-haspopup', 'true'); categoriesDiv.setAttribute('aria-haspopup', 'true');
categoriesDiv.style.backgroundColor = this.sourceBlock_.getColourTertiary(); categoriesDiv.style.backgroundColor = (this.sourceBlock_ as Blockly.BlockSvg).getColourTertiary();
categoriesDiv.className = 'blocklyMusicFieldCategories'; categoriesDiv.className = 'blocklyMusicFieldCategories';
this.refreshCategories(categoriesDiv, categories); this.refreshCategories(categoriesDiv, categories);
@ -82,30 +86,18 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
dropdownDiv.appendChild(categoriesDiv); dropdownDiv.appendChild(categoriesDiv);
dropdownDiv.appendChild(contentDiv); dropdownDiv.appendChild(contentDiv);
Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary()); Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), (this.sourceBlock_ as Blockly.BlockSvg).getColourTertiary());
// Calculate positioning based on the field position. // Position based on the field position.
let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale; Blockly.DropDownDiv.showPositionedByField(this, this.onHide_.bind(this));
let bBox = { width: this.size_.width, height: this.size_.height };
bBox.width *= scale;
bBox.height *= scale;
let position = this.fieldGroup_.getBoundingClientRect();
let primaryX = position.left + bBox.width / 2;
let primaryY = position.top + bBox.height;
let secondaryX = primaryX;
let secondaryY = position.top;
// Set bounds to workspace; show the drop-down.
(Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode);
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
this.onHide_.bind(this));
// Update colour to look selected. // Update colour to look selected.
if (this.sourceBlock_.isShadow()) { let source = this.sourceBlock_ as Blockly.BlockSvg;
this.savedPrimary_ = this.sourceBlock_.getColour(); this.savedPrimary_ = source?.getColour();
this.sourceBlock_.setColour(this.sourceBlock_.getColourTertiary(), if (source?.isShadow()) {
this.sourceBlock_.getColourSecondary(), this.sourceBlock_.getColourTertiary()); source.setColour(source.getColourTertiary());
} else if (this.box_) { } else if (this.borderRect_) {
this.box_.setAttribute('fill', this.sourceBlock_.getColourTertiary()); this.borderRect_.setAttribute('fill', (this.sourceBlock_ as Blockly.BlockSvg).getColourTertiary());
} }
} }
@ -138,6 +130,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
backgroundColor = '#0c4e5e'; backgroundColor = '#0c4e5e';
button.setAttribute('aria-selected', 'true'); button.setAttribute('aria-selected', 'true');
} }
button.style.padding = "2px 6px";
button.style.backgroundColor = backgroundColor; button.style.backgroundColor = backgroundColor;
button.style.borderColor = backgroundColor; button.style.borderColor = backgroundColor;
Blockly.bindEvent_(button, 'click', this, this.categoryClick_); Blockly.bindEvent_(button, 'click', this, this.categoryClick_);
@ -151,7 +144,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
} }
refreshOptions(contentDiv: Element, options: any) { refreshOptions(contentDiv: Element, options: any) {
const categories = this.getCategories(options);
// Show options // Show options
for (let i = 0, option: any; option = options[i]; i++) { for (let i = 0, option: any; option = options[i]; i++) {
let content = (options[i] as any)[0]; // Human-readable text or image. let content = (options[i] as any)[0]; // Human-readable text or image.
@ -186,11 +179,11 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
let backgroundColor = this.savedPrimary_ || this.sourceBlock_.getColour(); let backgroundColor = this.savedPrimary_ || this.sourceBlock_.getColour();
if (value == this.getValue()) { if (value == this.getValue()) {
// This icon is selected, show it in a different colour // This icon is selected, show it in a different colour
backgroundColor = this.sourceBlock_.getColourTertiary(); backgroundColor = (this.sourceBlock_ as Blockly.BlockSvg).getColourTertiary();
button.setAttribute('aria-selected', 'true'); button.setAttribute('aria-selected', 'true');
} }
button.style.backgroundColor = backgroundColor; button.style.backgroundColor = backgroundColor;
button.style.borderColor = this.sourceBlock_.getColourTertiary(); button.style.borderColor = (this.sourceBlock_ as Blockly.BlockSvg).getColourTertiary();
Blockly.bindEvent_(button, 'click', this, this.buttonClick_); Blockly.bindEvent_(button, 'click', this, this.buttonClick_);
Blockly.bindEvent_(button, 'mouseup', this, this.buttonClick_); Blockly.bindEvent_(button, 'mouseup', this, this.buttonClick_);
// These are applied manually instead of using the :hover pseudoclass // These are applied manually instead of using the :hover pseudoclass
@ -215,15 +208,27 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
this.setAttribute('class', 'blocklyDropDownButton'); this.setAttribute('class', 'blocklyDropDownButton');
contentDiv.removeAttribute('aria-activedescendant'); contentDiv.removeAttribute('aria-activedescendant');
}); });
// Find index in array by category name
const categoryIndex = categories.indexOf(category);
let buttonImg = document.createElement('img'); let buttonImg = document.createElement('img');
buttonImg.src = this.getSoundIcon(category); buttonImg.src = this.getSoundIcon(categoryIndex);
//buttonImg.alt = icon.alt;
// Upon click/touch, we will be able to get the clicked element as e.target // Upon click/touch, we will be able to get the clicked element as e.target
// Store a data attribute on all possible click targets so we can match it to the icon. // Store a data attribute on all possible click targets so we can match it to the icon.
const textNode = this.createTextNode_(content); const textNode = this.createTextNode_(content);
button.setAttribute('data-value', value); button.setAttribute('data-value', value);
buttonImg.setAttribute('data-value', value); buttonImg.setAttribute('data-value', value);
buttonImg.style.height = "auto";
textNode.setAttribute('data-value', value); textNode.setAttribute('data-value', value);
if (pxt.Util.userLanguage() !== "en") textNode.setAttribute('lang', pxt.Util.userLanguage()); // for hyphens, here you need to set the correct abbreviation of the selected language
textNode.style.display = "block";
textNode.style.lineHeight = "1rem";
textNode.style.marginBottom = "5%";
textNode.style.padding = "0px 8px";
textNode.style.wordBreak = "break-word";
textNode.style.hyphens = "auto";
button.appendChild(buttonImg); button.appendChild(buttonImg);
button.appendChild(textNode); button.appendChild(textNode);
@ -238,12 +243,19 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
super.onHide_(); super.onHide_();
(Blockly.DropDownDiv.getContentDiv() as HTMLElement).style.maxHeight = ''; (Blockly.DropDownDiv.getContentDiv() as HTMLElement).style.maxHeight = '';
this.stopSounds(); this.stopSounds();
// Update color (deselect) on dropdown hide
let source = this.sourceBlock_ as Blockly.BlockSvg;
if (source?.isShadow()) {
source.setColour(this.savedPrimary_);
} else if (this.borderRect_) {
this.borderRect_.setAttribute('fill', this.savedPrimary_);
}
} }
protected createTextNode_(content: string) { protected createTextNode_(content: string) {
const category = this.parseCategory(content); const category = this.parseCategory(content);
let text = content.substr(content.indexOf(' ') + 1); let text = content.substr(content.indexOf(' ') + 1);
text = text.length > 15 ? text.substr(0, 12) + "..." : text;
const textSpan = document.createElement('span'); const textSpan = document.createElement('span');
textSpan.setAttribute('class', 'blocklyDropdownText'); textSpan.setAttribute('class', 'blocklyDropdownText');
textSpan.textContent = text; textSpan.textContent = text;
@ -311,9 +323,9 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
pxsim.AudioContextManager.stop(); pxsim.AudioContextManager.stop();
} }
private getSoundIcon(category: string) { private getSoundIcon(indexCategory: number) {
if (soundIconCache && soundIconCache[category]) { if (soundIconCacheArray && soundIconCacheArray[indexCategory]) {
return soundIconCache[category].icon; return soundIconCacheArray[indexCategory][1].icon;
} }
return undefined; return undefined;
} }

View File

@ -18,7 +18,6 @@ export class FieldPorts extends pxtblockly.FieldImages implements Blockly.FieldC
this.setText = Blockly.FieldDropdown.prototype.setText; this.setText = Blockly.FieldDropdown.prototype.setText;
this.updateSize_ = (Blockly.Field as any).prototype.updateSize_; this.updateSize_ = (Blockly.Field as any).prototype.updateSize_;
this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_;
} }
trimOptions_() { trimOptions_() {

View File

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

View File

@ -204,6 +204,8 @@ declare namespace control {
*/ */
//% shim=control::dmesgValue //% shim=control::dmesgValue
function dmesgValue(v: any): void; function dmesgValue(v: any): void;
}
declare namespace control {
/** /**
* Force GC and dump basic information about heap. * Force GC and dump basic information about heap.

View File

@ -250,7 +250,7 @@ namespace sensors {
} }
/** /**
* Measure the ambient or reflected light value from 0 (darkest) to 100 (brightest). * Measure the ambient or reflected light value from 0 (darkest) to 100 (brightest). In raw reflection light mode, the range will be different.
* @param sensor the color sensor port * @param sensor the color sensor port
*/ */
//% help=sensors/color-sensor/light //% help=sensors/color-sensor/light

View File

@ -1,5 +1,3 @@
namespace sensors { namespace sensors {
/** /**
@ -9,7 +7,7 @@ namespace sensors {
//% blockId=colorEnumPicker block="%color" shim=TD_ID //% blockId=colorEnumPicker block="%color" shim=TD_ID
//% weight=0 blockHidden=1 turnRatio.fieldOptions.decompileLiterals=1 //% weight=0 blockHidden=1 turnRatio.fieldOptions.decompileLiterals=1
//% color.fieldEditor="colorenum" //% color.fieldEditor="colorenum"
//% color.fieldOptions.colours='["#f12a21", "#ffd01b", "#006db3", "#00934b", "#000000", "#6c2d00", "#ffffff"]' //% color.fieldOptions.colours='["#f12a21", "#ffd01b", "#006db3", "#00934b", "#000000", "#6c2d00", "#ffffff", "#dfe6e9"]'
//% color.fieldOptions.columns=2 color.fieldOptions.className='legoColorPicker' //% color.fieldOptions.columns=2 color.fieldOptions.className='legoColorPicker'
export function __colorEnumPicker(color: ColorSensorColor): number { export function __colorEnumPicker(color: ColorSensorColor): number {
return color; return color;

11
libs/core/cooperate.ts Normal file
View File

@ -0,0 +1,11 @@
namespace control {
let lastPause = 0;
const COOPERATION_INTERVAL = 20
export function cooperate() {
const now = control.millis()
if (now - lastPause > COOPERATION_INTERVAL) {
lastPause = now
pause(1)
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -21,8 +21,7 @@ namespace sensors.internal {
const now = control.millis(); const now = control.millis();
if (now - this.lastQuery >= this.interval * 2) if (now - this.lastQuery >= this.interval * 2)
this.queryAndUpdate(); // sensor poller is not allowed to run this.queryAndUpdate(); // sensor poller is not allowed to run
if (now - this.lastPause >= this.interval * 5) control.cooperate(); // allow events to trigger
pause(1); // allow events to trigger
} }
private queryAndUpdate() { private queryAndUpdate() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -124,7 +124,7 @@ namespace motors {
export function stopAll() { export function stopAll() {
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0) const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
writePWM(b); writePWM(b);
pause(1); control.cooperate();
} }
/** /**
@ -136,7 +136,7 @@ namespace motors {
//% help=motors/reset-all //% help=motors/reset-all
export function resetAll() { export function resetAll() {
reset(Output.ALL) reset(Output.ALL)
pause(1); control.cooperate();
} }
interface MoveSchedule { interface MoveSchedule {
@ -196,6 +196,7 @@ namespace motors {
*/ */
//% blockId=outputMotorSetBrakeMode block="set %motor|brake %brake=toggleOnOff" //% blockId=outputMotorSetBrakeMode block="set %motor|brake %brake=toggleOnOff"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=60 blockGap=8 //% weight=60 blockGap=8
//% group="Properties" //% group="Properties"
//% help=motors/motor/set-brake //% help=motors/motor/set-brake
@ -210,6 +211,7 @@ namespace motors {
*/ */
//% blockId=outputMotorSetPauseMode block="set %motor|pause on run %brake=toggleOnOff" //% blockId=outputMotorSetPauseMode block="set %motor|pause on run %brake=toggleOnOff"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=60 blockGap=8 //% weight=60 blockGap=8
//% group="Properties" //% group="Properties"
setPauseOnRun(value: boolean) { setPauseOnRun(value: boolean) {
@ -222,6 +224,7 @@ namespace motors {
*/ */
//% blockId=motorSetInverted block="set %motor|inverted %reversed=toggleOnOff" //% blockId=motorSetInverted block="set %motor|inverted %reversed=toggleOnOff"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=59 blockGap=8 //% weight=59 blockGap=8
//% group="Properties" //% group="Properties"
//% help=motors/motor/set-inverted //% help=motors/motor/set-inverted
@ -239,6 +242,7 @@ namespace motors {
*/ */
//% blockId=motorSetBrakeSettleTime block="set %motor|brake settle time %millis|ms" //% blockId=motorSetBrakeSettleTime block="set %motor|brake settle time %millis|ms"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=1 blockGap=8 //% weight=1 blockGap=8
//% group="Properties" //% group="Properties"
//% millis.defl=200 millis.min=0 millis.max=500 //% millis.defl=200 millis.min=0 millis.max=500
@ -269,7 +273,7 @@ namespace motors {
if (this._brake && this._brakeSettleTime > 0) if (this._brake && this._brakeSettleTime > 0)
pause(this._brakeSettleTime); pause(this._brakeSettleTime);
else { else {
pause(1); control.cooperate();
} }
} }
@ -280,7 +284,7 @@ namespace motors {
// allow robot to settle // allow robot to settle
this.settle(); this.settle();
} else { } else {
pause(1); control.cooperate();
} }
} }
@ -344,6 +348,7 @@ namespace motors {
//% weight=100 blockGap=8 //% weight=100 blockGap=8
//% group="Move" //% group="Move"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% expandableArgumentMode=toggle //% expandableArgumentMode=toggle
//% help=motors/motor/run //% help=motors/motor/run
run(speed: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) { run(speed: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
@ -357,7 +362,7 @@ namespace motors {
// special: 0 is infinity // special: 0 is infinity
if (schedule.steps[0] + schedule.steps[1] + schedule.steps[2] == 0) { if (schedule.steps[0] + schedule.steps[1] + schedule.steps[2] == 0) {
this._run(schedule.speed); this._run(schedule.speed);
pause(1); control.cooperate();
return; return;
} }
@ -393,6 +398,7 @@ namespace motors {
//% weight=99 blockGap=8 //% weight=99 blockGap=8
//% group="Move" //% group="Move"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% help=motors/motor/ramp //% help=motors/motor/ramp
//% inlineInputMode=inline //% inlineInputMode=inline
//% expandableArgumentMode=toggle //% expandableArgumentMode=toggle
@ -422,6 +428,7 @@ namespace motors {
*/ */
//% blockId=outputMotorsetRunRamp block="set %motor|run %ramp to $value||$unit" //% blockId=outputMotorsetRunRamp block="set %motor|run %ramp to $value||$unit"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=21 blockGap=8 //% weight=21 blockGap=8
//% group="Properties" //% group="Properties"
//% help=motors/motor/set-run-phase //% help=motors/motor/set-run-phase
@ -493,6 +500,7 @@ namespace motors {
*/ */
//% blockId=outputMotorSetRegulated block="set %motor|regulated %value=toggleOnOff" //% blockId=outputMotorSetRegulated block="set %motor|regulated %value=toggleOnOff"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=58 blockGap=8 //% weight=58 blockGap=8
//% group="Properties" //% group="Properties"
//% help=motors/motor/set-regulated //% help=motors/motor/set-regulated
@ -518,6 +526,7 @@ namespace motors {
*/ */
//% blockId=motorPauseUntilRead block="pause until %motor|ready" //% blockId=motorPauseUntilRead block="pause until %motor|ready"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=90 blockGap=8 //% weight=90 blockGap=8
//% group="Move" //% group="Move"
pauseUntilReady(timeOut?: number) { pauseUntilReady(timeOut?: number) {
@ -576,6 +585,7 @@ namespace motors {
*/ */
//% blockId=motorSpeed block="%motor|speed" //% blockId=motorSpeed block="%motor|speed"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=72 //% weight=72
//% blockGap=8 //% blockGap=8
//% group="Counters" //% group="Counters"
@ -591,13 +601,14 @@ namespace motors {
*/ */
//% blockId=motorAngle block="%motor|angle" //% blockId=motorAngle block="%motor|angle"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=70 //% weight=70
//% blockGap=8 //% blockGap=8
//% group="Counters" //% group="Counters"
//% help=motors/motor/angle //% help=motors/motor/angle
angle(): number { angle(): number {
this.init(); this.init();
return getMotorData(this._port).count; return getMotorData(this._port).count * this.invertedFactor();
} }
/** /**
@ -605,6 +616,7 @@ namespace motors {
*/ */
//% blockId=motorClearCount block="clear %motor|counters" //% blockId=motorClearCount block="clear %motor|counters"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=68 //% weight=68
//% blockGap=8 //% blockGap=8
//% group="Counters" //% group="Counters"
@ -633,6 +645,7 @@ namespace motors {
*/ */
//% blockId=motorPauseUntilStall block="pause until %motor|stalled" //% blockId=motorPauseUntilStall block="pause until %motor|stalled"
//% motor.fieldEditor="motors" //% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=89 //% weight=89
//% group="Move" //% group="Move"
//% help=motors/motor/pause-until-stalled //% help=motors/motor/pause-until-stalled
@ -656,28 +669,28 @@ namespace motors {
} }
} }
//% whenUsed fixedInstance block="large motor A" jres=icons.portA //% whenUsed fixedInstance block="large motor A" jres=icons.motorLargePortA
export const largeA = new Motor(Output.A, true); export const largeA = new Motor(Output.A, true);
//% whenUsed fixedInstance block="large motor B" jres=icons.portB //% whenUsed fixedInstance block="large motor B" jres=icons.motorLargePortB
export const largeB = new Motor(Output.B, true); export const largeB = new Motor(Output.B, true);
//% whenUsed fixedInstance block="large motor C" jres=icons.portC //% whenUsed fixedInstance block="large motor C" jres=icons.motorLargePortC
export const largeC = new Motor(Output.C, true); export const largeC = new Motor(Output.C, true);
//% whenUsed fixedInstance block="large motor D" jres=icons.portD //% whenUsed fixedInstance block="large motor D" jres=icons.motorLargePortD
export const largeD = new Motor(Output.D, true); export const largeD = new Motor(Output.D, true);
//% whenUsed fixedInstance block="medium motor A" jres=icons.portA //% whenUsed fixedInstance block="medium motor A" jres=icons.motorMeduimPortA
export const mediumA = new Motor(Output.A, false); export const mediumA = new Motor(Output.A, false);
//% whenUsed fixedInstance block="medium motor B" jres=icons.portB //% whenUsed fixedInstance block="medium motor B" jres=icons.motorMeduimPortB
export const mediumB = new Motor(Output.B, false); export const mediumB = new Motor(Output.B, false);
//% whenUsed fixedInstance block="medium motor C" jres=icons.portC //% whenUsed fixedInstance block="medium motor C" jres=icons.motorMeduimPortC
export const mediumC = new Motor(Output.C, false); export const mediumC = new Motor(Output.C, false);
//% whenUsed fixedInstance block="medium motor D" jres=icons.portD //% whenUsed fixedInstance block="medium motor D" jres=icons.motorMeduimPortD
export const mediumD = new Motor(Output.D, false); export const mediumD = new Motor(Output.D, false);
//% fixedInstances //% fixedInstances
@ -708,7 +721,7 @@ namespace motors {
* @param unit (optional) unit of the value * @param unit (optional) unit of the value
*/ */
//% blockId=motorPairTank block="tank **motors** %motors %speedLeft=motorSpeedPicker|\\% %speedRight=motorSpeedPicker|\\%||for %value %unit" //% blockId=motorPairTank block="tank **motors** %motors %speedLeft=motorSpeedPicker|\\% %speedRight=motorSpeedPicker|\\%||for %value %unit"
//% motors.fieldEditor="ports" //% motors.fieldEditor="motors"
//% weight=96 blockGap=8 //% weight=96 blockGap=8
//% inlineInputMode=inline //% inlineInputMode=inline
//% group="Move" //% group="Move"
@ -738,7 +751,7 @@ namespace motors {
* @param unit (optional) unit of the value * @param unit (optional) unit of the value
*/ */
//% blockId=motorPairSteer block="steer **motors** %chassis turn ratio %turnRatio=motorTurnRatioPicker speed %speed=motorSpeedPicker|\\%||for %value %unit" //% blockId=motorPairSteer block="steer **motors** %chassis turn ratio %turnRatio=motorTurnRatioPicker speed %speed=motorSpeedPicker|\\%||for %value %unit"
//% chassis.fieldEditor="ports" //% chassis.fieldEditor="motors"
//% weight=95 //% weight=95
//% turnRatio.min=-200 turnRatio=200 //% turnRatio.min=-200 turnRatio=200
//% inlineInputMode=inline //% inlineInputMode=inline
@ -811,16 +824,16 @@ namespace motors {
} }
} }
//% whenUsed fixedInstance block="B+C" jres=icons.portBC //% whenUsed fixedInstance block="large motors B+C" jres=icons.dualMotorLargePortBC
export const largeBC = new SynchedMotorPair(Output.BC); export const largeBC = new SynchedMotorPair(Output.BC);
//% whenUsed fixedInstance block="A+D" jres=icons.portAD //% whenUsed fixedInstance block="large motors A+D" jres=icons.dualMotorLargePortAD
export const largeAD = new SynchedMotorPair(Output.AD); export const largeAD = new SynchedMotorPair(Output.AD);
//% whenUsed fixedInstance block="A+B" jres=icons.portAB //% whenUsed fixedInstance block="large motors A+B" jres=icons.dualMotorLargePortAB
export const largeAB = new SynchedMotorPair(Output.AB); export const largeAB = new SynchedMotorPair(Output.AB);
//% whenUsed fixedInstance block="C+D" jres=icons.portCD //% whenUsed fixedInstance block="large motors C+D" jres=icons.dualMotorLargePortCD
export const largeCD = new SynchedMotorPair(Output.CD); export const largeCD = new SynchedMotorPair(Output.CD);
function reset(out: Output) { function reset(out: Output) {

View File

@ -28,7 +28,8 @@
"platform.h", "platform.h",
"platform.cpp", "platform.cpp",
"dmesg.cpp", "dmesg.cpp",
"integrator.ts" "integrator.ts",
"cooperate.ts"
], ],
"testFiles": [ "testFiles": [
"test.ts" "test.ts"

View File

@ -12,4 +12,5 @@ music.setTempo(120)
music.noteFrequency(Note.C) music.noteFrequency(Note.C)
music.beat() music.beat()
music.setVolume(50) music.setVolume(50)
music.volume()
``` ```

View File

@ -13,7 +13,22 @@
namespace music { namespace music {
uint8_t currVolume = 50; int _readSystemVolume() {
char ParBuf[8];
int volume;
int fd = open("../sys/settings/Volume.rtf", O_RDONLY);
read(fd, ParBuf, sizeof(ParBuf));
close(fd);
if (sscanf(ParBuf,"%d",&volume) > 0) {
if ((volume >= 0) && (volume <= 100)) {
return volume;
}
}
return 50;
}
uint8_t currVolume = _readSystemVolume();
uint8_t *lmsSoundMMap; uint8_t *lmsSoundMMap;
int writeDev(void *data, int size) { int writeDev(void *data, int size) {
@ -37,6 +52,18 @@ void setVolume(int volume) {
currVolume = max(0, min(100, volume)); currVolume = max(0, min(100, volume));
} }
/**
* Return the output volume of the sound synthesizer.
*/
//% weight=96
//% blockId=synth_get_volume block="volume"
//% parts="speaker" blockGap=8
//% help=music/volume
//% weight=1
int volume() {
return currVolume;
}
#define SOUND_CMD_BREAK 0 #define SOUND_CMD_BREAK 0
#define SOUND_CMD_TONE 1 #define SOUND_CMD_TONE 1
#define SOUND_CMD_PLAY 2 #define SOUND_CMD_PLAY 2
@ -45,7 +72,7 @@ void setVolume(int volume) {
struct ToneCmd { struct ToneCmd {
uint8_t cmd; uint8_t cmd;
uint8_t vol; uint8_t lvl;
uint16_t freq; uint16_t freq;
uint16_t duration; uint16_t duration;
}; };
@ -55,10 +82,26 @@ static void _stopSound() {
writeDev(&cmd, sizeof(cmd)); writeDev(&cmd, sizeof(cmd));
} }
static uint8_t _getVolumeLevel(uint8_t volume, uint8_t levels) {
uint8_t level;
uint8_t step = (uint8_t) (100 / (levels - 1));
if (volume < step) {
level = 0;
} else if (volume > step * (levels - 1)) {
level = levels;
} else {
level = (uint8_t) (volume / step);
}
return level;
}
static void _playTone(uint16_t frequency, uint16_t duration, uint8_t volume) { static void _playTone(uint16_t frequency, uint16_t duration, uint8_t volume) {
// https://github.com/mindboards/ev3sources/blob/78ebaf5b6f8fe31cc17aa5dce0f8e4916a4fc072/lms2012/c_sound/source/c_sound.c#L471
uint8_t level = _getVolumeLevel(volume, 13);
ToneCmd cmd; ToneCmd cmd;
cmd.cmd = SOUND_CMD_TONE; cmd.cmd = SOUND_CMD_TONE;
cmd.vol = volume; cmd.lvl = level;
cmd.freq = frequency; cmd.freq = frequency;
cmd.duration = duration; cmd.duration = duration;
// (*SoundInstance.pSound).Busy = TRUE; // (*SoundInstance.pSound).Busy = TRUE;
@ -122,7 +165,8 @@ void playSample(Buffer buf) {
stopUser(); stopUser();
pthread_mutex_lock(&pumpMutex); pthread_mutex_lock(&pumpMutex);
*lmsSoundMMap = 1; // BUSY *lmsSoundMMap = 1; // BUSY
uint8_t cmd[] = {SOUND_CMD_PLAY, (uint8_t)((currVolume / 33) + 1)}; // https://github.com/mindboards/ev3sources/blob/78ebaf5b6f8fe31cc17aa5dce0f8e4916a4fc072/lms2012/c_sound/source/c_sound.c#L605
uint8_t cmd[] = {SOUND_CMD_PLAY, _getVolumeLevel(currVolume, 8)};
writeDev(cmd, 2); writeDev(cmd, 2);
decrRC(currentSample); decrRC(currentSample);
currentSample = buf; currentSample = buf;

10
libs/music/shims.d.ts vendored
View File

@ -13,6 +13,16 @@ declare namespace music {
//% weight=1 shim=music::setVolume //% weight=1 shim=music::setVolume
function setVolume(volume: int32): void; function setVolume(volume: int32): void;
/**
* Return the output volume of the sound synthesizer.
*/
//% weight=96
//% blockId=synth_get_volume block="volume"
//% parts="speaker" blockGap=8
//% help=music/volume
//% weight=1 shim=music::volume
function volume(): int32;
/** /**
* Play a tone through the speaker for some amount of time. * Play a tone through the speaker for some amount of time.
* @param frequency pitch of the tone to play in Hertz (Hz), eg: Note.C * @param frequency pitch of the tone to play in Hertz (Hz), eg: Note.C

View File

@ -5,3 +5,4 @@ music.playTone(1440, 500)
pause(500) pause(500)
music.playTone(2440, 500) music.playTone(2440, 500)
pause(500) pause(500)
music.volume()

View File

@ -22,6 +22,7 @@ namespace _screen_internal {
namespace brick { namespace brick {
const textOffset = 4; const textOffset = 4;
const lineOffset = 2; const lineOffset = 2;
enum ScreenMode { enum ScreenMode {
None, None,
ShowLines, ShowLines,
@ -29,6 +30,14 @@ namespace brick {
Ports, Ports,
Custom Custom
} }
export enum PrintStyle {
//% block="black on white"
BlackOnWhite,
//% block="white on black"
WhiteOnBlack
}
let screenMode = ScreenMode.None; let screenMode = ScreenMode.None;
export let font = image.font8; export let font = image.font8;
@ -48,6 +57,48 @@ namespace brick {
return ((screen.height - textOffset) / lineHeight()) >> 0 return ((screen.height - textOffset) / lineHeight()) >> 0
} }
/**
* Number of columns
*/
//%
export function columnCount(): number {
return ((screen.width - textOffset) / font.charWidth) >> 0
}
/**
* Show text on the screen on a specific line and starting at a column and the selected print style.
* @param text the text to print on the screen, eg: "Hello world"
* @param line the line number to print the text at (starting at 1), eg: 1
* @param column the column number to print the text at (starting at 1), eg: 1
* @param printStyle print style black on white or white on black
*/
//% blockId=screenPrintString block="show string $text|at line $line||column $column|style $printStyle"
//% weight=98 group="Screen" inlineInputMode="inline" blockGap=8
//% expandableArgumentMode="enabled"
//% help=brick/show-string
//% line.min=1 line.max=12
//% column.min=1 column.max=29
export function printString(text: string, line: number, column: number = 1, printStyle: PrintStyle = PrintStyle.BlackOnWhite) {
if (screenMode != ScreenMode.ShowLines) {
screenMode = ScreenMode.ShowLines;
screen.fill(0);
}
line = (line - 1) >> 0; // line indexing starts at 1
column = (column - 1) >> 0; // column indexing starts at 1
const nlines = lineCount();
const nColumn = columnCount();
if (line < 0 || line > nlines) return; // out of screen by line
if (column < 0 || column > nColumn) return; // out of screen by column
const w = font.charWidth;
const h = lineHeight();
const x = textOffset + w * column;
const y = textOffset + h * line;
screen.fillRect(x, y, text.length * font.charWidth, h, (printStyle == PrintStyle.BlackOnWhite ? 0 : 255)); // clear background
screen.print(text, x, y, (printStyle == PrintStyle.BlackOnWhite ? 1 : 2), font);
}
/** /**
* Show text on the screen at a specific line. * Show text on the screen at a specific line.
* @param text the text to print on the screen, eg: "Hello world" * @param text the text to print on the screen, eg: "Hello world"
@ -56,7 +107,8 @@ namespace brick {
//% blockId=screen_print block="show string %text|at line %line" //% blockId=screen_print block="show string %text|at line %line"
//% weight=98 group="Screen" inlineInputMode="inline" blockGap=8 //% weight=98 group="Screen" inlineInputMode="inline" blockGap=8
//% help=brick/show-string //% help=brick/show-string
//% line.min=1 line.max=10 //% line.min=1 line.max=12
//% deprecated=true
export function showString(text: string, line: number) { export function showString(text: string, line: number) {
if (screenMode != ScreenMode.ShowLines) { if (screenMode != ScreenMode.ShowLines) {
screenMode = ScreenMode.ShowLines; screenMode = ScreenMode.ShowLines;
@ -74,19 +126,56 @@ namespace brick {
screen.print(text, textOffset, y, 1, font); screen.print(text, textOffset, y, 1, font);
} }
/**
* Show a number on the screen on a specific line and starting at a column and the selected print style.
* @param value the numeric value
* @param line the line number to print the text at, eg: 1
* @param column the column number to print the text at (starting at 1), eg: 1
* @param printStyle print style black on white or white on black
*/
//% blockId=screenPrintNumber block="show number $value|at line $line||column $column|style $printStyle"
//% weight=97 group="Screen" inlineInputMode="inline" blockGap=8
//% expandableArgumentMode="enabled"
//% help=brick/show-number
//% line.min=1 line.max=12
//% column.min=1 column.max=29
export function printNumber(value: number, line: number, column: number = 1, printStyle: PrintStyle = PrintStyle.BlackOnWhite) {
printString("" + value, line, column, printStyle);
}
/** /**
* Show a number on the screen * Show a number on the screen
* @param value the numeric value * @param value the numeric value
* @param line the line number to print the text at, eg: 1 * @param line the line number to print the text at, eg: 1
*/ */
//% blockId=screenShowNumber block="show number %name|at line %line" //% blockId=screenShowNumber block="show number %name|at line %line"
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8 //% weight=97 group="Screen" inlineInputMode="inline" blockGap=8
//% help=brick/show-number //% help=brick/show-number
//% line.min=1 line.max=10 //% line.min=1 line.max=12
//% deprecated=true
export function showNumber(value: number, line: number) { export function showNumber(value: number, line: number) {
showString("" + value, line); showString("" + value, line);
} }
/**
* Show a name, value pair on the screen on a specific line and starting at a column and the selected print style.
* @param name the value name
* @param value the numeric value
* @param line the line number to print the text at, eg: 1
* @param column the column number to print the text at (starting at 1), eg: 1
* @param printStyle print style black on white or white on black
*/
//% blockId=screenPrintValue block="show value $name|= $value|at line $line||column $column|style $printStyle"
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
//% expandableArgumentMode="enabled"
//% help=brick/show-value
//% line.min=1 line.max=12
//% column.min=1 column.max=29
export function printValue(name: string, value: number, line: number, column: number = 1, printStyle: PrintStyle = PrintStyle.BlackOnWhite) {
value = Math.round(value * 1000) / 1000;
printString((name ? name + ": " : "") + value, line, column, printStyle);
}
/** /**
* Show a name, value pair on the screen * Show a name, value pair on the screen
* @param value the numeric value * @param value the numeric value
@ -95,7 +184,8 @@ namespace brick {
//% blockId=screenShowValue block="show value %name|= %text|at line %line" //% blockId=screenShowValue block="show value %name|= %text|at line %line"
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8 //% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
//% help=brick/show-value //% help=brick/show-value
//% line.min=1 line.max=10 //% line.min=1 line.max=12
//% deprecated=true
export function showValue(name: string, value: number, line: number) { export function showValue(name: string, value: number, line: number) {
value = Math.round(value * 1000) / 1000; value = Math.round(value * 1000) / 1000;
showString((name ? name + ": " : "") + value, line); showString((name ? name + ": " : "") + value, line);
@ -123,11 +213,11 @@ namespace brick {
*/ */
//% blockId=brickShowPorts block="show ports" //% blockId=brickShowPorts block="show ports"
//% help=brick/show-ports blockGap=8 //% help=brick/show-ports blockGap=8
//% weight=10 group="Screen" //% weight=95 group="Screen"
export function showPorts() { export function showPorts() {
if (screenMode == ScreenMode.Ports) return; if (screenMode == ScreenMode.Ports) return;
screenMode = ScreenMode.Ports; screenMode = ScreenMode.Ports;
renderPorts(); renderPorts();
control.runInParallel(function () { control.runInParallel(function () {
while (screenMode == ScreenMode.Ports) { while (screenMode == ScreenMode.Ports) {
@ -146,11 +236,14 @@ namespace brick {
for (let i = 0; i < 4; ++i) { for (let i = 0; i < 4; ++i) {
const x = i * col + 2; const x = i * col + 2;
screen.print("ABCD"[i], x, 1 * lineHeight8, 1, image.font8) if (screenMode != ScreenMode.Ports) return;
screen.print((i + 1).toString(), x, h - lineHeight8, 1, image.font8) screen.print("ABCD"[i], x, 1 * lineHeight8, 1, image.font8);
screen.print((i + 1).toString(), x, h - lineHeight8, 1, image.font8);
} }
if (screenMode != ScreenMode.Ports) return;
screen.drawLine(0, 5 * lineHeight8, screen.width, 5 * lineHeight8, 1); screen.drawLine(0, 5 * lineHeight8, screen.width, 5 * lineHeight8, 1);
screen.drawLine(0, h - 5 * lineHeight8, screen.width, h - 5 * lineHeight8, 1) screen.drawLine(0, h - 5 * lineHeight8, screen.width, h - 5 * lineHeight8, 1);
function scale(x: number) { function scale(x: number) {
if (Math.abs(x) >= 5000) { if (Math.abs(x) >= 5000) {
@ -167,8 +260,9 @@ namespace brick {
const data = datas[i]; const data = datas[i];
const x = i * col + 2; const x = i * col + 2;
if (!data.actualSpeed && !data.count) continue; if (!data.actualSpeed && !data.count) continue;
screen.print(`${scale(data.actualSpeed)}%`, x, 3 * lineHeight8, 1, image.font8) if (screenMode != ScreenMode.Ports) return;
screen.print(`${scale(data.count)}>`, x, 4 * lineHeight8, 1, image.font8) screen.print(`${scale(data.actualSpeed)}%`, x, 3 * lineHeight8, 1, image.font8);
screen.print(`${scale(data.count)}>`, x, 4 * lineHeight8, 1, image.font8);
} }
// sensors // sensors
@ -177,16 +271,16 @@ namespace brick {
const si = sis[i]; const si = sis[i];
const x = (si.port() - 1) * col + 2; const x = (si.port() - 1) * col + 2;
const inf = si._info(); const inf = si._info();
if (inf) if (screenMode != ScreenMode.Ports) return;
screen.print(inf, x, h - 2 * lineHeight8, 1, inf.length > 4 ? image.font5 : image.font8); if (inf) screen.print(inf, x, h - 2 * lineHeight8, 1, inf.length > 4 ? image.font5 : image.font8);
} }
} }
export function showBoot() { export function showBoot() {
// pulse green, play startup sound, turn off light // pulse green, play startup sound, turn off light
brick.setStatusLight(StatusLight.GreenPulse); brick.setStatusLight(StatusLight.GreenPulse);
// We pause for 100ms to give time to read sensor values, so they work in on_start block // We pause to give time to read sensor values, so they work in on_start block
pause(400) pause(400); // It turns out that this time is not enough for the simulator to display the LED change
// and we're ready // and we're ready
brick.setStatusLight(StatusLight.Off); brick.setStatusLight(StatusLight.Off);
// always show port by default if no UI is set // always show port by default if no UI is set
@ -210,11 +304,33 @@ namespace brick {
return image; return image;
} }
/**
* Clear on the screen at a specific line.
* @param line the line number to clear at (starting at 1), eg: 1
*/
//% blockId=clearLine block="clear line $line"
//% weight=94 group="Screen" inlineInputMode="inline" blockGap=8
//% line.min=1 line.max=12
export function clearLine(line: number) {
if (screenMode != ScreenMode.ShowLines) {
screenMode = ScreenMode.ShowLines;
screen.fill(0);
}
line = (line - 1) >> 0; // line indexing starts at 1
const nlines = lineCount();
if (line < 0 || line > nlines) return; // out of screen by line
const h = lineHeight();
const y = textOffset + h * line;
screen.fillRect(0, y, screen.width, h, 0); // clear background
}
/** /**
* Clear the screen * Clear the screen
*/ */
//% blockId=screen_clear_screen block="clear screen" //% blockId=screen_clear_screen block="clear screen"
//% weight=90 group="Screen" //% weight=93 group="Screen"
//% help=brick/clear-screen weight=1 //% help=brick/clear-screen weight=1
export function clearScreen() { export function clearScreen() {
screen.fill(0) screen.fill(0)

View File

@ -1,6 +1,6 @@
{ {
"name": "pxt-ev3", "name": "pxt-ev3",
"version": "1.4.21", "version": "1.4.32",
"description": "LEGO MINDSTORMS EV3 for Microsoft MakeCode", "description": "LEGO MINDSTORMS EV3 for Microsoft MakeCode",
"private": false, "private": false,
"keywords": [ "keywords": [
@ -32,21 +32,20 @@
"docs/*/*/*.md" "docs/*/*/*.md"
], ],
"devDependencies": { "devDependencies": {
"react": "16.8.3",
"webfonts-generator": "^0.4.0",
"@types/jquery": "3.2.16",
"@types/react": "16.0.25",
"@types/react-dom": "16.0.3",
"@types/web-bluetooth": "0.0.4",
"@types/bluebird": "^2.0.33",
"@types/marked": "^0.3.0", "@types/marked": "^0.3.0",
"@types/node": "^9.3.0", "@types/node": "^9.3.0",
"semantic-ui-less": "2.2.14", "@types/react": "16.8.25",
"typescript": "^3.7.5" "@types/react-dom": "16.0.3",
"@types/web-bluetooth": "0.0.4",
"@vusion/webfonts-generator": "^0.7.1",
"react": "16.8.3",
"react-dom": "16.11.0",
"semantic-ui-less": "2.4.1",
"typescript": "^4.2.3"
}, },
"dependencies": { "dependencies": {
"pxt-common-packages": "8.1.3", "pxt-common-packages": "9.2.7",
"pxt-core": "6.2.8" "pxt-core": "7.2.27"
}, },
"scripts": { "scripts": {
"test": "node node_modules/pxt-core/built/pxt.js travis" "test": "node node_modules/pxt-core/built/pxt.js travis"

View File

@ -77,8 +77,9 @@
"pauseUntilBlock": { "pauseUntilBlock": {
"category": "loops" "category": "loops"
}, },
"bannedCategories": [ "breakBlock": true,
] "continueBlock": true,
"bannedCategories": []
}, },
"compileService": { "compileService": {
"buildEngine": "dockermake", "buildEngine": "dockermake",
@ -106,20 +107,21 @@
"driveDisplayName": "EV3", "driveDisplayName": "EV3",
"boardName": "LEGO® MINDSTORMS® Education EV3", "boardName": "LEGO® MINDSTORMS® Education EV3",
"copyrightText": "LEGO, the LEGO logo, MINDSTORMS and the MINDSTORMS EV3 logo are trademarks and/ or copyrights of the LEGO Group. ©2018 The LEGO Group. All rights reserved.", "copyrightText": "LEGO, the LEGO logo, MINDSTORMS and the MINDSTORMS EV3 logo are trademarks and/ or copyrights of the LEGO Group. ©2018 The LEGO Group. All rights reserved.",
"crowdinProject": "kindscript", "crowdinProject": "makecode",
"selectLanguage": true, "selectLanguage": true,
"blocksCollapsing": true,
"highContrast": true,
"greenScreen": true, "greenScreen": true,
"availableLocales": [ "availableLocales": [
"en", "en",
"de", "de",
"ja", "ja",
"ru", "ru",
"zh-CN" "zh-CN",
"fr"
], ],
"highContrast": true,
"lightToc": true, "lightToc": true,
"docMenu": [ "docMenu": [{
{
"name": "Support", "name": "Support",
"path": "https://forum.makecode.com/" "path": "https://forum.makecode.com/"
}, },
@ -158,7 +160,10 @@
"extendEditor": true, "extendEditor": true,
"extendFieldEditors": true, "extendFieldEditors": true,
"scriptManager": true, "scriptManager": true,
"debugger": true,
"errorList": true,
"importExtensionFiles": true, "importExtensionFiles": true,
"addNewTypeScriptFile": true,
"experiments": [ "experiments": [
"python", "python",
"alwaysGithubItemBlocks" "alwaysGithubItemBlocks"

View File

@ -1,7 +1,6 @@
CACHE MANIFEST CACHE MANIFEST
CACHE: CACHE:
/cdn/bluebird.min.js
/cdn/pxtsim.js /cdn/pxtsim.js
/sim/common-sim.js /sim/common-sim.js
/sim/sim.js /sim/sim.js

View File

@ -23,7 +23,6 @@ body {
transition: none !important; transition: none !important;
} }
</style> </style>
<script src="/cdn/bluebird.min.js"></script>
<script src="/cdn/pxtsim.js"></script> <script src="/cdn/pxtsim.js"></script>
<script src="/sim/common-sim.js"></script> <script src="/sim/common-sim.js"></script>
<script src="/sim/sim.js"></script> <script src="/sim/sim.js"></script>

View File

@ -21,7 +21,7 @@ namespace pxsim {
export class ColorSensorNode extends UartSensorNode { export class ColorSensorNode extends UartSensorNode {
id = NodeType.ColorSensor; id = NodeType.ColorSensor;
private color: number = 50; private color: number = 0;
constructor(port: number) { constructor(port: number) {
super(port); super(port);
@ -40,5 +40,13 @@ namespace pxsim {
getValue() { getValue() {
return this.color; return this.color;
} }
setMode(mode: number) {
this.mode = mode;
if (this.mode == ColorSensorMode.RefRaw) this.color = 512;
else this.color = 50;
this.changed = true;
this.modeChanged = true;
}
} }
} }

View File

@ -37,7 +37,7 @@ namespace pxsim {
return Math.round(this.angle); return Math.round(this.angle);
} }
// returns the slave motor if any // returns the secondary motor if any
getSynchedMotor() { getSynchedMotor() {
return this._synchedMotor; return this._synchedMotor;
} }

View File

@ -7,6 +7,14 @@ namespace pxsim.music {
export function stopAllSounds() { export function stopAllSounds() {
SoundMethods.stop() SoundMethods.stop()
} }
pxsim.music.setVolume = (volume: number): void => {
pxsim.getAudioState().volume = volume;
};
export function volume() {
return pxsim.getAudioState().volume;
}
} }
namespace pxsim.SoundMethods { namespace pxsim.SoundMethods {

View File

@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "target": "es2017",
"noImplicitAny": true, "noImplicitAny": true,
"noImplicitReturns": true, "noImplicitReturns": true,
"declaration": true, "declaration": true,
@ -8,8 +8,8 @@
"rootDir": ".", "rootDir": ".",
"newLine": "LF", "newLine": "LF",
"sourceMap": false, "sourceMap": false,
"lib": ["dom", "dom.iterable", "scripthost", "es6"], "lib": ["dom", "dom.iterable", "scripthost", "es2017"],
"types": ["bluebird"], "types": [],
"typeRoots": ["../node_modules/@types"] "typeRoots": ["../node_modules/@types"]
} }
} }

View File

@ -241,6 +241,8 @@ namespace pxsim.visuals {
view = new ColorGridControl(this.element, this.defs, state, port); view = new ColorGridControl(this.element, this.defs, state, port);
} else if (state.getMode() == ColorSensorMode.Reflected) { } else if (state.getMode() == ColorSensorMode.Reflected) {
view = new ColorWheelControl(this.element, this.defs, state, port); view = new ColorWheelControl(this.element, this.defs, state, port);
} else if (state.getMode() == ColorSensorMode.RefRaw) {
view = new ColorWheelControl(this.element, this.defs, state, port);
} else if (state.getMode() == ColorSensorMode.Ambient) { } else if (state.getMode() == ColorSensorMode.Ambient) {
view = new ColorWheelControl(this.element, this.defs, state, port); view = new ColorWheelControl(this.element, this.defs, state, port);
} }
@ -381,7 +383,7 @@ namespace pxsim.visuals {
this.screenCanvas = document.createElement("canvas"); this.screenCanvas = document.createElement("canvas");
this.screenCanvas.id = "board-screen-canvas"; this.screenCanvas.id = "board-screen-canvas";
this.screenCanvas.style.userSelect = "none"; this.screenCanvas.style.userSelect = "none";
this.screenCanvas.style.msUserSelect = "none"; (this.screenCanvas.style as any).msUserSelect = "none";
this.screenCanvas.style.webkitUserSelect = "none"; this.screenCanvas.style.webkitUserSelect = "none";
(this.screenCanvas.style as any).MozUserSelect = "none"; (this.screenCanvas.style as any).MozUserSelect = "none";
this.screenCanvas.style.position = "absolute"; this.screenCanvas.style.position = "absolute";

View File

@ -5,8 +5,8 @@ namespace pxsim.visuals {
export class ColorGridControl extends ControlView<ColorSensorNode> { export class ColorGridControl extends ControlView<ColorSensorNode> {
private group: SVGGElement; private group: SVGGElement;
private static colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'grey', 'white']; private static colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'brown', 'white', 'none'];
private static colorValue = [5, 4, 2, 3, 1, 7, 6]; private static colorValue = [5, 4, 2, 3, 1, 7, 6, 0];
private colorDivs: Element[] = []; private colorDivs: Element[] = [];
@ -15,7 +15,7 @@ namespace pxsim.visuals {
this.group.setAttribute("transform", `translate(2, 2.5) scale(0.6)`) this.group.setAttribute("transform", `translate(2, 2.5) scale(0.6)`)
const colors = ['#f12a21', '#ffd01b', '#006db3', '#00934b', '#000', '#6c2d00']; const colors = ['#f12a21', '#ffd01b', '#006db3', '#00934b', '#000', '#6c2d00'];
const colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'grey']; const colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'brown'];
let cy = -4; let cy = -4;
for (let c = 0; c < colorIds.length; c++) { for (let c = 0; c < colorIds.length; c++) {
@ -33,12 +33,19 @@ namespace pxsim.visuals {
} }
const whiteCircleWrapper = pxsim.svg.child(this.group, "g", { 'id': 'white-cirlce-wrapper' }); const whiteCircleWrapper = pxsim.svg.child(this.group, "g", { 'id': 'white-cirlce-wrapper' });
const circle = pxsim.svg.child(whiteCircleWrapper, "circle", { 'class': 'sim-color-grid-circle sim-color-grid-white', 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: #fff` }); const noneCircleWrapper = pxsim.svg.child(this.group, "g", { 'id': 'nothing-circle-wrapper' });
this.colorDivs.push(circle); const whiteCircle = pxsim.svg.child(whiteCircleWrapper, "circle", { 'class': 'sim-color-grid-circle sim-color-grid-white', 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: #fff` });
pxsim.svg.child(whiteCircleWrapper, "circle", { 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: none;stroke: #94989b;stroke-width: 0.1px` }); const noneCircle = pxsim.svg.child(noneCircleWrapper, "circle", { 'class': 'sim-color-grid-circle sim-color-grid-none', 'cx': 7.5, 'cy': '16', 'r': '2', 'style': `fill: #fff; fill-opacity: 0%;` });
this.colorDivs.push(whiteCircle);
this.colorDivs.push(noneCircle);
pxsim.svg.child(whiteCircleWrapper, "circle", { 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: none; stroke: #94989b; stroke-width: 0.1px` });
pxsim.svg.child(noneCircleWrapper, "circle", { 'cx': 7.5, 'cy': '16', 'r': '2', 'style': `fill: none; stroke: #94989b; stroke-width: 0.1px` });
pointerEvents.down.forEach(evid => whiteCircleWrapper.addEventListener(evid, ev => { pointerEvents.down.forEach(evid => whiteCircleWrapper.addEventListener(evid, ev => {
this.setColor(6); this.setColor(6);
})); }));
pointerEvents.down.forEach(evid => noneCircleWrapper.addEventListener(evid, ev => {
this.setColor(0);
}));
return this.group; return this.group;
} }

View File

@ -26,8 +26,12 @@ namespace pxsim.visuals {
return 131; return 131;
} }
private getMaxValue() { private getMaxValue(state: ColorSensorMode) {
return 100; return (state == ColorSensorMode.RefRaw ? 1023 : 100);
}
private mapValue(x: number, inMin: number, inMax: number, outMin: number, outMax: number) {
return (x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
} }
updateState() { updateState() {
@ -35,10 +39,12 @@ namespace pxsim.visuals {
return; return;
} }
const node = this.state; const node = this.state;
const percentage = node.getValue(); const value = node.getValue();
const inversePercentage = this.getMaxValue() - percentage; let inverseValue = this.getMaxValue(node.getMode()) - value;
svg.setGradientValue(this.colorGradient, inversePercentage + "%"); if (node.getMode() == ColorSensorMode.RefRaw) inverseValue = this.mapValue(inverseValue, 0, 1023, 0, 100);
this.reporter.textContent = `${parseFloat((percentage).toString()).toFixed(0)}%`; svg.setGradientValue(this.colorGradient, inverseValue + "%");
this.reporter.textContent = `${parseFloat((value).toString()).toFixed(0)}`;
if (node.getMode() != ColorSensorMode.RefRaw) this.reporter.textContent += `%`;
} }
updateColorLevel(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) { updateColorLevel(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
@ -47,7 +53,7 @@ namespace pxsim.visuals {
const height = bBox.height; const height = bBox.height;
let t = Math.max(0, Math.min(1, (height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / height)); let t = Math.max(0, Math.min(1, (height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / height));
const state = this.state; const state = this.state;
state.setColor(t * this.getMaxValue()); state.setColor(t * this.getMaxValue(state.getMode()));
} }
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) { getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {

View File

@ -29,6 +29,7 @@ namespace pxsim.visuals {
switch (mode) { switch (mode) {
case ColorSensorMode.Colors: this.updateSensorLightVisual('#0062DD'); return; // blue case ColorSensorMode.Colors: this.updateSensorLightVisual('#0062DD'); return; // blue
case ColorSensorMode.Reflected: this.updateSensorLightVisual('#F86262'); return; // red case ColorSensorMode.Reflected: this.updateSensorLightVisual('#F86262'); return; // red
case ColorSensorMode.RefRaw: this.updateSensorLightVisual('#F86262'); return; // red
case ColorSensorMode.Ambient: this.updateSensorLightVisual('#67C3E2'); return; // light blue case ColorSensorMode.Ambient: this.updateSensorLightVisual('#67C3E2'); return; // light blue
} }
this.updateSensorLightVisual('#ffffff'); this.updateSensorLightVisual('#ffffff');

View File

@ -92,6 +92,11 @@
color: white; color: white;
} }
/* active toggle */
.ui.item.editor-menuitem .active~.item.toggle {
background: @editorToggleColor!important;
}
.menubar .ui.item.editor-menuitem .item.toggle { .menubar .ui.item.editor-menuitem .item.toggle {
height: 45px; height: 45px;
} }

View File

@ -17,6 +17,8 @@
specify theme name below specify theme name below
*/ */
@placeholder: 'default';
/* Global */ /* Global */
@site : 'pxt'; @site : 'pxt';
@reset : 'default'; @reset : 'default';
@ -87,7 +89,7 @@
Import Theme Import Theme
*******************************/ *******************************/
@import "theme.less"; @import (multiple) "theme.less";
@fontPath : 'fonts'; @fontPath : 'fonts';