Compare commits

..

2 Commits

Author SHA1 Message Date
Peli de Halleux
8fd0bf92fa move electron to v1.1.22 2019-10-07 14:23:34 -07:00
Peli de Halleux
a33bff0520 offline template 2019-10-07 14:22:05 -07:00
68 changed files with 1574 additions and 1651 deletions

View File

@@ -1,12 +0,0 @@
name: Compress images
on: pull_request
jobs:
build:
name: calibreapp/image-actions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: calibreapp/image-actions
uses: calibreapp/image-actions@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
.gitignore vendored
View File

@@ -17,7 +17,6 @@ clients/**/bin/**
clients/**/obj/** clients/**/obj/**
clients/electron/projects clients/electron/projects
libs/**/_locales/** libs/**/_locales/**
package-lock.json
videos/** videos/**

14
cmds/cmds.ts Normal file
View File

@@ -0,0 +1,14 @@
/// <reference path="../node_modules/pxt-core/built/pxtlib.d.ts" />
import * as fs from 'fs';
const deploy = require("./editor/deploy")
export function deployCoreAsync(resp: pxtc.CompileResult) {
return deploy.deployCoreAsync(resp, process.env["PXT_SERIAL"] ? false : true)
.then(() => {
fs.writeFileSync("built/full-" + pxtc.BINARY_UF2, resp.outfiles[pxtc.BINARY_UF2], {
encoding: "base64"
})
})
}

14
cmds/tsconfig.json Normal file
View File

@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "es5",
"noImplicitAny": true,
"noImplicitReturns": true,
"declaration": true,
"outDir": "../built",
"module": "commonjs",
"rootDir": ".",
"newLine": "LF",
"sourceMap": false,
"types": ["node"]
}
}

View File

@@ -6,13 +6,13 @@
<a class="item" href="https://makecode.com/privacy" target="_blank" rel="noopener">Privacy &amp; Cookies</a> <a class="item" href="https://makecode.com/privacy" target="_blank" rel="noopener">Privacy &amp; Cookies</a>
<a class="item" href="https://makecode.com/termsofuse" target="_blank" rel="noopener"> Terms Of Use</a> <a class="item" href="https://makecode.com/termsofuse" target="_blank" rel="noopener"> Terms Of Use</a>
<a class="item" href="https://makecode.com/trademarks" target="_blank" rel="noopener">Trademarks</a> <a class="item" href="https://makecode.com/trademarks" target="_blank" rel="noopener">Trademarks</a>
<div class="item">© 2018 Microsoft</div> <div class="item">©2019 Microsoft</div>
</div> </div>
<div class="ui container horizontal small divided link list"> <div class="ui container horizontal small divided link list">
<a class="ui centered item" href="https://makecode.com/" title="Microsoft MakeCode" target="_blank" rel="noopener">Powered by Microsoft MakeCode</a> <a class="ui centered item" href="https://makecode.com/" title="Microsoft MakeCode" target="_blank" rel="noopener">Powered by Microsoft MakeCode</a>
</div> </div>
<div class="ui centered container small list"> <div class="ui centered container small list">
<p class="item">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.</p> <p class="item">@copyrightText@</p>
</div> </div>
</div> </div>
</footer> </footer>

View File

@@ -35,13 +35,6 @@ On the home page, scroll down to the **FLL / City Shaper** section for specific
Yes. Yes.
### Can I run the program again on the brick?
![EV3 Brick with Try in BrkProg_Save Folder in File Manager](/static/getting-started/try-in-file-manager.png)
Use the Brick Buttons and navigate to the File Manager tab. Open the **BrkProg_SAVE** folder,
select your program and click the center button to run it again.
### Does it work without internet? ### Does it work without internet?
No, the editor is cached in your browser cache. However, you can also download the [offline app](/offline-app) in case you need to install it on a computer. No, the editor is cached in your browser cache. However, you can also download the [offline app](/offline-app) in case you need to install it on a computer.
@@ -105,12 +98,6 @@ The official answer is currently no. That being said, we have **Experimental sup
https://youtu.be/VIq8-6Egtqs https://youtu.be/VIq8-6Egtqs
## Are there YouTube videos on MakeCode for EV3?
The MakeCode has a [FLL / City Shaper YouTube Channel](https://www.youtube.com/watch?v=IqL0Pyeu5Ng&list=PLMMBk9hE-SeqkOObethhlZtBTEK6FYx3n) with useful videos.
https://youtu.be/-AirqwC9DL4
### Why can't I delete my program (*.uf2) files from the Brick? ### Why can't I delete my program (*.uf2) files from the Brick?
There's a bug in the firmware which prevents you from deleting the programs (``*.uf2`` files) from your EV3 Brick. There isn't a firmware update to fix this yet. There's a bug in the firmware which prevents you from deleting the programs (``*.uf2`` files) from your EV3 Brick. There isn't a firmware update to fix this yet.

View File

@@ -73,12 +73,6 @@ Verify that the program you just created shows eyes on the Brick Display, and th
**Well done!** **Well done!**
## Run it Again
![EV3 Brick with Try in BrkProg_Save Folder in File Manager](/static/getting-started/try-in-file-manager.png)
Use the Brick Buttons and navigate to the File Manager tab. Open the **BrkProg_SAVE** folder, select **Try** and click the center button to run it again.
## Connect a Large Motor @unplugged ## Connect a Large Motor @unplugged
Now you will learn to control the Large Motor. Now you will learn to control the Large Motor.

View File

@@ -54,12 +54,6 @@ Verify that the program you just created shows eyes on the Brick Display, and th
**Well done!** **Well done!**
## Run it Again
![EV3 Brick with Try in BrkProg_Save Folder in File Manager](/static/getting-started/try-in-file-manager.png)
Use the Brick Buttons and navigate to the File Manager tab. Open the **BrkProg_SAVE** folder, select **Try** and click the center button to run it again.
## Connect a Large Motor ## Connect a Large Motor
Now you will learn to control the Large Motor. Now you will learn to control the Large Motor.

View File

@@ -1,3 +1,3 @@
{ {
"appref": "v1.2.26" "appref": "v1.2.22"
} }

View File

@@ -3,11 +3,20 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>LEGO® MINDSTORMS® Education EV3 Offline App</title> <title>@name@ Offline App</title>
<meta name="Description" content="A MakeCode for LEGO® MINDSTORMS® Education EV3 offline app" /> <meta name="Description" content="A MakeCode for @name@ offline app" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- @include indexhead.html --> <link rel="stylesheet" data-rtl="/blb/rtlsemantic.css" href="/doccdn/semantic.css" />
<link rel="stylesheet" href="/docfiles/style.css" />
<link rel="stylesheet" href="/docfiles/target.css" />
<script src="/doccdn/jquery.js" type="text/javascript"></script>
<script src="/doccdn/semantic.js" type="text/javascript"></script>
<script src="/docfiles/target.js" type="text/javascript"></script>
<style>
@targetstyle@
</style>
<style> <style>
p.item { p.item {
color: rgba(0, 0, 0, 0.4); color: rgba(0, 0, 0, 0.4);
@@ -55,6 +64,10 @@
background-color: rgb(250, 250, 250); background-color: rgb(250, 250, 250);
} }
#legal-segment {
background:white;
}
@media only screen and (max-width: 800px) { @media only screen and (max-width: 800px) {
.grid .column .image { .grid .column .image {
display: none; display: none;
@@ -368,34 +381,61 @@
</style> </style>
<script> <script>
$(document).ready(function () { var electronLatestVersion = "";
tickEvent = function (id, data) { function tickEvent(id, data) {
if (!pxt.aiTrackEvent) return; if (!pxt.aiTrackEvent) return;
if (!data) pxt.aiTrackEvent(id); if (!data) pxt.aiTrackEvent(id);
else { else {
var props = {}; var props = {};
var measures = {}; var measures = {};
for (var k in data) for (var k in data)
if (typeof data[k] == "string") props[k] = data[k]; if (typeof data[k] == "string") props[k] = data[k];
else measures[k] = data[k]; else measures[k] = data[k];
pxt.aiTrackEvent(id, props, measures); pxt.aiTrackEvent(id, props, measures);
}
} }
}); }
function agreeCheckboxChanged() { function agreeCheckboxChanged() {
var downloadSegment = document.getElementById("download-segment"); showDownloads();
downloadSegment.classList.toggle("hidden"); }
function showAgree() {
$("#agree-segment").removeClass("hidden");
$("#read-segment").removeClass("hidden");
$("#legal-segment").removeClass("hidden");
}
function showNoDownloads() {
$("#no-download-segment").removeClass("hidden");
$("#read-segment").addClass("hidden");
$("#legal-segment").addClass("hidden");
}
function showDownloads() {
$("#download-win64").attr("href", "https://makecode.com/api/release/@targetid@/" + electronLatestVersion + "/win64");
$("#download-mac64").attr("href", "https://makecode.com/api/release/@targetid@/" + electronLatestVersion + "/mac64");
$("#download-segment").removeClass("hidden");
} }
function downloadWin64() { function downloadWin64() {
// TODO: Keep this link up-to-date with the desired release version tickEvent("offlineapp.download", { "target": "@targetid@", "platform": "win64" });
window.open("https://makecode.com/api/release/ev3/v1.2.26/win64");
tickEvent("offlineapp.download", { "target": "ev3", "platform": "win64" });
} }
function downloadMac64() { function downloadMac64() {
// TODO: Keep this link up-to-date with the desired release version tickEvent("offlineapp.download", { "target": "@targetid@", "platform": "mac64" });
window.open("https://makecode.com/api/release/ev3/v1.2.26/mac64");
tickEvent("offlineapp.download", { "target": "ev3", "platform": "mac64" });
} }
$(function () {
$.getJSON("https://makecode.com/api/config/@targetid@/targetconfig")
.then(function (data) {
if (data && data.electronManifest && data.electronManifest.latest) {
electronLatestVersion = data.electronManifest.latest;
showAgree();
} else {
showNoDownloads();
}
})
.catch(function () {
showNoDownloads();
})
});
</script> </script>
</head> </head>
@@ -406,35 +446,39 @@
<div class="ui grid topbar"> <div class="ui grid topbar">
<div class="three wide column"> <div class="three wide column">
<img class="ui small image left" src="/static//lego_education_logo_white.png" /> <img class="ui small image left" src="@cardLogo@" />
</div> </div>
<div class="ten wide column"> <div class="ten wide column">
<h1 class="ui inverted welcomeheader">MakeCode Offline App</h1> <h1 class="ui inverted welcomeheader">@name@ Offline App</h1>
</div> </div>
<div class="three wide column"> <div class="three wide column">
<img class="ui small image right" src="/static//Microsoft-logo_rgb_c-white.png" /> <img class="ui small image right" src="/static/Microsoft-logo_rgb_c-white.png" />
</div> </div>
</div> </div>
<div class="ui compact segments terms-container"> <div id="segments" class="ui compact segments terms-container">
<div class="ui secondary center aligned segment"> <div id="read-segment" class="ui secondary center aligned segment hidden">
Please read and accept the following terms to download the app. Please read and accept the following terms to download the app.
</div> </div>
<div class="ui left aligned segment terms"> <div id="legal-segment" class="ui left aligned segment terms hidden">
<div id="loader" class="ui active loader"></div>
<div class="c17"> <div class="c17">
<p class="c11"> <p class="c11">
<span class="c4 c1">MICROSOFT PRE-RELEASE SOFTWARE LICENSE TERMS</span> <span class="c4 c1">MICROSOFT PRE-RELEASE SOFTWARE LICENSE TERMS</span>
</p> </p>
<p class="c11"> <p class="c11">
<span class="c4 c1">MICROSOFT MAKECODE FOR LEGO MINDSTORMS EDUCATION EV3</span> <span class="c4 c1">MICROSOFT MAKECODE SOFTWARE FOR @name@</span>
</p> </p>
<p class="c7"> <p class="c7">
<span class="c4 c1"></span> <span class="c4 c1"></span>
</p> </p>
<p class="c11"> <p class="c11">
<span class="c3 c1">These license terms are an agreement between Microsoft Corporation (or based on where you live, one <span class="c3 c1">These license terms are an agreement between Microsoft Corporation (or based
of its affiliates) and you. They apply to the software named above. The terms also apply to any on where you live, one
Microsoft services or updates for the software, except to the extent those have additional terms.</span> of its affiliates) and you. They apply to the software named above. The terms also apply to
any
Microsoft services or updates for the software, except to the extent those have additional
terms.</span>
</p> </p>
<p class="c7"> <p class="c7">
<span class="c3 c1"></span> <span class="c3 c1"></span>
@@ -446,27 +490,35 @@
<span class="c5 c1">1.</span> <span class="c5 c1">1.</span>
<span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="c5 c1">INSTALLATION AND USE RIGHTS. </span> <span class="c5 c1">INSTALLATION AND USE RIGHTS. </span>
<span class="c3 c1">You may install and use any number of copies of the software to evaluate it as you develop and test <span class="c3 c1">You may install and use any number of copies of the software to evaluate it
your software applications for use with Lego Mindstorms Education EV3 hardware.</span> as you develop and test
your software applications for use with @name@ hardware.</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c5 c1">2.</span> <span class="c5 c1">2.</span>
<span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="c5 c1">PRE-RELEASE SOFTWARE. </span> <span class="c5 c1">PRE-RELEASE SOFTWARE. </span>
<span class="c3 c1">The software is a pre-release version. It may not work the way a final version of the software will. <span class="c3 c1">The software is a pre-release version. It may not work the way a final
Microsoft may change it for the final, commercial version. We also may not release a commercial version of the software will.
version. Microsoft is not obligated to provide maintenance, technical support or updates to you Microsoft may change it for the final, commercial version. We also may not release a
commercial
version. Microsoft is not obligated to provide maintenance, technical support or updates to
you
for the software.</span> for the software.</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c5 c1">3.</span> <span class="c5 c1">3.</span>
<span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="c5 c1">ASSOCIATED ONLINE SERVICES.</span> <span class="c5 c1">ASSOCIATED ONLINE SERVICES.</span>
<span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Some features of the software provide access <span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Some features of the software
to, or rely on, online services to provide you information about updates to the software or extensions, provide access
or to enable you to retrieve content, collaborate with others, or otherwise supplement your development to, or rely on, online services to provide you information about updates to the software or
experience. As used throughout these license terms, the term <q>software</q> includes these online extensions,
services and features. By using these online services and features you consent to the to the or to enable you to retrieve content, collaborate with others, or otherwise supplement your
development
experience. As used throughout these license terms, the term <q>software</q> includes these
online
services and features. By using these online services and features you consent to the to the
transmission of information as described in Section 5, DATA. transmission of information as described in Section 5, DATA.
</span> </span>
</p> </p>
@@ -474,9 +526,11 @@
<span class="c5 c1">4.</span> <span class="c5 c1">4.</span>
<span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="c5 c1">LICENSES FOR OTHER COMPONENTS.</span> <span class="c5 c1">LICENSES FOR OTHER COMPONENTS.</span>
<span class="c3 c1">&nbsp;The software may include third party components with separate legal notices or governed by <span class="c3 c1">&nbsp;The software may include third party components with separate legal
notices or governed by
other agreements, as described in the ThirdPartyNotices file accompanying the software. Even other agreements, as described in the ThirdPartyNotices file accompanying the software. Even
if such components are governed by other agreements, the disclaimers and the limitations on and if such components are governed by other agreements, the disclaimers and the limitations on
and
exclusions of damages below also apply.</span> exclusions of damages below also apply.</span>
</p> </p>
<p class="c2"> <p class="c2">
@@ -488,26 +542,35 @@
<span class="c5 c1">a.</span> <span class="c5 c1">a.</span>
<span class="c1">&nbsp; &nbsp;</span> <span class="c1">&nbsp; &nbsp;</span>
<span class="c1 c5">Data Collection. </span> <span class="c1 c5">Data Collection. </span>
<span class="c1">The software may collect information about you and your use of the software, and send that to Microsoft. <span class="c1">The software may collect information about you and your use of the software,
Microsoft may use this information to provide services and improve our products and services. and send that to Microsoft.
You may opt out of many of these scenarios, but not all, as described in the product documentation. Microsoft may use this information to provide services and improve our products and
In using the software, you must comply with applicable law. You can learn more about data collection services.
You may opt out of many of these scenarios, but not all, as described in the product
documentation.
In using the software, you must comply with applicable law. You can learn more about data
collection
and use in the help documentation and the privacy statement at </span> and use in the help documentation and the privacy statement at </span>
<span class="c14 c1"> <span class="c14 c1">
<a class="c9" href="http://go.microsoft.com/fwlink/?LinkId=398505">http://go.microsoft.com/fwlink/?LinkId=398505</a> <a class="c9"
href="http://go.microsoft.com/fwlink/?LinkId=398505">http://go.microsoft.com/fwlink/?LinkId=398505</a>
</span> </span>
<span class="c1">.</span> <span class="c1">.</span>
<span class="c3 c1">&nbsp;Your use of the software operates as your consent to these practices.</span> <span class="c3 c1">&nbsp;Your use of the software operates as your consent to these
practices.</span>
</p> </p>
<p class="c8"> <p class="c8">
<span class="c5 c1">b.</span> <span class="c5 c1">b.</span>
<span class="c1">&nbsp; &nbsp;</span> <span class="c1">&nbsp; &nbsp;</span>
<span class="c5 c1">Processing of Personal Data. </span> <span class="c5 c1">Processing of Personal Data. </span>
<span class="c1">To the extent Microsoft is a processor or subprocessor of personal data in connection with the software, <span class="c1">To the extent Microsoft is a processor or subprocessor of personal data in
Microsoft makes the commitments in the European Union General Data Protection Regulation Terms connection with the software,
Microsoft makes the commitments in the European Union General Data Protection Regulation
Terms
of the Online Services Terms to all customers effective May 25, 2018, at </span> of the Online Services Terms to all customers effective May 25, 2018, at </span>
<span class="c1 c14"> <span class="c1 c14">
<a class="c9" href="http://go.microsoft.com/?linkid=9840733">http://go.microsoft.com/?linkid=9840733</a> <a class="c9"
href="http://go.microsoft.com/?linkid=9840733">http://go.microsoft.com/?linkid=9840733</a>
</span> </span>
<span class="c3 c1">.</span> <span class="c3 c1">.</span>
</p> </p>
@@ -515,48 +578,62 @@
<span class="c5 c1">6.</span> <span class="c5 c1">6.</span>
<span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="c5 c1">FEEDBACK. </span> <span class="c5 c1">FEEDBACK. </span>
<span class="c3 c1">If you give feedback about the software to Microsoft, you give to Microsoft, without charge, the <span class="c3 c1">If you give feedback about the software to Microsoft, you give to Microsoft,
without charge, the
right to use, share and commercialize your feedback in any way and for any purpose. You will right to use, share and commercialize your feedback in any way and for any purpose. You will
not give feedback that is subject to a license that requires Microsoft to license its software not give feedback that is subject to a license that requires Microsoft to license its
or documentation to third parties because we include your feedback in them. These rights survive software
or documentation to third parties because we include your feedback in them. These rights
survive
this agreement.</span> this agreement.</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c5 c1">7.</span> <span class="c5 c1">7.</span>
<span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class="c1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="c5 c1">SCOPE OF LICENSE.</span> <span class="c5 c1">SCOPE OF LICENSE.</span>
<span class="c3 c1">&nbsp;The software is licensed, not sold. This agreement only gives you some rights to use the software. <span class="c3 c1">&nbsp;The software is licensed, not sold. This agreement only gives you some
Microsoft reserves all other rights. Unless applicable law gives you more rights despite this rights to use the software.
Microsoft reserves all other rights. Unless applicable law gives you more rights despite
this
limitation, you may use the software only as expressly permitted in this agreement. &nbsp;In limitation, you may use the software only as expressly permitted in this agreement. &nbsp;In
doing so, you must comply with any technical limitations in the software that only allow you doing so, you must comply with any technical limitations in the software that only allow you
to use it in certain ways. You may not:</span> to use it in certain ways. You may not:</span>
</p> </p>
<p class="c8"> <p class="c8">
<span class="c3 c1">- &nbsp; &nbsp; work around any technical limitations in the software;</span> <span class="c3 c1">- &nbsp; &nbsp; work around any technical limitations in the
software;</span>
</p> </p>
<p class="c8"> <p class="c8">
<span class="c3 c1">- &nbsp; &nbsp; reverse engineer, decompile or disassemble the software, or attempt to do so, except <span class="c3 c1">- &nbsp; &nbsp; reverse engineer, decompile or disassemble the software, or
attempt to do so, except
and only to the extent required by third party licensing terms governing use of certain open and only to the extent required by third party licensing terms governing use of certain open
source components that may be included with the software;</span> source components that may be included with the software;</span>
</p> </p>
<p class="c8"> <p class="c8">
<span class="c3 c1">- &nbsp; &nbsp; remove, minimize, block or modify any notices of Microsoft or its suppliers in the <span class="c3 c1">- &nbsp; &nbsp; remove, minimize, block or modify any notices of Microsoft
or its suppliers in the
software; software;
</span> </span>
</p> </p>
<p class="c8"> <p class="c8">
<span class="c3 c1">- &nbsp; &nbsp; use the software in any way that is against the law; or</span> <span class="c3 c1">- &nbsp; &nbsp; use the software in any way that is against the law;
or</span>
</p> </p>
<p class="c8"> <p class="c8">
<span class="c3 c1">- &nbsp; &nbsp; share, publish, rent or lease the software, or provide the software as a stand-alone <span class="c3 c1">- &nbsp; &nbsp; share, publish, rent or lease the software, or provide the
software as a stand-alone
offering for others to use.</span> offering for others to use.</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c5 c1">8. &nbsp; UPDATES. </span> <span class="c5 c1">8. &nbsp; UPDATES. </span>
<span class="c3 c1">The software may periodically check for updates and download and install them for you. You may obtain <span class="c3 c1">The software may periodically check for updates and download and install
updates only from Microsoft or authorized sources. Microsoft may need to update your system to them for you. You may obtain
provide you with updates. You agree to receive these automatic updates without any additional updates only from Microsoft or authorized sources. Microsoft may need to update your system
notice. Updates may not include or support all existing software features, services, or peripheral to
provide you with updates. You agree to receive these automatic updates without any
additional
notice. Updates may not include or support all existing software features, services, or
peripheral
devices. devices.
</span> </span>
</p> </p>
@@ -564,57 +641,74 @@
<span class="c5 c1">9.</span> <span class="c5 c1">9.</span>
<span class="c1">&nbsp; &nbsp;</span> <span class="c1">&nbsp; &nbsp;</span>
<span class="c5 c1">EXPORT RESTRICTIONS.</span> <span class="c5 c1">EXPORT RESTRICTIONS.</span>
<span class="c3 c1">&nbsp;You must comply with all domestic and international export laws and regulations that apply <span class="c3 c1">&nbsp;You must comply with all domestic and international export laws and
to the software, which include restrictions on destinations, end users and end use. For further regulations that apply
to the software, which include restrictions on destinations, end users and end use. For
further
information on export restrictions, visit (aka.ms/exporting).</span> information on export restrictions, visit (aka.ms/exporting).</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c5 c1">10.</span> <span class="c5 c1">10.</span>
<span class="c1">&nbsp;</span> <span class="c1">&nbsp;</span>
<span class="c5 c1">SUPPORT SERVICES. </span> <span class="c5 c1">SUPPORT SERVICES. </span>
<span class="c3 c1">Because the software is &ldquo;as is,&rdquo; we may not provide support services for it.</span> <span class="c3 c1">Because the software is &ldquo;as is,&rdquo; we may not provide support
services for it.</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c5 c1">11.</span> <span class="c5 c1">11.</span>
<span class="c1">&nbsp;</span> <span class="c1">&nbsp;</span>
<span class="c5 c1">ENTIRE AGREEMENT.</span> <span class="c5 c1">ENTIRE AGREEMENT.</span>
<span class="c3 c1">&nbsp;This agreement, and the terms for supplements, updates, Internet-based services and support <span class="c3 c1">&nbsp;This agreement, and the terms for supplements, updates, Internet-based
services that you use, are the entire agreement for the software and support services.</span> services and support
services that you use, are the entire agreement for the software and support
services.</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c5 c1">12.</span> <span class="c5 c1">12.</span>
<span class="c1">&nbsp;</span> <span class="c1">&nbsp;</span>
<span class="c5 c1">APPLICABLE LAW. </span> <span class="c5 c1">APPLICABLE LAW. </span>
<span class="c3 c1">If you acquired the software in the United States, Washington State law applies to interpretation <span class="c3 c1">If you acquired the software in the United States, Washington State law
of and claims for breach of this agreement, and the laws of the state where you live apply to applies to interpretation
of and claims for breach of this agreement, and the laws of the state where you live apply
to
all other claims. If you acquired the software in any other country, its laws apply.</span> all other claims. If you acquired the software in any other country, its laws apply.</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c5 c1">13.</span> <span class="c5 c1">13.</span>
<span class="c1">&nbsp;</span> <span class="c1">&nbsp;</span>
<span class="c5 c1">CONSUMER RIGHTS; REGIONAL VARIATIONS. </span> <span class="c5 c1">CONSUMER RIGHTS; REGIONAL VARIATIONS. </span>
<span class="c3 c1">This agreement describes certain legal rights. You may have other rights, including consumer rights, <span class="c3 c1">This agreement describes certain legal rights. You may have other rights,
under the laws of your state or country. Separate and apart from your relationship with Microsoft, including consumer rights,
you may also have rights with respect to the party from which you acquired the software. This under the laws of your state or country. Separate and apart from your relationship with
agreement does not change those other rights if the laws of your state or country do not permit Microsoft,
it to do so. For example, if you acquired the software in one of the below regions, or mandatory you may also have rights with respect to the party from which you acquired the software.
This
agreement does not change those other rights if the laws of your state or country do not
permit
it to do so. For example, if you acquired the software in one of the below regions, or
mandatory
country law applies, then the following provisions apply to you:</span> country law applies, then the following provisions apply to you:</span>
</p> </p>
<p class="c8"> <p class="c8">
<span class="c5 c1">a.</span> <span class="c5 c1">a.</span>
<span class="c1">&nbsp; &nbsp;</span> <span class="c1">&nbsp; &nbsp;</span>
<span class="c5 c1">Australia. </span> <span class="c5 c1">Australia. </span>
<span class="c3 c1">You have statutory guarantees under the Australian Consumer Law and nothing in this agreement is <span class="c3 c1">You have statutory guarantees under the Australian Consumer Law and nothing
in this agreement is
intended to affect those rights.</span> intended to affect those rights.</span>
</p> </p>
<p class="c8"> <p class="c8">
<span class="c5 c1">b.</span> <span class="c5 c1">b.</span>
<span class="c1">&nbsp; &nbsp;</span> <span class="c1">&nbsp; &nbsp;</span>
<span class="c5 c1">Canada. </span> <span class="c5 c1">Canada. </span>
<span class="c3 c1">If you acquired the software in Canada, you may stop receiving updates by turning off the automatic <span class="c3 c1">If you acquired the software in Canada, you may stop receiving updates by
update feature, disconnecting your device from the Internet (if and when you re-connect to the turning off the automatic
Internet, however, the software will resume checking for and installing updates), or uninstalling update feature, disconnecting your device from the Internet (if and when you re-connect to
the software. The product documentation, if any, may also specify how to turn off updates for the
Internet, however, the software will resume checking for and installing updates), or
uninstalling
the software. The product documentation, if any, may also specify how to turn off updates
for
your specific device or software.</span> your specific device or software.</span>
</p> </p>
<p class="c8"> <p class="c8">
@@ -627,8 +721,10 @@
<span class="c5 c1">(i)</span> <span class="c5 c1">(i)</span>
<span class="c1">&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class="c1">&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="c5 c1">Warranty</span> <span class="c5 c1">Warranty</span>
<span class="c3 c1">. The properly licensed software will perform substantially as described in any Microsoft materials <span class="c3 c1">. The properly licensed software will perform substantially as described in
that accompany the software. However, Microsoft gives no contractual guarantee in relation to any Microsoft materials
that accompany the software. However, Microsoft gives no contractual guarantee in relation
to
the licensed software.</span> the licensed software.</span>
</p> </p>
<p class="c6"> <p class="c6">
@@ -638,74 +734,103 @@
<span class="c5 c1">(ii)</span> <span class="c5 c1">(ii)</span>
<span class="c1">&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class="c1">&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="c5 c1">Limitation of Liability</span> <span class="c5 c1">Limitation of Liability</span>
<span class="c3 c1">. In case of intentional conduct, gross negligence, claims based on the Product Liability Act, as <span class="c3 c1">. In case of intentional conduct, gross negligence, claims based on the
well as, in case of death or personal or physical injury, Microsoft is liable according to the Product Liability Act, as
well as, in case of death or personal or physical injury, Microsoft is liable according to
the
statutory law.</span> statutory law.</span>
</p> </p>
<p class="c10"> <p class="c10">
<span class="c3 c1">Subject to the foregoing clause (ii), Microsoft will only be liable for slight negligence if Microsoft <span class="c3 c1">Subject to the foregoing clause (ii), Microsoft will only be liable for
is in breach of such material contractual obligations, the fulfillment of which facilitate the slight negligence if Microsoft
due performance of this agreement, the breach of which would endanger the purpose of this agreement is in breach of such material contractual obligations, the fulfillment of which facilitate
and the compliance with which a party may constantly trust in (so-called &quot;cardinal obligations&quot;). the
In other cases of slight negligence, Microsoft will not be liable for slight negligence.</span> due performance of this agreement, the breach of which would endanger the purpose of this
agreement
and the compliance with which a party may constantly trust in (so-called &quot;cardinal
obligations&quot;).
In other cases of slight negligence, Microsoft will not be liable for slight
negligence.</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c5 c1">14.</span> <span class="c5 c1">14.</span>
<span class="c1">&nbsp;</span> <span class="c1">&nbsp;</span>
<span class="c5 c1">LEGAL EFFECT.</span> <span class="c5 c1">LEGAL EFFECT.</span>
<span class="c3 c1">&nbsp;This agreement describes certain legal rights. You may have other rights under the laws of <span class="c3 c1">&nbsp;This agreement describes certain legal rights. You may have other
your country. You may also have rights with respect to the party from whom you acquired the software. rights under the laws of
This agreement does not change your rights under the laws of your country if the laws of your your country. You may also have rights with respect to the party from whom you acquired the
software.
This agreement does not change your rights under the laws of your country if the laws of
your
country do not permit it to do so.</span> country do not permit it to do so.</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c5 c1">15.</span> <span class="c5 c1">15.</span>
<span class="c1">&nbsp;</span> <span class="c1">&nbsp;</span>
<span class="c4 c1">DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED &ldquo;AS-IS.&rdquo; &nbsp;YOU BEAR THE RISK OF <span class="c4 c1">DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED &ldquo;AS-IS.&rdquo;
USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. TO THE EXTENT PERMITTED &nbsp;YOU BEAR THE RISK OF
USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. TO THE EXTENT
PERMITTED
UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.</span> FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c5 c1">16.</span> <span class="c5 c1">16.</span>
<span class="c1">&nbsp;</span> <span class="c1">&nbsp;</span>
<span class="c4 c1">LIMITATION ON AND EXCLUSION OF DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT <span class="c4 c1">LIMITATION ON AND EXCLUSION OF DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND
DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST ITS SUPPLIERS ONLY DIRECT
DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL,
LOST
PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.</span> PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.</span>
</p> </p>
<p class="c0"> <p class="c0">
<span class="c3 c1">This limitation applies to (a) anything related to the software, services, content (including code) <span class="c3 c1">This limitation applies to (a) anything related to the software, services,
on third party Internet sites, or third party programs; and (b) claims for breach of contract, content (including code)
breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the on third party Internet sites, or third party programs; and (b) claims for breach of
contract,
breach of warranty, guarantee or condition, strict liability, negligence, or other tort to
the
extent permitted by applicable law.</span> extent permitted by applicable law.</span>
</p> </p>
<p class="c0"> <p class="c0">
<span class="c3 c1">It also applies even if Microsoft knew or should have known about the possibility of the damages. <span class="c3 c1">It also applies even if Microsoft knew or should have known about the
The above limitation or exclusion may not apply to you because your country may not allow the possibility of the damages.
The above limitation or exclusion may not apply to you because your country may not allow
the
exclusion or limitation of incidental, consequential or other damages.</span> exclusion or limitation of incidental, consequential or other damages.</span>
</p> </p>
<p class="c12"> <p class="c12">
<span class="c4 c1">Please note: As the software is distributed in Quebec, Canada, some of the clauses in this agreement <span class="c4 c1">Please note: As the software is distributed in Quebec, Canada, some of the
clauses in this agreement
are provided below in French.</span> are provided below in French.</span>
</p> </p>
<p class="c12"> <p class="c12">
<span class="c4 c1">Remarque : Ce logiciel &eacute;tant distribu&eacute; au Qu&eacute;bec, Canada, certaines des clauses <span class="c4 c1">Remarque : Ce logiciel &eacute;tant distribu&eacute; au Qu&eacute;bec,
Canada, certaines des clauses
dans ce contrat sont fournies ci-dessous en fran&ccedil;ais.</span> dans ce contrat sont fournies ci-dessous en fran&ccedil;ais.</span>
</p> </p>
<p class="c11"> <p class="c11">
<span class="c5 c1">EXON&Eacute;RATION DE GARANTIE.</span> <span class="c5 c1">EXON&Eacute;RATION DE GARANTIE.</span>
<span class="c1 c3">&nbsp;Le logiciel vis&eacute; par une licence est offert &laquo; tel quel &raquo;. Toute utilisation <span class="c1 c3">&nbsp;Le logiciel vis&eacute; par une licence est offert &laquo; tel quel
de ce logiciel est &agrave; votre seule risque et p&eacute;ril. Microsoft n&rsquo;accorde aucune &raquo;. Toute utilisation
autre garantie expresse. Vous pouvez b&eacute;n&eacute;ficier de droits additionnels en vertu de ce logiciel est &agrave; votre seule risque et p&eacute;ril. Microsoft n&rsquo;accorde
du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles aucune
sont permises par le droit locale, les garanties implicites de qualit&eacute; marchande, d&rsquo;ad&eacute;quation autre garantie expresse. Vous pouvez b&eacute;n&eacute;ficier de droits additionnels en
vertu
du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou
elles
sont permises par le droit locale, les garanties implicites de qualit&eacute; marchande,
d&rsquo;ad&eacute;quation
&agrave; un usage particulier et d&rsquo;absence de contrefa&ccedil;on sont exclues. &agrave; un usage particulier et d&rsquo;absence de contrefa&ccedil;on sont exclues.
</span> </span>
</p> </p>
<p class="c11"> <p class="c11">
<span class="c5 c1">LIMITATION DES DOMMAGES-INT&Eacute;R&Ecirc;TS ET EXCLUSION DE RESPONSABILIT&Eacute; POUR LES DOMMAGES.</span> <span class="c5 c1">LIMITATION DES DOMMAGES-INT&Eacute;R&Ecirc;TS ET EXCLUSION DE
<span class="c3 c1">&nbsp;Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages RESPONSABILIT&Eacute; POUR LES DOMMAGES.</span>
directs uniquement &agrave; hauteur de 5,00 $ US. Vous ne pouvez pr&eacute;tendre &agrave; aucune <span class="c3 c1">&nbsp;Vous pouvez obtenir de Microsoft et de ses fournisseurs une
indemnisation en cas de dommages
directs uniquement &agrave; hauteur de 5,00 $ US. Vous ne pouvez pr&eacute;tendre &agrave;
aucune
indemnisation pour les autres dommages, y compris les dommages sp&eacute;ciaux, indirects ou indemnisation pour les autres dommages, y compris les dommages sp&eacute;ciaux, indirects ou
accessoires et pertes de b&eacute;n&eacute;fices.</span> accessoires et pertes de b&eacute;n&eacute;fices.</span>
</p> </p>
@@ -713,26 +838,36 @@
<span class="c3 c1">Cette limitation concerne :</span> <span class="c3 c1">Cette limitation concerne :</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c3 c1">- &nbsp; &nbsp; &nbsp; &nbsp; tout ce qui est reli&eacute; au logiciel, aux services ou au contenu <span class="c3 c1">- &nbsp; &nbsp; &nbsp; &nbsp; tout ce qui est reli&eacute; au logiciel, aux
(y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et</span> services ou au contenu
(y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ;
et</span>
</p> </p>
<p class="c2"> <p class="c2">
<span class="c3 c1">- &nbsp; &nbsp; &nbsp; &nbsp; les r&eacute;clamations au titre de violation de contrat ou de garantie, <span class="c3 c1">- &nbsp; &nbsp; &nbsp; &nbsp; les r&eacute;clamations au titre de violation
ou au titre de responsabilit&eacute; stricte, de n&eacute;gligence ou d&rsquo;une autre faute de contrat ou de garantie,
ou au titre de responsabilit&eacute; stricte, de n&eacute;gligence ou d&rsquo;une autre
faute
dans la limite autoris&eacute;e par la loi en vigueur.</span> dans la limite autoris&eacute;e par la loi en vigueur.</span>
</p> </p>
<p class="c12"> <p class="c12">
<span class="c3 c1">Elle s&rsquo;applique &eacute;galement, m&ecirc;me si Microsoft connaissait ou devrait conna&icirc;tre <span class="c3 c1">Elle s&rsquo;applique &eacute;galement, m&ecirc;me si Microsoft connaissait
ou devrait conna&icirc;tre
l&rsquo;&eacute;ventualit&eacute; d&rsquo;un tel dommage. Si votre pays n&rsquo;autorise pas l&rsquo;&eacute;ventualit&eacute; d&rsquo;un tel dommage. Si votre pays n&rsquo;autorise pas
l&rsquo;exclusion ou la limitation de responsabilit&eacute; pour les dommages indirects, accessoires l&rsquo;exclusion ou la limitation de responsabilit&eacute; pour les dommages indirects,
ou de quelque nature que ce soit, il se peut que la limitation ou l&rsquo;exclusion ci-dessus accessoires
ou de quelque nature que ce soit, il se peut que la limitation ou l&rsquo;exclusion
ci-dessus
ne s&rsquo;appliquera pas &agrave; votre &eacute;gard.</span> ne s&rsquo;appliquera pas &agrave; votre &eacute;gard.</span>
</p> </p>
<p class="c16"> <p class="c16">
<span class="c5 c1">EFFET JURIDIQUE.</span> <span class="c5 c1">EFFET JURIDIQUE.</span>
<span class="c3 c1">&nbsp;Le pr&eacute;sent contrat d&eacute;crit certains droits juridiques. Vous pourriez avoir d&rsquo;autres <span class="c3 c1">&nbsp;Le pr&eacute;sent contrat d&eacute;crit certains droits juridiques.
droits pr&eacute;vus par les lois de votre pays. Le pr&eacute;sent contrat ne modifie pas les Vous pourriez avoir d&rsquo;autres
droits que vous conf&egrave;rent les lois de votre pays si celles-ci ne le permettent pas.</span> droits pr&eacute;vus par les lois de votre pays. Le pr&eacute;sent contrat ne modifie pas
les
droits que vous conf&egrave;rent les lois de votre pays si celles-ci ne le permettent
pas.</span>
</p> </p>
<p class="c15"> <p class="c15">
<span class="c3 c1"></span> <span class="c3 c1"></span>
@@ -740,9 +875,9 @@
<p class="c16"> <p class="c16">
<span class="c3 c1">&nbsp;</span> <span class="c3 c1">&nbsp;</span>
</p> </p>
<p class="c11"> <p class="c11">
<span class="c3 c1">LEGO, the LEGO logo, MINDSTORMS and the MINDSTORMS EV3 logo are trademarks and/ or copyrights of <span class="c3 c1">@copyrightText@</span>
the LEGO Group. &copy;2018 The LEGO Group. All rights reserved.</span>
</p> </p>
<p class="c11"> <p class="c11">
<span class="c3 c1">&nbsp;</span> <span class="c3 c1">&nbsp;</span>
@@ -755,27 +890,30 @@
</p> </p>
</div> </div>
</div> </div>
<div class="ui center aligned segment"> <div id="agree-segment" class="ui center aligned segment hidden">
<input id="agree-checkbox" type="checkbox" autocomplete="off" onchange="agreeCheckboxChanged(this)"> <input id="agree-checkbox" type="checkbox" autocomplete="off" onchange="agreeCheckboxChanged(this)">
<label for="agree-checkbox">I agree to these Microsoft Software License Terms and to the <label for="agree-checkbox">I agree to these Microsoft Software License Terms and to the
<a href="https://privacy.microsoft.com/en-us/privacystatement">Microsoft Privacy Statement.</a> <a href="https://privacy.microsoft.com/en-us/privacystatement">Microsoft Privacy Statement.</a>
</label> </label>
</div> </div>
<div id="no-download-segment" class="ui center aligned segment hidden">
<p>Sorry, there is no Offline App available for this editor.</p>
</div>
<div id="download-segment" class="ui center aligned segment hidden"> <div id="download-segment" class="ui center aligned segment hidden">
<div class="ui grid"> <div class="ui grid">
<div class="eight wide column"> <div class="eight wide column">
<h3 class="ui">Windows</h3> <h3 class="ui">Windows</h3>
<button class="ui icon button" onclick="downloadWin64()"> <a id="download-win64" class="ui icon button" onclick="downloadWin64()">
<i class="download icon"></i> <i class="download icon"></i>
makecode-ev3-setup-win64.exe makecode-@targetid@-setup-win64.exe
</button> </a>
</div> </div>
<div class="eight wide column"> <div class="eight wide column">
<h3 class="ui">Mac OS</h3> <h3 class="ui">Mac OS</h3>
<button class="ui icon button" onclick="downloadMac64()"> <a id="download-mac64" class="ui icon button" onclick="downloadMac64()">
<i class="download icon"></i> <i class="download icon"></i>
makecode-ev3-mac64.zip makecode-@targetid@-mac64.zip
</button> </a>
</div> </div>
</div> </div>
</div> </div>
@@ -788,4 +926,4 @@
</body> </body>
</html> </html>

View File

@@ -1,88 +1,9 @@
# Projects # Projects
```codecard Here are some cool projects that you can build with your @boardname@!
[
{
"name": "Getting Started",
"url": "/getting-started",
"imageUrl": "/static/lessons/firmware.png"
},
{
"name": "Brick Tutorials",
"url": "/tutorials/brick",
"imageUrl": "/static/tutorials/wake-up.png"
},
{
"name": "Motor Tutorials",
"url": "/tutorials/motors",
"imageUrl": "/static/tutorials/run-motors.png"
},
{
"name": "Touch Sensor Tutorials",
"url": "/tutorials/touch-sensor",
"imageUrl": "/static/tutorials/touch-to-run.png"
},
{
"name": "Color Sensor Tutorials",
"url": "/tutorials/color-sensor",
"imageUrl": "/static/tutorials/what-color.png"
},
{
"name": "Ultrasonic Sensor Tutorials",
"url": "/tutorials/ultrasonic-sensor",
"imageUrl": "/static/tutorials/object-near.png"
},
{
"name": "Gyro Tutorials",
"url": "/tutorials/gyro",
"imageUrl": "/static/tutorials/calibrate-gyro.png"
},
{
"name": "Infrared Sensor Tutorials",
"url": "/tutorials/infrared-sensor",
"imageUrl": "/static/tutorials/security-alert.png"
},
{
"name": "FLL / City Shaper",
"url": "/tutorials/city-shaper",
"imageUrl": "/static/tutorials/city-shaper/robot1.jpg"
},
{
"name": "Design Engineering",
"url": "/design-engineering",
"imageUrl": "/static/lessons/make-it-move-without-wheels.png"
},
{
"name": "Coding",
"url": "/coding",
"imageUrl": "/static/lessons/autonomous-parking.png"
},
{
"name": "Maker",
"url": "/maker",
"imageUrl": "/static/lessons/make-a-sound-machine.png"
},
{
"name": "Tutorial Videos",
"url": "/videos",
"imageUrl": "https://legoeducation.videomarketingplatform.co/27288170/35719444/5d009e5f93fbf479c2e5ed2bf87a7990/thumbnail.png"
}
]
```
## See Also ## Basic
[Getting Started](/getting-started), Basic projects to build with your EV3 Brick.
[Brick Tutorials](/tutorials/brick),
[Motor Tutorials](/tutorials/motors),
[Touch Sensor Tutorials](/tutorials/touch-sensor),
[Color Sensor Tutorials](/tutorials/color-sensor),
[Ultrasonic Sensor Tutorials](/tutorials/ultrasonic-sensor),
[Gyro Tutorials](/tutorials/gyro),
[Infrared Sensor Tutorials](/tutorials/infrared-sensor),
[FLL / City Shaper](/tutorials/city-shaper),
[Design Engineering](/design-engineering),
[Coding](/coding),
[Maker](/maker),
[Tutorial Videos](/videos)
Coming soon.

View File

@@ -1,69 +0,0 @@
# Projects
* [Getting Started](/getting-started)
* [Prepare](https://makecode.mindstorms.com/troubleshoot)
* [Try](/getting-started/try)
* [Use](/getting-started/use)
* [First LEGO League](/fll)
* [Brick Tutorials](/tutorials/brick)
* [Wake Up!](/tutorials/wake-up)
* [Make an Animation](/tutorials/make-an-animation)
* [What Animal Am I?](/tutorials/what-animal-am-i)
* [Music Brick](/tutorials/music-brick)
* [Pause On Start](/tutorials/pause-on-start)
* [Motor Tutorials](/tutorials/motors)
* [Run Motors](/tutorials/run-motors)
* [Spin Turn](/tutorials/spin-turn)
* [Pivot Turn](/tutorials/pivot-turn)
* [Smooth Turn](/tutorials/smooth-turn)
* [Tank ZigZag](/tutorials/tank-zigzag)
* [Coast Or Brake](/tutorials/coast-or-brake)
* [Turtle](/tutorials/turtle)
* [Touch Sensor Tutorials](/tutorials/touch-sensor)
* [Touch to Run](/tutorials/touch-to-run)
* [Sensor Values](/tutorials/touch-sensor-values)
* [Stop At Object](/tutorials/stop-at-object)
* [Color Sensor Tutorials](/tutorials/color-sensor)
* [What Color?](/tutorials/what-color)
* [Line Following](/tutorials/line-following)
* [Red Light, Green Light](/tutorials/redlight-greenlight)
* [Move To Color](/tutorials/move-to-color)
* [Reflected Light Measure](/tutorials/reflected-light-measure)
* [Reflected Light Calibration](/tutorials/reflected-light-calibration)
* [Ultrasonic Sensor Tutorials](/tutorials/ultrasonic-sensor)
* [Object Near](/tutorials/object-near)
* [Wall Follower](/tutorials/wall-follower)
* [Gyro Tutorials](/tutorials/gyro)
* [Calibrate](/tutorials/calibrate-gyro)
* [Turn](/tutorials/turn-with-gyro)
* [Move Straight](/tutorials/move-straight-with-gyro)
* [Drifter](/tutorials/drifter)
* [Infrared Sensor Tutorials](/tutorials/infrared-sensor)
* [Security Alert](/tutorials/security-alert)
* [FLL / City Shaper](/tutorials/city-shaper)
* [Crane Mission / Robot 1](/tutorials/city-shaper/robot-1)
* [Crane Mission / Robot 2](/tutorials/city-shaper/robot-2)
* [Crane Mission / Video 1](https://youtu.be/IqL0Pyeu5Ng)
* [Bluetooth download (beta)](https://youtu.be/VIq8-6Egtqs)
* [Turn with Gyro](https://youtu.be/I7ncuXAfBwk)
* [Moving with Gyro](https://youtu.be/ufiOPvW37xc)
* [Line following with 1 color sensor](https://youtu.be/_LeduyKQVjg)
* [Proportional line following with 1 color sensor](https://youtu.be/-AirqwC9DL4)
* [Proportional line following with 2 color sensors](https://youtu.be/QWOflBuu9Oo)
* [Design Engineering](/design-engineering)
* [Make It Move Without Wheels](/design-engineering/make-it-move)
* [Make It Smarter and Faster](/design-engineering/make-it-smarter)
* [Make a System that Communicates](/design-engineering/make-it-communicate)
* [Coding](/coding)
* [Autonomous Parking](/coding/autonomous-parking)
* [Object Detection](/coding/object-detection)
* [Line Detection](/coding/line-detection)
* [Maker](/maker)
* [Make A Sound Machine](/maker/sound-machine)
* [Make A Security Gadget](/maker/security-gadget)
* [Tutorial Videos](/videos)
* [undefined](https://legoeducation.videomarketingplatform.co/v.ihtml/player.html?token=5d009e5f93fbf479c2e5ed2bf87a7990&source=embed&photo%5fid=35719444)
* [undefined](https://legoeducation.videomarketingplatform.co/v.ihtml/player.html?token=2008a566f1fb034d58d5ebe19ba8621f&source=embed&photo%5fid=35719467)
* [undefined](https://legoeducation.videomarketingplatform.co/v.ihtml/player.html?token=629730c938e452f0fd7653fbc4708166&source=embed&photo%5fid=35719470)
* [undefined](https://legoeducation.videomarketingplatform.co/v.ihtml/player.html?token=3513a83b87fe536b2dc512237465fd1b&source=embed&photo%5fid=35719471)
* [undefined](https://legoeducation.videomarketingplatform.co/v.ihtml/player.html?token=5c594c2373367f7870196f519f3bfc7a&source=embed&photo%5fid=35719472)

View File

@@ -1,18 +0,0 @@
# exit Program
Stops the program and returns to the brick menu
```sig
brick.exitProgram();
```
## Example
Do a sequence of motor commands and stop the program.
```blocks
motors.largeA.run(50)
pause(500)
motors.stopAll()
brick.exitProgram();
```

View File

@@ -1,3 +0,0 @@
{
"appref": "v1.2"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

View File

@@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" id="svg4487" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4" clip-rule="evenodd" version="1.1" width="32" height="32" viewBox="0 0 32 32">
<path id="path4485" fill="#696969" d="M16.1 2.7a13.8 13.8 0 00-4.4 27c.7 0 1-.4 1-.7v-2.4c-3.9.9-4.7-1.8-4.7-1.8-.6-1.6-1.5-2-1.5-2-1.3-1 0-.9 0-.9 1.4.1 2.2 1.4 2.2 1.4 1.2 2.1 3.2 1.5 4 1.2a3 3 0 01.9-1.9c-3.1-.3-6.3-1.5-6.3-6.8 0-1.5.5-2.7 1.4-3.7a5 5 0 01.1-3.7s1.2-.3 3.8 1.4a13.2 13.2 0 013.5-.4c1.2 0 2.4.1 3.5.4 2.6-1.7 3.8-1.4 3.8-1.4a5 5 0 01.1 3.7c.9 1 1.4 2.2 1.4 3.7 0 5.3-3.2 6.5-6.3 6.8.5.5 1 1.3 1 2.6V29c0 .4.2.8.9.6a13.8 13.8 0 00-4.4-27"/>
<g id="text4497" fill="#000" fill-opacity="1" stroke="none" stroke-width=".7" aria-label="v" font-family="consolas" font-size="26.6" font-stretch="normal" font-style="normal" font-variant="normal" font-weight="400" letter-spacing="0" style="line-height:1.25;-inkscape-font-specification:consolas" transform="rotate(14.1)" word-spacing="0">
<path id="path4499" stroke-width=".7" d="M21.4-1.7l2.9 8 3-8.3.8-1.5q.4-.4 1-.4.8 0 1.2.5.5.4.5 1v.6l-.3.5-.2.7-3.4 8.4-.4 1-.5 1-.7.5q-.4.2-1 .2-.8 0-1.2-.3-.5-.3-.7-.8l-.7-1.6-3.4-8.3q0-.4-.2-.7l-.2-.6-.1-.6.2-.7.6-.6q.4-.2.9-.2.9 0 1.2.5l.7 1.7z" font-family="Arial Rounded MT Bold" font-stretch="normal" font-style="normal" font-variant="normal" font-weight="400" style="-inkscape-font-specification:'Arial Rounded MT Bold, '"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,18 +1,16 @@
# Troubleshooting # Troubleshooting download problems
## Download issues
If you're having trouble getting your code onto the EV3 Brick, try these steps to see if you can fix the problem. If you're having trouble getting your code onto the EV3 Brick, try these steps to see if you can fix the problem.
### Check your **@drivename@** firmware ## Check your **@drivename@** firmware
MakeCode needs a firmware version of **1.10E** or higher installed on your brick. MakeCode needs a firmware version of **1.10E** or higher installed on your brick.
#### ~hint ### ~hint
Firmware is the software that runs all the basic operations on your EV3 Brick. Your programs and the firmware work together to make the EV3 Brick do all things you want it to. Your EV3 Brick comes with firmware pre-installed, but it may need to be updated to work properly with MakeCode. Firmware is the software that runs all the basic operations on your EV3 Brick. Your programs and the firmware work together to make the EV3 Brick do all things you want it to. Your EV3 Brick comes with firmware pre-installed, but it may need to be updated to work properly with MakeCode.
#### ~ ### ~
To check the the firmware version on your EV3 Brick: To check the the firmware version on your EV3 Brick:
@@ -27,15 +25,15 @@ To check the the firmware version on your EV3 Brick:
If you can't find the **Brick Info** or you see that the version is less than **1.10E**, **you need to upgrade your firmware**. If you can't find the **Brick Info** or you see that the version is less than **1.10E**, **you need to upgrade your firmware**.
### Upgrade your **@drivename@** ## Upgrade your **@drivename@**
If your a firmware version level is less than **1.10E**, you need to install an upgraded version. You can upgrade the firmware with the **EV3 Lab** or **EV3 Programming** software. Also, you can do a manual upgrade by downloading the firmware install file. See the [Firmware Update](https://education.lego.com/en-us/support/mindstorms-ev3/firmware-update) support page to learn about the upgrade process. If your a firmware version level is less than **1.10E**, you need to install an upgraded version. You can upgrade the firmware with the **EV3 Lab** or **EV3 Programming** software. Also, you can do a manual upgrade by downloading the firmware install file. See the [Firmware Update](https://education.lego.com/en-us/support/mindstorms-ev3/firmware-update) support page to learn about the upgrade process.
#### ~ hint ### ~ hint
**Recommended:** Upgrade with the **[EV3 Device Manager](https://ev3manager.education.lego.com/)** **Recommended:** Upgrade with the **[EV3 Device Manager](https://ev3manager.education.lego.com/)**
#### ~ ### ~
## Can I see the **@drivename@** drive on my computer? ## Can I see the **@drivename@** drive on my computer?
@@ -47,24 +45,14 @@ On Windows, it looks like this in Explorer:
If you don't see the **@drivename@** drive, make sure your brick is powered on and check that your USB connection is good. If you don't see the **@drivename@** drive, make sure your brick is powered on and check that your USB connection is good.
### The display on the EV3 Brick is blank ## The display on the EV3 Brick is blank
Make sure your EV3 Brick is charged and powered on. If your it doesn't turn on, find the charger and plug it into wall power, then connect it to your EV3 Brick. Does it turn on and start up? Make sure your EV3 Brick is charged and powered on. If your it doesn't turn on, find the charger and plug it into wall power, then connect it to your EV3 Brick. Does it turn on and start up?
### I still can't see my @drivename@ drive ## I still can't see my @drivename@ drive
Make sure that one end of your USB cable is firmly inserted into a USB port on the computer and the other end is connected to the EV3 Brick. If you still can't see the **@drivename@** drive, try a different port on the computer. If that doesn't work then maybe your cable is faulty or you need to reset the EV3 Brick. Make sure that one end of your USB cable is firmly inserted into a USB port on the computer and the other end is connected to the EV3 Brick. If you still can't see the **@drivename@** drive, try a different port on the computer. If that doesn't work then maybe your cable is faulty or you need to reset the EV3 Brick.
## Why can't I delete my program (*.uf2) files from the Brick? #deletefiles
There's a bug in the firmware which prevents you from deleting the programs (``*.uf2`` files) from your EV3 Brick. There isn't a firmware update to fix this yet.
We have prepared a special program that lets you delete UF2 files from the brick.
Download [these PDF instructions](/file-manager.pdf) and drop the PDF on the brick drive.
This will present you with an menu for deleting files.
For other common questions, try the FAQ page https://makecode.mindstorms.com/faq.
## How do I reset my EV3 Brick? ## How do I reset my EV3 Brick?
If you think your USB connection is good and you still can't see your **@drivename@** drive, try giving the EV3 Brick a reset. You can follow these steps to reset: If you think your USB connection is good and you still can't see your **@drivename@** drive, try giving the EV3 Brick a reset. You can follow these steps to reset:

View File

@@ -3,15 +3,20 @@
import UF2 = pxtc.UF2; import UF2 = pxtc.UF2;
import { Ev3Wrapper } from "./wrap"; import { Ev3Wrapper } from "./wrap";
import { bluetoothTryAgainAsync } from "./dialogs";
export let ev3: Ev3Wrapper; export let ev3: Ev3Wrapper;
let confirmAsync: (options: any) => Promise<number>;
export function setConfirmAsync(cf: (options: any) => Promise<number>) {
confirmAsync = cf;
}
export function debug() { export function debug() {
return initHidAsync() return initHidAsync()
.then(w => w.downloadFileAsync("/tmp/dmesg.txt", v => console.log(pxt.Util.uint8ArrayToString(v)))) .then(w => w.downloadFileAsync("/tmp/dmesg.txt", v => console.log(pxt.Util.uint8ArrayToString(v))))
} }
// Web Serial API https://wicg.github.io/serial/ // Web Serial API https://wicg.github.io/serial/
// chromium bug https://bugs.chromium.org/p/chromium/issues/detail?id=884928 // chromium bug https://bugs.chromium.org/p/chromium/issues/detail?id=884928
// Under experimental features in Chrome Desktop 77+ // Under experimental features in Chrome Desktop 77+
@@ -162,7 +167,7 @@ export function initAsync(): Promise<void> {
useHID = false useHID = false
} else { } else {
const nodehid = /nodehid/i.test(window.location.href); const nodehid = /nodehid/i.test(window.location.href);
if (pxt.BrowserUtils.isLocalHost() && pxt.Cloud.localToken && nodehid) if (pxt.Cloud.isLocalHost() && pxt.Cloud.localToken && nodehid)
useHID = true; useHID = true;
} }
@@ -278,9 +283,22 @@ export function deployCoreAsync(resp: pxtc.CompileResult) {
return w.reconnectAsync(false) return w.reconnectAsync(false)
.catch(e => { .catch(e => {
// user easily forgets to stop robot // user easily forgets to stop robot
bluetoothTryAgainAsync().then(() => w.disconnectAsync()) if (confirmAsync)
.then(() => Promise.delay(1000)) return confirmAsync({
.then(() => w.reconnectAsync()); header: lf("Bluetooth download failed..."),
htmlBody:
`<ul>
<li>${lf("Make sure to stop your program or exit portview on the EV3.")}</li>
<li>${lf("Check your battery level.")}</li>
<li>${lf("Close EV3 LabView or other MakeCode editor tabs.")}
</ul>`,
hasCloseIcon: true,
hideCancel: true,
hideAgree: false,
agreeLbl: lf("Try again"),
}).then(() => w.disconnectAsync())
.then(() => Promise.delay(1000))
.then(() => w.reconnectAsync());
// nothing we can do // nothing we can do
return Promise.reject(e); return Promise.reject(e);

View File

@@ -1,145 +0,0 @@
import * as React from "react";
import { canUseWebSerial, enableWebSerialAsync } from "./deploy";
import { projectView } from "./extension";
let confirmAsync: (options: any) => Promise<number>;
export function bluetoothTryAgainAsync(): Promise<void> {
return confirmAsync({
header: lf("Bluetooth download failed..."),
jsx: <ul>
<li>{lf("Make sure to stop your program or exit portview on the EV3.")}</li>
<li>{lf("Check your battery level.")}</li>
<li>{lf("Close EV3 LabView or other MakeCode editor tabs.")}</li>
</ul>,
hasCloseIcon: false,
hideCancel: true,
hideAgree: false,
agreeLbl: lf("Try again")
}).then(r => {});
}
function enableWebSerialAndCompileAsync() {
return enableWebSerialAsync()
.then(() => Promise.delay(500))
.then(() => projectView.compile());
}
let bluetoothDialogShown = false;
function explainWebSerialPairingAsync(): Promise<void> {
if (!confirmAsync || bluetoothDialogShown) return Promise.resolve();
bluetoothDialogShown = true;
return confirmAsync({
header: lf("Bluetooth pairing"),
hasCloseIcon: false,
hideCancel: true,
buttons: [{
label: lf("Help"),
icon: "question circle",
className: "lightgrey",
url: "/bluetooth"
}],
jsx: <p>
{lf("You will be prompted to select a serial port.")}
{pxt.BrowserUtils.isWindows()
? lf("Look for 'Standard Serial over Bluetooth link'.")
: lf("Loop for 'cu.EV3-SerialPort'.")}
{lf("If you have paired multiple EV3, you might have to try out multiple ports until you find the correct one.")}
</p>
}).then(() => { })
}
export function showUploadDialogAsync(fn: string, url: string, _confirmAsync: (options: any) => Promise<number>): Promise<void> {
confirmAsync = _confirmAsync;
// https://msdn.microsoft.com/en-us/library/cc848897.aspx
// "For security reasons, data URIs are restricted to downloaded resources.
// Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements"
const downloadAgain = !pxt.BrowserUtils.isIE() && !pxt.BrowserUtils.isEdge();
const docUrl = pxt.appTarget.appTheme.usbDocs;
const jsx =
<div className="ui grid stackable">
<div className="column five wide" style={{ backgroundColor: "#E2E2E2" }}>
<div className="ui header">{lf("First time here?")}</div>
<strong style={{ fontSize: "small" }}>{lf("You must have version 1.10E or above of the firmware")}</strong>
<div style={{ justifyContent: "center", display: "flex", padding: "1rem" }}>
<img className="ui image" src="/static/download/firmware.png" style={{ height: "100px" }} />
</div>
<a href="/troubleshoot" target="_blank">{lf("Check your firmware version here and update if needed")}</a>
</div>
<div className="column eleven wide">
<div className="ui grid">
<div className="row">
<div className="column">
<div className="ui two column grid padded">
<div className="column">
<div className="ui">
<div className="image">
<img className="ui medium rounded image" src="/static/download/connect.svg" style={{ height: "109px", width: "261px", marginBottom: "1rem" }} />
</div>
<div className="content">
<div className="description">
<span className="ui yellow circular label">1</span>
<strong>{lf("Connect the EV3 to your computer with a USB cable")}</strong>
<br />
<span style={{ fontSize: "small" }}>{lf("Use the miniUSB port on the top of the EV3 Brick")}</span>
</div>
</div>
</div>
</div>
<div className="column">
<div className="ui">
<div className="image">
<img className="ui medium rounded image" src="/static/download/transfer.svg" style={{ height: "109px", width: "261px", marginBottom: "1rem" }} />
</div>
<div className="content">
<div className="description">
<span className="ui yellow circular label">2</span>
<strong>{lf("Move the .uf2 file to the EV3 Brick")}</strong>
<br />
<span style={{ fontSize: "small" }}>{lf("Locate the downloaded .uf2 file and drag it to the EV3 USB drive")}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>;
return confirmAsync({
header: lf("Download to your EV3"),
jsx,
hasCloseIcon: true,
hideCancel: true,
hideAgree: false,
agreeLbl: lf("I got it"),
className: 'downloaddialog',
buttons: [canUseWebSerial() ? {
label: lf("Bluetooth"),
icon: "bluetooth",
className: "bluetooth focused",
onclick: () => {
pxt.tickEvent("bluetooth.enable");
explainWebSerialPairingAsync()
.then(() => enableWebSerialAndCompileAsync())
.done();
}
} : undefined, downloadAgain ? {
label: fn,
icon: "download",
className: "lightgrey focused",
url,
fileName: fn
} : undefined, docUrl ? {
label: lf("Help"),
icon: "help",
className: "lightgrey",
url: docUrl
} : undefined]
//timeout: 20000
}).then(() => { });
}

View File

@@ -1,26 +1,144 @@
/// <reference path="../node_modules/pxt-core/localtypings/pxtarget.d.ts" />
/// <reference path="../node_modules/pxt-core/built/pxtblocks.d.ts" />
/// <reference path="../node_modules/pxt-core/built/pxtcompiler.d.ts" />
/// <reference path="../node_modules/pxt-core/built/pxtlib.d.ts" />
/// <reference path="../node_modules/pxt-core/built/pxteditor.d.ts"/> /// <reference path="../node_modules/pxt-core/built/pxteditor.d.ts"/>
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/> /// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
import { deployCoreAsync, initAsync } from "./deploy"; import { deployCoreAsync, initAsync, canUseWebSerial, enableWebSerialAsync, setConfirmAsync } from "./deploy";
import { showUploadDialogAsync } from "./dialogs";
export let projectView: pxt.editor.IProjectView;
let bluetoothDialogShown = false;
pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> { pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> {
const projectView = opts.projectView;
pxt.debug('loading pxt-ev3 target extensions...') pxt.debug('loading pxt-ev3 target extensions...')
projectView = opts.projectView;
function enableWebSerialAndCompileAsync() {
return enableWebSerialAsync()
.then(() => Promise.delay(500))
.then(() => projectView.compile());
}
const res: pxt.editor.ExtensionResult = { const res: pxt.editor.ExtensionResult = {
deployAsync: deployCoreAsync, deployCoreAsync,
showUploadInstructionsAsync: showUploadDialogAsync showUploadInstructionsAsync: (fn: string, url: string, confirmAsync: (options: any) => Promise<number>) => {
}; setConfirmAsync(confirmAsync);
// https://msdn.microsoft.com/en-us/library/cc848897.aspx
// "For security reasons, data URIs are restricted to downloaded resources.
// Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements"
const downloadAgain = !pxt.BrowserUtils.isIE() && !pxt.BrowserUtils.isEdge();
const docUrl = pxt.appTarget.appTheme.usbDocs;
const htmlBody = `
<div class="ui grid stackable">
<div class="column five wide" style="background-color: #E2E2E2;">
<div class="ui header">${lf("First time here?")}</div>
<strong style="font-size:small">${lf("You must have version 1.10E or above of the firmware")}</strong>
<div style="justify-content: center;display: flex;padding: 1rem;">
<img class="ui image" src="/static/download/firmware.png" style="height:100px;" />
</div>
<a href="/troubleshoot" target="_blank">${lf("Check your firmware version here and update if needed")}</a>
</div>
<div class="column eleven wide">
<div class="ui grid">
<div class="row">
<div class="column">
<div class="ui two column grid padded">
<div class="column">
<div class="ui">
<div class="image">
<img class="ui medium rounded image" src="/static/download/connect.svg" style="height:109px;width:261px;margin-bottom:1rem;" />
</div>
<div class="content">
<div class="description">
<span class="ui yellow circular label">1</span>
<strong>${lf("Connect the EV3 to your computer with a USB cable")}</strong>
<br />
<span style="font-size:small">${lf("Use the miniUSB port on the top of the EV3 Brick")}</span>
</div>
</div>
</div>
</div>
<div class="column">
<div class="ui">
<div class="image">
<img class="ui medium rounded image" src="/static/download/transfer.svg" style="height:109px;width:261px;margin-bottom:1rem;" />
</div>
<div class="content">
<div class="description">
<span class="ui yellow circular label">2</span>
<strong>${lf("Move the .uf2 file to the EV3 Brick")}</strong>
<br />
<span style="font-size:small">${lf("Locate the downloaded .uf2 file and drag it to the EV3 USB drive")}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>`;
return confirmAsync({
header: lf("Download to your EV3"),
htmlBody,
hasCloseIcon: true,
hideCancel: true,
hideAgree: false,
agreeLbl: lf("I got it"),
className: 'downloaddialog',
buttons: [canUseWebSerial() ? {
label: lf("Bluetooth"),
icon: "bluetooth",
className: "bluetooth focused",
onclick: () => {
pxt.tickEvent("bluetooth.enable");
if (bluetoothDialogShown) {
enableWebSerialAndCompileAsync().done();
} else {
bluetoothDialogShown = true;
confirmAsync({
header: lf("Bluetooth pairing"),
hasCloseIcon: true,
hideCancel: true,
buttons: [{
label: lf("Help"),
icon: "question circle",
className: "lightgrey",
url: "/bluetooth"
}],
htmlBody: `<p>
${lf("You will be prompted to select a serial port.")}
${pxt.BrowserUtils.isWindows()
? lf("Look for 'Standard Serial over Bluetooth link'.")
: lf("Loop for 'cu.EV3-SerialPort'.")}
${lf("If you have paired multiple EV3, you might have to try out multiple ports until you find the correct one.")}
</p>
`
}).then(() => enableWebSerialAndCompileAsync())
}
}
} : undefined, downloadAgain ? {
label: fn,
icon: "download",
className: "lightgrey focused",
url,
fileName: fn
} : undefined, docUrl ? {
label: lf("Help"),
icon: "help",
className: "lightgrey",
url: docUrl
} : undefined]
//timeout: 20000
}).then(() => { });
}
};
initAsync().catch(e => { initAsync().catch(e => {
// probably no HID - we'll try this again upon deployment // probably no HID - we'll try this again upon deployment
}) })
return Promise.resolve<pxt.editor.ExtensionResult>(res); return Promise.resolve<pxt.editor.ExtensionResult>(res);
} }
// When require()d from node, bind the global pxt namespace
// namespace pxt {
// export const dummyExport = 1;
// }
// eval("if (typeof process === 'object' && process + '' === '[object process]') pxt = global.pxt")

View File

@@ -1,17 +1,14 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "target": "es5",
"noImplicitAny": true, "noImplicitAny": false,
"noImplicitReturns": true, "noImplicitReturns": true,
"noImplicitThis": true,
"declaration": true,
"module": "commonjs", "module": "commonjs",
"moduleResolution": "node",
"isolatedModules": false,
"outDir": "../built/editor", "outDir": "../built/editor",
"rootDir": ".", "rootDir": ".",
"newLine": "LF", "newLine": "LF",
"sourceMap": false, "sourceMap": false,
"jsx": "react" "allowSyntheticDefaultImports": true,
"declaration": true
} }
} }

View File

@@ -3,7 +3,9 @@
import { FieldPorts } from "./field_ports"; import { FieldPorts } from "./field_ports";
import { FieldMotors } from "./field_motors"; import { FieldMotors } from "./field_motors";
import { FieldSpeed } from "./field_speed";
import { FieldBrickButtons } from "./field_brickbuttons"; import { FieldBrickButtons } from "./field_brickbuttons";
import { FieldTurnRatio } from "./field_turnratio";
import { FieldColorEnum } from "./field_color"; import { FieldColorEnum } from "./field_color";
import { FieldMusic } from "./field_music"; import { FieldMusic } from "./field_music";
@@ -17,9 +19,15 @@ pxt.editor.initFieldExtensionsAsync = function (opts: pxt.editor.FieldExtensionO
}, { }, {
selector: "motors", selector: "motors",
editor: FieldMotors editor: FieldMotors
}, {
selector: "speed",
editor: FieldSpeed
}, { }, {
selector: "brickbuttons", selector: "brickbuttons",
editor: FieldBrickButtons editor: FieldBrickButtons
}, {
selector: "turnratio",
editor: FieldTurnRatio
}, { }, {
selector: "colorenum", selector: "colorenum",
editor: FieldColorEnum editor: FieldColorEnum

View File

@@ -121,17 +121,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. // Calculate positioning based on the field position.
let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale; var scale = this.sourceBlock_.workspace.scale;
let bBox = { width: this.size_.width, height: this.size_.height }; var bBox = { width: this.size_.width, height: this.size_.height };
bBox.width *= scale; bBox.width *= scale;
bBox.height *= scale; bBox.height *= scale;
let position = this.fieldGroup_.getBoundingClientRect(); var position = this.fieldGroup_.getBoundingClientRect();
let primaryX = position.left + bBox.width / 2; var primaryX = position.left + bBox.width / 2;
let primaryY = position.top + bBox.height; var primaryY = position.top + bBox.height;
let secondaryX = primaryX; var secondaryX = primaryX;
let secondaryY = position.top; var secondaryY = position.top;
// Set bounds to workspace; show the drop-down. // Set bounds to workspace; show the drop-down.
(Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode); (Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode);
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY, (Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
this.onHide_.bind(this)); this.onHide_.bind(this));
} }
@@ -152,10 +152,9 @@ export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly.
* Callback for when the drop-down is hidden. * Callback for when the drop-down is hidden.
*/ */
private onHide_ = function () { private onHide_ = function () {
const content = Blockly.DropDownDiv.getContentDiv(); Blockly.DropDownDiv.content_.removeAttribute('role');
content.removeAttribute('role'); Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup');
content.removeAttribute('aria-haspopup'); Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant');
content.removeAttribute('aria-activedescendant'); Blockly.DropDownDiv.getContentDiv().style.width = '';
(content as HTMLElement).style.width = '';
}; };
} }

View File

@@ -44,7 +44,7 @@ export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Block
* @return {string} Current colour in '#rrggbb' format. * @return {string} Current colour in '#rrggbb' format.
*/ */
getValue(opt_asHex?: boolean) { getValue(opt_asHex?: boolean) {
const colour = this.mapColour(this.value_); var colour = this.mapColour(this.colour_);
if (!opt_asHex && colour.indexOf('#') > -1) { if (!opt_asHex && colour.indexOf('#') > -1) {
return `0x${colour.replace(/^#/, '')}`; return `0x${colour.replace(/^#/, '')}`;
} }
@@ -56,13 +56,13 @@ export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Block
* @param {string} colour The new colour in '#rrggbb' format. * @param {string} colour The new colour in '#rrggbb' format.
*/ */
setValue(colorStr: string) { setValue(colorStr: string) {
let colour = this.mapEnum(colorStr); var colour = this.mapEnum(colorStr);
if (this.sourceBlock_ && Blockly.Events.isEnabled() && if (this.sourceBlock_ && Blockly.Events.isEnabled() &&
this.value_ != colour) { this.colour_ != colour) {
Blockly.Events.fire(new (Blockly as any).Events.BlockChange( Blockly.Events.fire(new (Blockly as any).Events.BlockChange(
this.sourceBlock_, 'field', this.name, this.value_, colour)); this.sourceBlock_, 'field', this.name, this.colour_, colour));
} }
this.value_ = colour; this.colour_ = colour;
if (this.sourceBlock_) { if (this.sourceBlock_) {
this.sourceBlock_.setColour(colour, colour, colour); this.sourceBlock_.setColour(colour, colour, colour);
} }

View File

@@ -46,31 +46,31 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
(this as any).arrowX_ = 0; (this as any).arrowX_ = 0;
/** @type {Number} */ /** @type {Number} */
this.arrowY_ = 11; this.arrowY_ = 11;
this.arrow_ = Blockly.utils.dom.createSvgElement('image', { this.arrow_ = Blockly.utils.createSvgElement('image', {
'height': (this as any).arrowSize_ + 'px', 'height': (this as any).arrowSize_ + 'px',
'width': (this as any).arrowSize_ + 'px' 'width': (this as any).arrowSize_ + 'px'
}, null); });
this.arrow_.setAttributeNS('http://www.w3.org/1999/xlink', this.arrow_.setAttributeNS('http://www.w3.org/1999/xlink',
'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI); 'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI);
this.arrow2_ = <SVGImageElement>Blockly.utils.dom.createSvgElement('image', { this.arrow2_ = Blockly.utils.createSvgElement('image', {
'height': (this as any).arrowSize_ + 'px', 'height': (this as any).arrowSize_ + 'px',
'width': (this as any).arrowSize_ + 'px' 'width': (this as any).arrowSize_ + 'px'
}, null); });
this.arrow2_.setAttributeNS('http://www.w3.org/1999/xlink', this.arrow2_.setAttributeNS('http://www.w3.org/1999/xlink',
'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI); 'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI);
(this as any).className_ += ' blocklyDropdownText'; (this as any).className_ += ' blocklyDropdownText';
// Build the DOM. // Build the DOM.
this.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null);
if (!this.visible_) { if (!this.visible_) {
(this.fieldGroup_ as any).style.display = 'none'; (this.fieldGroup_ as any).style.display = 'none';
} }
// Adjust X to be flipped for RTL. Position is relative to horizontal start of source block. // Adjust X to be flipped for RTL. Position is relative to horizontal start of source block.
let size = this.getSize(); var size = this.getSize();
let fieldX = (this.sourceBlock_.RTL) ? -size.width / 2 : size.width / 2; var fieldX = (this.sourceBlock_.RTL) ? -size.width / 2 : size.width / 2;
/** @type {!Element} */ /** @type {!Element} */
this.textElement_ = Blockly.utils.dom.createSvgElement('text', this.textElement_ = Blockly.utils.createSvgElement('text',
{ {
'class': (this as any).className_, 'class': (this as any).className_,
'x': fieldX, 'x': fieldX,
@@ -79,7 +79,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
}, },
this.fieldGroup_); this.fieldGroup_);
fieldX += 10; // size of first group. fieldX += 10; // size of first group.
this.textElement2_ = <SVGTextElement>Blockly.utils.dom.createSvgElement('text', this.textElement2_ = Blockly.utils.createSvgElement('text',
{ {
'class': (this as any).className_, 'class': (this as any).className_,
'x': fieldX, 'x': fieldX,
@@ -89,17 +89,17 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
this.fieldGroup_); this.fieldGroup_);
this.updateEditable(); this.updateEditable();
(this.sourceBlock_ as Blockly.BlockSvg).getSvgRoot().appendChild(this.fieldGroup_); this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_);
// Force a render. // Force a render.
this.render_(); this.render_();
this.isDirty_ = true; this.size_.width = 0;
(this as any).mouseDownWrapper_ = (this as any).mouseDownWrapper_ =
Blockly.bindEventWithChecks_((this as any).getClickTarget_(), 'mousedown', this, Blockly.bindEventWithChecks_((this as any).getClickTarget_(), 'mousedown', this,
(this as any).onMouseDown_); (this as any).onMouseDown_);
// Add second dropdown // Add second dropdown
if (this.shouldShowRect_()) { if (this.shouldShowRect_()) {
this.box_ = <SVGRectElement>Blockly.utils.dom.createSvgElement('rect', { this.box_ = Blockly.utils.createSvgElement('rect', {
'rx': (Blockly.BlockSvg as any).CORNER_RADIUS, 'rx': (Blockly.BlockSvg as any).CORNER_RADIUS,
'ry': (Blockly.BlockSvg as any).CORNER_RADIUS, 'ry': (Blockly.BlockSvg as any).CORNER_RADIUS,
'x': 0, 'x': 0,
@@ -112,7 +112,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
'fill-opacity': 1 'fill-opacity': 1
}, null); }, null);
this.fieldGroup_.insertBefore(this.box_, this.textElement_); this.fieldGroup_.insertBefore(this.box_, this.textElement_);
this.box2_ = <SVGRectElement>Blockly.utils.dom.createSvgElement('rect', { this.box2_ = Blockly.utils.createSvgElement('rect', {
'rx': (Blockly.BlockSvg as any).CORNER_RADIUS, 'rx': (Blockly.BlockSvg as any).CORNER_RADIUS,
'ry': (Blockly.BlockSvg as any).CORNER_RADIUS, 'ry': (Blockly.BlockSvg as any).CORNER_RADIUS,
'x': 0, 'x': 0,
@@ -128,7 +128,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
} }
// Force a reset of the text to add the arrow. // Force a reset of the text to add the arrow.
let text = this.text_; var text = this.text_;
this.text_ = null; this.text_ = null;
this.setText(text); this.setText(text);
} }
@@ -149,9 +149,9 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
getFirstValueI11n(value: string) { getFirstValueI11n(value: string) {
const firstValue = this.getFirstValue(value); const firstValue = this.getFirstValue(value);
const motorOptions = { const motorOptions = {
'medium motor': lf("medium motor"), 'medium motor': lf('medium motor'),
'large motor': lf("large motor"), 'large motor': lf('large motor'),
'large motors': lf("large motors") 'large motors': lf('large motors')
} }
return motorOptions[firstValue]; return motorOptions[firstValue];
} }
@@ -179,7 +179,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
// Not rendered yet. // Not rendered yet.
return; return;
} }
let text = this.text_; var text = this.text_;
if (text.length > this.maxDisplayLength) { if (text.length > this.maxDisplayLength) {
// Truncate displayed string and add an ellipsis ('...'). // Truncate displayed string and add an ellipsis ('...').
text = text.substring(0, this.maxDisplayLength - 2) + '\u2026'; text = text.substring(0, this.maxDisplayLength - 2) + '\u2026';
@@ -200,11 +200,11 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
// Prevent the field from disappearing if empty. // Prevent the field from disappearing if empty.
text = Blockly.Field.NBSP; text = Blockly.Field.NBSP;
} }
let textNode = document.createTextNode(text); var textNode = document.createTextNode(text);
this.textElement2_.appendChild(textNode); this.textElement2_.appendChild(textNode);
// Cached width is obsolete. Clear it. // Cached width is obsolete. Clear it.
this.isDirty_ = true; this.size_.width = 0;
}; };
patchDualMotorText(text: string) { patchDualMotorText(text: string) {
@@ -233,8 +233,8 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
if (this.textElement2_) { if (this.textElement2_) {
this.textElement2_.parentNode.appendChild(this.arrow2_); this.textElement2_.parentNode.appendChild(this.arrow2_);
} }
if (this.sourceBlock_ && (<Blockly.BlockSvg>this.sourceBlock_).rendered) { if (this.sourceBlock_ && this.sourceBlock_.rendered) {
(<Blockly.BlockSvg>this.sourceBlock_).render(); this.sourceBlock_.render();
this.sourceBlock_.bumpNeighbours_(); this.sourceBlock_.bumpNeighbours_();
} }
} }
@@ -244,7 +244,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
return 0; return 0;
} }
let addedWidth = 0; var addedWidth = 0;
if (this.sourceBlock_.RTL) { if (this.sourceBlock_.RTL) {
(this as any).arrow2X_ = (this as any).arrowSize_ - (Blockly.BlockSvg as any).DROPDOWN_ARROW_PADDING; (this as any).arrow2X_ = (this as any).arrowSize_ - (Blockly.BlockSvg as any).DROPDOWN_ARROW_PADDING;
addedWidth = (this as any).arrowSize_ + (Blockly.BlockSvg as any).DROPDOWN_ARROW_PADDING; addedWidth = (this as any).arrowSize_ + (Blockly.BlockSvg as any).DROPDOWN_ARROW_PADDING;
@@ -263,10 +263,10 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
return addedWidth; return addedWidth;
}; };
updateSize_() { updateWidth() {
// Calculate width of field // Calculate width of field
let width = Blockly.Field.getCachedWidth(this.textElement_); var width = Blockly.Field.getCachedWidth(this.textElement_);
let width2 = Blockly.Field.getCachedWidth(this.textElement2_); var width2 = Blockly.Field.getCachedWidth(this.textElement2_);
// Add padding to left and right of text. // Add padding to left and right of text.
if (this.EDITABLE) { if (this.EDITABLE) {
@@ -311,15 +311,15 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
// First dropdown // First dropdown
// Use one of the following options, medium motor, large motor or large motors (translated) // Use one of the following options, medium motor, large motor or large motors (translated)
const textNode1 = document.createTextNode(this.getFirstValueI11n(<string>this.value_)); const textNode1 = document.createTextNode(this.getFirstValueI11n(this.value_));
this.textElement_.appendChild(textNode1); this.textElement_.appendChild(textNode1);
// Second dropdown, no need to translate. Only port numbers // Second dropdown, no need to translate. Only port numbers
if (this.textElement2_) { if (this.textElement2_) {
const textNode2 = document.createTextNode(this.getSecondValue(<string>this.value_)); const textNode2 = document.createTextNode(this.getSecondValue(this.value_));
this.textElement2_.appendChild(textNode2); this.textElement2_.appendChild(textNode2);
} }
this.updateSize_(); this.updateWidth();
// Update text centering, based on newly calculated width. // Update text centering, based on newly calculated width.
let centerTextX = ((this as any).width1 - this.arrowWidth_) / 2; let centerTextX = ((this as any).width1 - this.arrowWidth_) / 2;
@@ -347,8 +347,8 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
} }
// Apply new text element x position. // Apply new text element x position.
let width = Blockly.Field.getCachedWidth(this.textElement_); var width = Blockly.Field.getCachedWidth(this.textElement_);
let newX = centerTextX - width / 2; var newX = centerTextX - width / 2;
this.textElement_.setAttribute('x', `${newX}`); this.textElement_.setAttribute('x', `${newX}`);
// Update text centering, based on newly calculated width. // Update text centering, based on newly calculated width.
@@ -377,8 +377,8 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
} }
// Apply new text element x position. // Apply new text element x position.
let width2 = Blockly.Field.getCachedWidth(this.textElement2_); var width2 = Blockly.Field.getCachedWidth(this.textElement2_);
let newX2 = centerTextX2 - width2 / 2; var newX2 = centerTextX2 - width2 / 2;
this.textElement2_.setAttribute('x', `${newX2 + (this as any).width1 + Blockly.BlockSvg.BOX_FIELD_PADDING}`); this.textElement2_.setAttribute('x', `${newX2 + (this as any).width1 + Blockly.BlockSvg.BOX_FIELD_PADDING}`);
} }
@@ -401,7 +401,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
if (Blockly.DropDownDiv.hideIfOwner(this)) { if (Blockly.DropDownDiv.hideIfOwner(this)) {
return; return;
} }
this.isFirst_ = e.clientX - this.getScaledBBox_().left < ((this as any).width1 * (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale); this.isFirst_ = e.clientX - this.getScaledBBox_().left < ((this as any).width1 * this.sourceBlock_.workspace.scale);
// If there is an existing drop-down someone else owns, hide it immediately and clear it. // If there is an existing drop-down someone else owns, hide it immediately and clear it.
Blockly.DropDownDiv.hideWithoutAnimation(); Blockly.DropDownDiv.hideWithoutAnimation();
Blockly.DropDownDiv.clearContent(); Blockly.DropDownDiv.clearContent();
@@ -411,14 +411,14 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
// Accessibility properties // Accessibility properties
contentDiv.setAttribute('role', 'menu'); contentDiv.setAttribute('role', 'menu');
contentDiv.setAttribute('aria-haspopup', 'true'); contentDiv.setAttribute('aria-haspopup', 'true');
const foptions = this.getOptions(); // [img info, text] let options = this.getOptions();
let opts = {}; let opts = {};
let conts = {}; let conts = {};
let vals = {}; let vals = {};
// Go through all option values and split them into groups // Go through all option values and split them into groups
for (let opt = 0; opt < foptions.length; opt++) { for (let opt = 0; opt < options.length; opt++) {
const value = foptions[opt][1]; const value = options[opt][1];
const motorValue = value.substring(value.indexOf('.') + 1); const motorValue = value.substring(value.indexOf('.') + 1);
const typeValue = motorValue.indexOf('large') == 0 ? 'large' : 'medium'; const typeValue = motorValue.indexOf('large') == 0 ? 'large' : 'medium';
const portValue = motorValue.indexOf('large') == 0 ? motorValue.substring(5) : motorValue.substring(6); const portValue = motorValue.indexOf('large') == 0 ? motorValue.substring(5) : motorValue.substring(6);
@@ -429,14 +429,13 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
if (!opts[key]) opts[key] = []; if (!opts[key]) opts[key] = [];
opts[key].push(portValue); opts[key].push(portValue);
conts[text] = foptions[opt][0]; conts[text] = options[opt][0];
vals[text] = value; vals[text] = value;
} }
const currentFirst = this.getFirstValue(<string>this.value_); const currentFirst = this.getFirstValue(this.value_);
//const currentSecond = this.getSecondValue(<string>this.value_); const currentSecond = this.getSecondValue(this.value_);
let options: string[];
if (!this.isFirst_) { if (!this.isFirst_) {
options = opts[currentFirst]; options = opts[currentFirst];
} else { } else {
@@ -527,7 +526,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
Blockly.DropDownDiv.setColour(this.backgroundColour_, this.borderColour_); Blockly.DropDownDiv.setColour(this.backgroundColour_, this.borderColour_);
// Calculate positioning based on the field position. // Calculate positioning based on the field position.
let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale; let scale = this.sourceBlock_.workspace.scale;
let width = this.isFirst_ ? (this as any).width1 : (this as any).width2; let width = this.isFirst_ ? (this as any).width1 : (this as any).width2;
let bBox = { width: this.size_.width, height: this.size_.height }; let bBox = { width: this.size_.width, height: this.size_.height };
width *= scale; width *= scale;
@@ -539,7 +538,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
let secondaryX = primaryX; let secondaryX = primaryX;
let secondaryY = position.top; let secondaryY = position.top;
// Set bounds to workspace; show the drop-down. // Set bounds to workspace; show the drop-down.
(Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode); (Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode);
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY, (Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
this.onHide_.bind(this)); this.onHide_.bind(this));
@@ -562,11 +561,10 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
* Callback for when the drop-down is hidden. * Callback for when the drop-down is hidden.
*/ */
protected onHide_() { protected onHide_() {
const content = Blockly.DropDownDiv.getContentDiv(); Blockly.DropDownDiv.content_.removeAttribute('role');
content.removeAttribute('role'); Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup');
content.removeAttribute('aria-haspopup'); Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant');
content.removeAttribute('aria-activedescendant'); Blockly.DropDownDiv.getContentDiv().style.width = '';
(content as HTMLElement).style.width = '';
if (this.isFirst_ && this.box_) { if (this.isFirst_ && this.box_) {
this.box_.setAttribute('fill', this.sourceBlock_.getColour()); this.box_.setAttribute('fill', this.sourceBlock_.getColour());
} else if (!this.isFirst_ && this.box2_) { } else if (!this.isFirst_ && this.box2_) {

View File

@@ -26,7 +26,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
this.width_ = parseInt(options.width) || 380; this.width_ = parseInt(options.width) || 380;
this.setText = Blockly.FieldDropdown.prototype.setText; this.setText = Blockly.FieldDropdown.prototype.setText;
this.updateSize_ = (Blockly.Field as any).prototype.updateSize_; this.updateWidth = (Blockly.Field as any).prototype.updateWidth;
this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_; this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_;
if (!pxt.BrowserUtils.isIE() && !soundCache) { if (!pxt.BrowserUtils.isIE() && !soundCache) {
@@ -78,14 +78,14 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
contentDiv.style.width = (this as any).width_ + 'px'; contentDiv.style.width = (this as any).width_ + 'px';
contentDiv.style.cssFloat = 'left'; contentDiv.style.cssFloat = 'left';
(dropdownDiv as HTMLElement).style.maxHeight = `410px`; dropdownDiv.style.maxHeight = `410px`;
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_.getColourTertiary());
// Calculate positioning based on the field position. // Calculate positioning based on the field position.
let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale; let scale = this.sourceBlock_.workspace.scale;
let bBox = { width: this.size_.width, height: this.size_.height }; let bBox = { width: this.size_.width, height: this.size_.height };
bBox.width *= scale; bBox.width *= scale;
bBox.height *= scale; bBox.height *= scale;
@@ -95,7 +95,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
let secondaryX = primaryX; let secondaryX = primaryX;
let secondaryY = position.top; let secondaryY = position.top;
// Set bounds to workspace; show the drop-down. // Set bounds to workspace; show the drop-down.
(Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode); (Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode);
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY, (Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
this.onHide_.bind(this)); this.onHide_.bind(this));
@@ -236,7 +236,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
protected onHide_() { protected onHide_() {
super.onHide_(); super.onHide_();
(Blockly.DropDownDiv.getContentDiv() as HTMLElement).style.maxHeight = ''; Blockly.DropDownDiv.getContentDiv().style.maxHeight = '';
this.stopSounds(); this.stopSounds();
} }

View File

@@ -17,7 +17,7 @@ export class FieldPorts extends pxtblockly.FieldImages implements Blockly.FieldC
this.width_ = parseInt(options.width) || 300; this.width_ = parseInt(options.width) || 300;
this.setText = Blockly.FieldDropdown.prototype.setText; this.setText = Blockly.FieldDropdown.prototype.setText;
this.updateSize_ = (Blockly.Field as any).prototype.updateSize_; this.updateWidth = (Blockly.Field as any).prototype.updateWidth;
this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_; this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_;
} }

View File

@@ -0,0 +1,98 @@
/// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts"/>
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
export interface FieldSpeedOptions extends Blockly.FieldCustomOptions {
min?: string;
max?: string;
label?: string;
}
export class FieldSpeed extends Blockly.FieldSlider implements Blockly.FieldCustom {
public isFieldCustom_ = true;
private params: any;
private speedSVG: SVGElement;
private circleBar: SVGCircleElement;
private reporter: SVGTextElement;
/**
* Class for a color wheel field.
* @param {number|string} value The initial content of the field.
* @param {Function=} opt_validator An optional function that is called
* to validate any constraints on what the user entered. Takes the new
* text as an argument and returns either the accepted text, a replacement
* text, or null to abort the change.
* @extends {Blockly.FieldNumber}
* @constructor
*/
constructor(value_: any, params: FieldSpeedOptions, opt_validator?: Function) {
super(String(value_), '-100', '100', null, '10', 'Speed', opt_validator);
this.params = params;
if (this.params['min']) this.min_ = parseFloat(this.params.min);
if (this.params['max']) this.max_ = parseFloat(this.params.max);
if (this.params['label']) this.labelText_ = this.params.label;
(this as any).sliderColor_ = '#a8aaa8';
}
createLabelDom_(labelText: string) {
var labelContainer = document.createElement('div');
this.speedSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg") as SVGGElement;
pxsim.svg.hydrate(this.speedSVG, {
viewBox: "0 0 200 100",
width: "170"
});
labelContainer.appendChild(this.speedSVG);
const outerCircle = pxsim.svg.child(this.speedSVG, "circle", {
'stroke-dasharray': '565.48', 'stroke-dashoffset': '0',
'cx': 100, 'cy': 100, 'r': '90', 'style': `fill:transparent; transition: stroke-dashoffset 0.1s linear;`,
'stroke': '#a8aaa8', 'stroke-width': '1rem'
}) as SVGCircleElement;
this.circleBar = pxsim.svg.child(this.speedSVG, "circle", {
'stroke-dasharray': '565.48', 'stroke-dashoffset': '0',
'cx': 100, 'cy': 100, 'r': '90', 'style': `fill:transparent; transition: stroke-dashoffset 0.1s linear;`,
'stroke': '#f12a21', 'stroke-width': '1rem'
}) as SVGCircleElement;
this.reporter = pxsim.svg.child(this.speedSVG, "text", {
'x': 100, 'y': 80,
'text-anchor': 'middle', 'dominant-baseline': 'middle',
'style': 'font-size: 50px',
'class': 'sim-text inverted number'
}) as SVGTextElement;
// labelContainer.setAttribute('class', 'blocklyFieldSliderLabel');
var readout = document.createElement('span');
readout.setAttribute('class', 'blocklyFieldSliderReadout');
// var label = document.createElement('span');
// label.setAttribute('class', 'blocklyFieldSliderLabelText');
// label.innerHTML = labelText;
// labelContainer.appendChild(label);
// labelContainer.appendChild(readout);
return [labelContainer, readout];
};
setReadout_(readout: Element, value: string) {
let x = parseFloat(value) || 0;
this.updateSpeed(x);
// Update reporter
this.reporter.textContent = `${x}%`;
}
private updateSpeed(speed: number) {
let sign = this.sign(speed);
speed = (Math.abs(speed) / 100 * 50) + 50;
if (sign == -1) speed = 50 - speed;
let c = Math.PI * (90 * 2);
let pct = ((100 - speed) / 100) * c;
this.circleBar.setAttribute('stroke-dashoffset', `${pct}`);
}
// A re-implementation of Math.sign (since IE11 doesn't support it)
private sign(num: number) {
return num ? num < 0 ? -1 : 1 : 0;
}
}

View File

@@ -0,0 +1,108 @@
/// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts"/>
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
export interface FieldTurnRatioOptions extends Blockly.FieldCustomOptions {
}
export class FieldTurnRatio extends Blockly.FieldSlider implements Blockly.FieldCustom {
public isFieldCustom_ = true;
private params: any;
private path_: SVGPathElement;
private reporter_: SVGTextElement;
/**
* Class for a color wheel field.
* @param {number|string} value The initial content of the field.
* @param {Function=} opt_validator An optional function that is called
* to validate any constraints on what the user entered. Takes the new
* text as an argument and returns either the accepted text, a replacement
* text, or null to abort the change.
* @extends {Blockly.FieldNumber}
* @constructor
*/
constructor(value_: any, params: FieldTurnRatioOptions, opt_validator?: Function) {
super(String(value_), '-200', '200', null, '10', 'TurnRatio', opt_validator);
this.params = params;
(this as any).sliderColor_ = '#a8aaa8';
}
static HALF = 80;
static HANDLE_RADIUS = 30;
static RADIUS = FieldTurnRatio.HALF - FieldTurnRatio.HANDLE_RADIUS - 1;
createLabelDom_(labelText: string) {
let labelContainer = document.createElement('div');
let svg = Blockly.utils.createSvgElement('svg', {
'xmlns': 'http://www.w3.org/2000/svg',
'xmlns:html': 'http://www.w3.org/1999/xhtml',
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
'version': '1.1',
'height': (FieldTurnRatio.HALF + FieldTurnRatio.HANDLE_RADIUS + 10) + 'px',
'width': (FieldTurnRatio.HALF * 2) + 'px'
}, labelContainer);
let defs = Blockly.utils.createSvgElement('defs', {}, svg);
let marker = Blockly.utils.createSvgElement('marker', {
'id': 'head',
'orient': "auto",
'markerWidth': '2',
'markerHeight': '4',
'refX': '0.1', 'refY': '1.5'
}, defs);
let markerPath = Blockly.utils.createSvgElement('path', {
'd': 'M0,0 V3 L1.5,1.5 Z',
'fill': '#f12a21'
}, marker);
this.reporter_ = pxsim.svg.child(svg, "text", {
'x': FieldTurnRatio.HALF, 'y': 96,
'text-anchor': 'middle', 'dominant-baseline': 'middle',
'style': 'font-size: 50px',
'class': 'sim-text inverted number'
}) as SVGTextElement;
this.path_ = Blockly.utils.createSvgElement('path', {
'x1': FieldTurnRatio.HALF,
'y1': FieldTurnRatio.HALF,
'marker-end': 'url(#head)',
'style': 'fill: none; stroke: #f12a21; stroke-width: 10'
}, svg);
this.updateGraph_();
let readout = document.createElement('span');
readout.setAttribute('class', 'blocklyFieldSliderReadout');
return [labelContainer, readout];
};
updateGraph_() {
if (!this.path_) {
return;
}
let v = goog.math.clamp(parseFloat(this.getText()), -200, 200);
if (isNaN(v)) {
v = 0;
}
const x = v / 100;
const nx = Math.max(-1, Math.min(1, x));
const theta = Math.max(nx) * Math.PI / 2;
const r = FieldTurnRatio.RADIUS - 6;
let cx = FieldTurnRatio.HALF;
const cy = FieldTurnRatio.HALF - 22;
if (Math.abs(x) > 1) {
cx -= (x - (x > 0 ? 1 : -1)) * r / 2; // move center of circle
}
const alpha = 0.2 + Math.abs(nx) * 0.5;
const y1 = r * alpha;
const y2 = r * Math.sin(Math.PI / 2 - theta);
const x2 = r * Math.cos(Math.PI / 2 - theta);
const y3 = y2 - r * alpha * Math.cos(2 * theta);
const x3 = x2 - r * alpha * Math.sin(2 * theta);
const d = `M ${cx} ${cy} C ${cx} ${cy - y1} ${cx + x3} ${cy - y3} ${cx + x2} ${cy - y2}`;
this.path_.setAttribute('d', d);
this.reporter_.textContent = `${v}`;
}
setReadout_(readout: Element, value: string) {
this.updateGraph_();
}
}

View File

@@ -22,8 +22,13 @@
} }
declare const enum PerfCounters { declare const enum ValType {
GC = 0, Undefined = 0,
Boolean = 1,
Number = 2,
String = 3,
Object = 4,
Function = 5,
} }
// Auto-generated. Do not edit. Really. // Auto-generated. Do not edit. Really.

76
libs/base/shims.d.ts vendored
View File

@@ -4,18 +4,6 @@
//% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte //% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte
declare interface Buffer { declare interface Buffer {
/**
* Reads an unsigned byte at a particular location
*/
//% shim=BufferMethods::getUint8
getUint8(off: int32): int32;
/**
* Writes an unsigned byte at a particular location
*/
//% shim=BufferMethods::setUint8
setUint8(off: int32, v: int32): void;
/** /**
* Write a number in specified format in the buffer. * Write a number in specified format in the buffer.
*/ */
@@ -54,12 +42,6 @@ declare interface Buffer {
//% start.defl=0 length.defl=-1 shim=BufferMethods::shift //% start.defl=0 length.defl=-1 shim=BufferMethods::shift
shift(offset: int32, start?: int32, length?: int32): void; shift(offset: int32, start?: int32, length?: int32): void;
/**
* Convert a buffer to string assuming UTF8 encoding
*/
//% shim=BufferMethods::toString
toString(): string;
/** /**
* Convert a buffer to its hexadecimal representation. * Convert a buffer to its hexadecimal representation.
*/ */
@@ -90,13 +72,6 @@ declare namespace control {
*/ */
//% shim=control::createBuffer //% shim=control::createBuffer
function createBuffer(size: int32): Buffer; function createBuffer(size: int32): Buffer;
/**
* Create a new buffer with UTF8-encoded string
* @param str the string to put in the buffer
*/
//% shim=control::createBufferFromUTF8
function createBufferFromUTF8(str: string): Buffer;
} }
declare namespace loops { declare namespace loops {
@@ -126,12 +101,6 @@ declare namespace control {
//% blockId=control_running_time block="millis (ms)" shim=control::millis //% blockId=control_running_time block="millis (ms)" shim=control::millis
function millis(): int32; function millis(): int32;
/**
* Gets current time in microseconds. Overflows every ~18 minutes.
*/
//% shim=control::micros
function micros(): int32;
/** /**
* Used internally * Used internally
*/ */
@@ -174,54 +143,11 @@ declare namespace control {
//% help=control/device-serial-number shim=control::deviceSerialNumber //% help=control/device-serial-number shim=control::deviceSerialNumber
function deviceSerialNumber(): int32; function deviceSerialNumber(): int32;
/**
* Derive a unique, consistent 64-bit serial number of this device from internal data.
*/
//% blockId="control_device_long_serial_number" block="device long serial number" weight=9
//% help=control/device-long-serial-number shim=control::deviceLongSerialNumber
function deviceLongSerialNumber(): Buffer;
/** /**
* *
*/ */
//% shim=control::__log //% shim=control::__log
function __log(prority: int32, text: string): void; function __log(text: string): void;
/**
* Dump internal information about a value.
*/
//% shim=control::dmesgValue
function dmesgValue(v: any): void;
/**
* 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;
} }
// Auto-generated. Do not edit. Really. // Auto-generated. Do not edit. Really.

View File

@@ -1,4 +1,5 @@
const enum ColorSensorMode { const enum ColorSensorMode {
None = 0,
//% block="reflected light intensity" //% block="reflected light intensity"
ReflectedLightIntensity = 0, ReflectedLightIntensity = 0,
//% block="ambient light intensity" //% block="ambient light intensity"
@@ -58,6 +59,7 @@ namespace sensors {
constructor(port: number) { constructor(port: number) {
super(port) super(port)
this._setMode(ColorSensorMode.None);
this.thresholdDetector = new sensors.ThresholdDetector(this.id()); this.thresholdDetector = new sensors.ThresholdDetector(this.id());
this.calibrating = false; this.calibrating = false;
} }
@@ -179,22 +181,6 @@ namespace sensors {
return this.getNumber(NumberFormat.UInt8LE, 0) return this.getNumber(NumberFormat.UInt8LE, 0)
} }
/**
* Checks the color is being detected
* @param color the color to detect
*/
//% help=sensors/color-sensor/is-color-detected
//% block="is **color sensor** %this|detected|%color=colorEnumPicker"
//% blockId=colorisColorDetectedDetected
//% parts="colorsensor"
//% blockNamespace=sensors
//% this.fieldEditor="ports"
//% weight=99 blockGap=8
//% group="Color Sensor"
isColorDetected(color: number) {
return this.color() == color;
}
/** /**
* Get the current raw rgb values as an array from the color sensor. * Get the current raw rgb values as an array from the color sensor.
* @param sensor the color sensor to query the request * @param sensor the color sensor to query the request

View File

@@ -1,30 +0,0 @@
# Is Color Detected
Checks the color is detected
```sig
let b = sensors.color1.isColorDetected(ColorSensorColor.Blue)
```
The [color](/reference/sensors/color) you choose to look for is one of the colors that the sensor can detect. If you want to use colors for tracking, it's best to use a color that is the same or very close to the ones the sensor detects.
## Parameters
* **color**: the [color](/reference/sensors/color) to watch for.
## Example
Wait for the sensor to see ``blue``. Then, show an expression on the screen.
```blocks
brick.showString("Waiting for blue", 1)
while(!sensors.color1.isColorDetected(ColorSensorColor.Blue)) {
pause(20)
}
brick.clearScreen()
brick.showImage(images.expressionsSick)
```
## See also
[on color detected](/reference/sensors/color-sensor/on-color-detected), [color](/reference/sensors/color)

View File

@@ -26,7 +26,6 @@ namespace brick {
*/ */
//% blockId=brickBatteryProperty block="battery %property" //% blockId=brickBatteryProperty block="battery %property"
//% group="Battery" //% group="Battery"
//% blockGap=8
//% help=brick/battery-property //% help=brick/battery-property
export function batteryInfo(property: BatteryProperty): number { export function batteryInfo(property: BatteryProperty): number {
const info = sensors.internal.getBatteryInfo(); const info = sensors.internal.getBatteryInfo();

View File

@@ -85,7 +85,7 @@ namespace brick {
//% blockId=buttonIsPressed //% blockId=buttonIsPressed
//% parts="brick" //% parts="brick"
//% blockNamespace=brick //% blockNamespace=brick
//% weight=81 //% weight=81 blockGap=8
//% group="Buttons" //% group="Buttons"
//% button.fieldEditor="brickbuttons" //% button.fieldEditor="brickbuttons"
isPressed() { isPressed() {

40
libs/core/control.cpp Normal file
View File

@@ -0,0 +1,40 @@
#include "pxt.h"
namespace control {
/**
* Announce that an event happened to registered handlers.
* @param src ID of the Component that generated the event
* @param value Component specific code indicating the cause of the event.
* @param mode optional definition of how the event should be processed after construction.
*/
//% weight=21 blockGap=12 blockId="control_raise_event"
//% block="raise event|from %src|with value %value" blockExternalInputs=1
//% help=control/raise-event
void raiseEvent(int src, int value) {
pxt::raiseEvent(src, value);
}
/**
* Allocates the next user notification event
*/
//% help=control/allocate-notify-event
int allocateNotifyEvent() {
return pxt::allocateNotifyEvent();
}
/** Write data to DMESG debugging buffer. */
//%
void dmesg(String s) {
DMESG("# %s", s->data);
}
}
namespace serial {
/** Send DMESG debug buffer over serial. */
//%
void writeDmesg() {
pxt::dumpDmesg();
}
}

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

@@ -1,305 +1,6 @@
// Auto-generated. Do not edit. // Auto-generated. Do not edit.
declare const enum DAL { declare const enum DAL {
// /pxtapp/configkeys.h // built/dockermake/pxtapp/ev3const.h
CFG_PIN_NAME_MSK = 65535,
CFG_PIN_CONFIG_MSK = 4294901760,
CFG_PIN_CONFIG_ACTIVE_LO = 65536,
CFG_MAGIC0 = 513675505,
CFG_MAGIC1 = 539130489,
CFG_PIN_ACCELEROMETER_INT = 1,
CFG_PIN_ACCELEROMETER_SCL = 2,
CFG_PIN_ACCELEROMETER_SDA = 3,
CFG_PIN_BTN_A = 4,
CFG_PIN_BTN_B = 5,
CFG_PIN_BTN_SLIDE = 6,
CFG_PIN_DOTSTAR_CLOCK = 7,
CFG_PIN_DOTSTAR_DATA = 8,
CFG_PIN_FLASH_CS = 9,
CFG_PIN_FLASH_MISO = 10,
CFG_PIN_FLASH_MOSI = 11,
CFG_PIN_FLASH_SCK = 12,
CFG_PIN_LED = 13,
CFG_PIN_LIGHT = 14,
CFG_PIN_MICROPHONE = 15,
CFG_PIN_MIC_CLOCK = 16,
CFG_PIN_MIC_DATA = 17,
CFG_PIN_MISO = 18,
CFG_PIN_MOSI = 19,
CFG_PIN_NEOPIXEL = 20,
CFG_PIN_RX = 21,
CFG_PIN_RXLED = 22,
CFG_PIN_SCK = 23,
CFG_PIN_SCL = 24,
CFG_PIN_SDA = 25,
CFG_PIN_SPEAKER_AMP = 26,
CFG_PIN_TEMPERATURE = 27,
CFG_PIN_TX = 28,
CFG_PIN_TXLED = 29,
CFG_PIN_IR_OUT = 30,
CFG_PIN_IR_IN = 31,
CFG_PIN_DISPLAY_SCK = 32,
CFG_PIN_DISPLAY_MISO = 33,
CFG_PIN_DISPLAY_MOSI = 34,
CFG_PIN_DISPLAY_CS = 35,
CFG_PIN_DISPLAY_DC = 36,
CFG_DISPLAY_WIDTH = 37,
CFG_DISPLAY_HEIGHT = 38,
CFG_DISPLAY_CFG0 = 39,
CFG_DISPLAY_CFG1 = 40,
CFG_DISPLAY_CFG2 = 41,
CFG_DISPLAY_CFG3 = 42,
CFG_PIN_DISPLAY_RST = 43,
CFG_PIN_DISPLAY_BL = 44,
CFG_PIN_SERVO_1 = 45,
CFG_PIN_SERVO_2 = 46,
CFG_PIN_BTN_LEFT = 47,
CFG_PIN_BTN_RIGHT = 48,
CFG_PIN_BTN_UP = 49,
CFG_PIN_BTN_DOWN = 50,
CFG_PIN_BTN_MENU = 51,
CFG_PIN_LED_R = 52,
CFG_PIN_LED_G = 53,
CFG_PIN_LED_B = 54,
CFG_PIN_LED1 = 55,
CFG_PIN_LED2 = 56,
CFG_PIN_LED3 = 57,
CFG_PIN_LED4 = 58,
CFG_SPEAKER_VOLUME = 59,
CFG_PIN_JACK_TX = 60,
CFG_PIN_JACK_SENSE = 61,
CFG_PIN_JACK_HPEN = 62,
CFG_PIN_JACK_BZEN = 63,
CFG_PIN_JACK_PWREN = 64,
CFG_PIN_JACK_SND = 65,
CFG_PIN_JACK_BUSLED = 66,
CFG_PIN_JACK_COMMLED = 67,
CFG_PIN_BTN_SOFT_RESET = 69,
CFG_ACCELEROMETER_TYPE = 70,
CFG_PIN_BTNMX_LATCH = 71,
CFG_PIN_BTNMX_CLOCK = 72,
CFG_PIN_BTNMX_DATA = 73,
CFG_PIN_BTN_MENU2 = 74,
CFG_PIN_BATTSENSE = 75,
CFG_PIN_VIBRATION = 76,
CFG_PIN_PWREN = 77,
CFG_DISPLAY_TYPE = 78,
CFG_PIN_ROTARY_ENCODER_A = 79,
CFG_PIN_ROTARY_ENCODER_B = 80,
CFG_ACCELEROMETER_SPACE = 81,
CFG_PIN_WIFI_MOSI = 82,
CFG_PIN_WIFI_MISO = 83,
CFG_PIN_WIFI_SCK = 84,
CFG_PIN_WIFI_TX = 85,
CFG_PIN_WIFI_RX = 86,
CFG_PIN_WIFI_CS = 87,
CFG_PIN_WIFI_BUSY = 88,
CFG_PIN_WIFI_RESET = 89,
CFG_PIN_WIFI_GPIO0 = 90,
CFG_PIN_WIFI_AT_TX = 91,
CFG_PIN_WIFI_AT_RX = 92,
CFG_PIN_USB_POWER = 93,
ACCELEROMETER_TYPE_LIS3DH = 50,
ACCELEROMETER_TYPE_LIS3DH_ALT = 48,
ACCELEROMETER_TYPE_MMA8453 = 56,
ACCELEROMETER_TYPE_FXOS8700 = 60,
ACCELEROMETER_TYPE_MMA8653 = 58,
ACCELEROMETER_TYPE_MSA300 = 76,
ACCELEROMETER_TYPE_MPU6050 = 104,
DISPLAY_TYPE_ST7735 = 7735,
DISPLAY_TYPE_ILI9341 = 9341,
CFG_PIN_A0 = 100,
CFG_PIN_A1 = 101,
CFG_PIN_A2 = 102,
CFG_PIN_A3 = 103,
CFG_PIN_A4 = 104,
CFG_PIN_A5 = 105,
CFG_PIN_A6 = 106,
CFG_PIN_A7 = 107,
CFG_PIN_A8 = 108,
CFG_PIN_A9 = 109,
CFG_PIN_A10 = 110,
CFG_PIN_A11 = 111,
CFG_PIN_A12 = 112,
CFG_PIN_A13 = 113,
CFG_PIN_A14 = 114,
CFG_PIN_A15 = 115,
CFG_PIN_A16 = 116,
CFG_PIN_A17 = 117,
CFG_PIN_A18 = 118,
CFG_PIN_A19 = 119,
CFG_PIN_A20 = 120,
CFG_PIN_A21 = 121,
CFG_PIN_A22 = 122,
CFG_PIN_A23 = 123,
CFG_PIN_A24 = 124,
CFG_PIN_A25 = 125,
CFG_PIN_A26 = 126,
CFG_PIN_A27 = 127,
CFG_PIN_A28 = 128,
CFG_PIN_A29 = 129,
CFG_PIN_A30 = 130,
CFG_PIN_A31 = 131,
CFG_PIN_D0 = 150,
CFG_PIN_D1 = 151,
CFG_PIN_D2 = 152,
CFG_PIN_D3 = 153,
CFG_PIN_D4 = 154,
CFG_PIN_D5 = 155,
CFG_PIN_D6 = 156,
CFG_PIN_D7 = 157,
CFG_PIN_D8 = 158,
CFG_PIN_D9 = 159,
CFG_PIN_D10 = 160,
CFG_PIN_D11 = 161,
CFG_PIN_D12 = 162,
CFG_PIN_D13 = 163,
CFG_PIN_D14 = 164,
CFG_PIN_D15 = 165,
CFG_PIN_D16 = 166,
CFG_PIN_D17 = 167,
CFG_PIN_D18 = 168,
CFG_PIN_D19 = 169,
CFG_PIN_D20 = 170,
CFG_PIN_D21 = 171,
CFG_PIN_D22 = 172,
CFG_PIN_D23 = 173,
CFG_PIN_D24 = 174,
CFG_PIN_D25 = 175,
CFG_PIN_D26 = 176,
CFG_PIN_D27 = 177,
CFG_PIN_D28 = 178,
CFG_PIN_D29 = 179,
CFG_PIN_D30 = 180,
CFG_PIN_D31 = 181,
CFG_NUM_NEOPIXELS = 200,
CFG_NUM_DOTSTARS = 201,
CFG_DEFAULT_BUTTON_MODE = 202,
CFG_SWD_ENABLED = 203,
CFG_FLASH_BYTES = 204,
CFG_RAM_BYTES = 205,
CFG_SYSTEM_HEAP_BYTES = 206,
CFG_LOW_MEM_SIMULATION_KB = 207,
CFG_BOOTLOADER_BOARD_ID = 208,
CFG_UF2_FAMILY = 209,
CFG_PINS_PORT_SIZE = 210,
CFG_BOOTLOADER_PROTECTION = 211,
CFG_POWER_DEEPSLEEP_TIMEOUT = 212,
CFG_ANALOG_BUTTON_THRESHOLD = 213,
CFG_CPU_MHZ = 214,
CFG_CONTROLLER_LIGHT_MAX_BRIGHTNESS = 215,
CFG_PIN_B0 = 300,
CFG_PIN_B1 = 301,
CFG_PIN_B2 = 302,
CFG_PIN_B3 = 303,
CFG_PIN_B4 = 304,
CFG_PIN_B5 = 305,
CFG_PIN_B6 = 306,
CFG_PIN_B7 = 307,
CFG_PIN_B8 = 308,
CFG_PIN_B9 = 309,
CFG_PIN_B10 = 310,
CFG_PIN_B11 = 311,
CFG_PIN_B12 = 312,
CFG_PIN_B13 = 313,
CFG_PIN_B14 = 314,
CFG_PIN_B15 = 315,
CFG_PIN_B16 = 316,
CFG_PIN_B17 = 317,
CFG_PIN_B18 = 318,
CFG_PIN_B19 = 319,
CFG_PIN_B20 = 320,
CFG_PIN_B21 = 321,
CFG_PIN_B22 = 322,
CFG_PIN_B23 = 323,
CFG_PIN_B24 = 324,
CFG_PIN_B25 = 325,
CFG_PIN_B26 = 326,
CFG_PIN_B27 = 327,
CFG_PIN_B28 = 328,
CFG_PIN_B29 = 329,
CFG_PIN_B30 = 330,
CFG_PIN_B31 = 331,
CFG_PIN_C0 = 350,
CFG_PIN_C1 = 351,
CFG_PIN_C2 = 352,
CFG_PIN_C3 = 353,
CFG_PIN_C4 = 354,
CFG_PIN_C5 = 355,
CFG_PIN_C6 = 356,
CFG_PIN_C7 = 357,
CFG_PIN_C8 = 358,
CFG_PIN_C9 = 359,
CFG_PIN_C10 = 360,
CFG_PIN_C11 = 361,
CFG_PIN_C12 = 362,
CFG_PIN_C13 = 363,
CFG_PIN_C14 = 364,
CFG_PIN_C15 = 365,
CFG_PIN_C16 = 366,
CFG_PIN_C17 = 367,
CFG_PIN_C18 = 368,
CFG_PIN_C19 = 369,
CFG_PIN_C20 = 370,
CFG_PIN_C21 = 371,
CFG_PIN_C22 = 372,
CFG_PIN_C23 = 373,
CFG_PIN_C24 = 374,
CFG_PIN_C25 = 375,
CFG_PIN_C26 = 376,
CFG_PIN_C27 = 377,
CFG_PIN_C28 = 378,
CFG_PIN_C29 = 379,
CFG_PIN_C30 = 380,
CFG_PIN_C31 = 381,
CFG_PIN_P0 = 400,
CFG_PIN_P1 = 401,
CFG_PIN_P2 = 402,
CFG_PIN_P3 = 403,
CFG_PIN_P4 = 404,
CFG_PIN_P5 = 405,
CFG_PIN_P6 = 406,
CFG_PIN_P7 = 407,
CFG_PIN_P8 = 408,
CFG_PIN_P9 = 409,
CFG_PIN_P10 = 410,
CFG_PIN_P11 = 411,
CFG_PIN_P12 = 412,
CFG_PIN_P13 = 413,
CFG_PIN_P14 = 414,
CFG_PIN_P15 = 415,
CFG_PIN_P16 = 416,
CFG_PIN_P17 = 417,
CFG_PIN_P18 = 418,
CFG_PIN_P19 = 419,
CFG_PIN_P20 = 420,
CFG_PIN_P21 = 421,
CFG_PIN_P22 = 422,
CFG_PIN_P23 = 423,
CFG_PIN_P24 = 424,
CFG_PIN_P25 = 425,
CFG_PIN_P26 = 426,
CFG_PIN_P27 = 427,
CFG_PIN_P28 = 428,
CFG_PIN_P29 = 429,
CFG_PIN_P30 = 430,
CFG_PIN_P31 = 431,
CFG_PIN_LORA_MISO = 1001,
CFG_PIN_LORA_MOSI = 1002,
CFG_PIN_LORA_SCK = 1003,
CFG_PIN_LORA_CS = 1004,
CFG_PIN_LORA_BOOT = 1005,
CFG_PIN_LORA_RESET = 1006,
CFG_PIN_IRRXLED = 1007,
CFG_PIN_IRTXLED = 1008,
CFG_PIN_LCD_RESET = 1009,
CFG_PIN_LCD_ENABLE = 1010,
CFG_PIN_LCD_DATALINE4 = 1011,
CFG_PIN_LCD_DATALINE5 = 1012,
CFG_PIN_LCD_DATALINE6 = 1013,
CFG_PIN_LCD_DATALINE7 = 1014,
CFG_NUM_LCD_COLUMNS = 1015,
CFG_NUM_LCD_ROWS = 1016,
// /pxtapp/ev3const.h
NUM_INPUTS = 4, NUM_INPUTS = 4,
NUM_OUTPUTS = 4, NUM_OUTPUTS = 4,
LCD_WIDTH = 178, LCD_WIDTH = 178,
@@ -345,66 +46,44 @@ declare const enum DAL {
CONN_OUTPUT_TACHO = 125, CONN_OUTPUT_TACHO = 125,
CONN_NONE = 126, CONN_NONE = 126,
CONN_ERROR = 127, CONN_ERROR = 127,
opProgramStart = 3, opProgramStart = 0x03,
opOutputGetType = 160, opOutputGetType = 0xA0,
opOutputSetType = 161, opOutputSetType = 0xA1,
opOutputReset = 162, opOutputReset = 0xA2,
opOutputStop = 163, opOutputStop = 0xA3,
opOutputPower = 164, opOutputPower = 0xA4,
opOutputSpeed = 165, opOutputSpeed = 0xA5,
opOutputStart = 166, opOutputStart = 0xA6,
opOutputPolarity = 167, opOutputPolarity = 0xA7,
opOutputRead = 168, opOutputRead = 0xA8,
opOutputTest = 169, opOutputTest = 0xA9,
opOutputReady = 170, opOutputReady = 0xAA,
opOutputPosition = 171, opOutputPosition = 0xAB,
opOutputStepPower = 172, opOutputStepPower = 0xAC,
opOutputTimePower = 173, opOutputTimePower = 0xAD,
opOutputStepSpeed = 174, opOutputStepSpeed = 0xAE,
opOutputTimeSpeed = 175, opOutputTimeSpeed = 0xAF,
opOutputStepSync = 176, opOutputStepSync = 0xB0,
opOutputTimeSync = 177, opOutputTimeSync = 0xB1,
opOutputClearCount = 178, opOutputClearCount = 0xB2,
opOutputGetCount = 179, opOutputGetCount = 0xB3,
opOutputProgramStop = 180, opOutputProgramStop = 0xB4,
BUTTON_ID_UP = 1, BUTTON_ID_UP = 0x01,
BUTTON_ID_ENTER = 2, BUTTON_ID_ENTER = 0x02,
BUTTON_ID_DOWN = 4, BUTTON_ID_DOWN = 0x04,
BUTTON_ID_RIGHT = 8, BUTTON_ID_RIGHT = 0x08,
BUTTON_ID_LEFT = 16, BUTTON_ID_LEFT = 0x10,
BUTTON_ID_ESCAPE = 32, BUTTON_ID_ESCAPE = 0x20,
// /pxtapp/platform.h // built/dockermake/pxtapp/pxt.h
PXT_GC_THREAD_LIST = 1,
// /pxtapp/pxt.h
DEVICE_EVT_ANY = 0, DEVICE_EVT_ANY = 0,
DEVICE_ID_NOTIFY = 10000, DEVICE_ID_NOTIFY = 10000,
DEVICE_ID_NOTIFY_ONE = 10001, DEVICE_ID_NOTIFY_ONE = 10001,
IMAGE_BITS = 1, // built/dockermake/pxtapp/pxtbase.h
// /pxtapp/pxtbase.h PXT_REF_TAG_STRING = 1,
PXT32 = 1, PXT_REF_TAG_BUFFER = 2,
PXT64 = 1, PXT_REF_TAG_IMAGE = 3,
PXT_VTABLE_SHIFT = 2, PXT_REF_TAG_NUMBER = 32,
PXT_REFCNT_FLASH = 65534, PXT_REF_TAG_ACTION = 33,
VTABLE_MAGIC = 249,
Undefined = 0,
Boolean = 1,
Number = 2,
String = 3,
Object = 4,
Function = 5,
BoxedString = 1,
BoxedNumber = 2,
BoxedBuffer = 3,
RefAction = 4,
RefImage = 5,
RefCollection = 6,
RefRefLocal = 7,
RefMap = 8,
RefMImage = 9,
MMap = 10,
User0 = 16,
PXT_IOS_HEAP_ALLOC_BITS = 20,
IMAGE_HEADER_MAGIC = 135,
Int8LE = 1, Int8LE = 1,
UInt8LE = 2, UInt8LE = 2,
Int16LE = 3, Int16LE = 3,
@@ -421,10 +100,12 @@ declare const enum DAL {
Float64LE = 14, Float64LE = 14,
Float32BE = 15, Float32BE = 15,
Float64BE = 16, Float64BE = 16,
NUM_TRY_FRAME_REGS = 3, Undefined = 0,
GC = 0, Boolean = 1,
// /pxtapp/pxtconfig.h Number = 2,
PXT_GC = 1, String = 3,
// /pxtapp/pxtcore.h Object = 4,
PXT_HARD_FLOAT = 1, Function = 5,
// built/dockermake/pxtapp/pxtconfig.h
// built/dockermake/pxtapp/pxtcore.h
} }

View File

@@ -208,14 +208,12 @@ namespace sensors.internal {
} }
} }
export interface BatteryInfo { export function getBatteryInfo(): {
level: number; level: number;
Ibatt: number, Ibatt: number,
Vbatt: number, Vbatt: number,
Imotor: number Imotor: number
} } {
export function getBatteryInfo(): BatteryInfo {
init(); init();
if (!batteryInfo) updateBatteryInfo(); if (!batteryInfo) updateBatteryInfo();
const CinCnt = batteryInfo.CinCnt; const CinCnt = batteryInfo.CinCnt;
@@ -277,25 +275,22 @@ void cUiUpdatePower(void)
const conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS) const conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS)
let r = 0; let r = 0;
for (let i = 0; i < conns.length; ++i) { for (let i = 0; i < conns.length; ++i) {
r = conns[i] + (r << 6) + (r << 16) - r; r = (r << 8 | conns[i]);
} }
return r; return r;
} }
let nonActivated = 0; let nonActivated = 0;
function detectDevices() { function detectDevices() {
control.dmesg(`detect devices (hash ${hashDevices()})`) //control.dmesg(`detect devices (${nonActivated} na)`)
const conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS) const conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS)
let numChanged = 0; let numChanged = 0;
const uartSensors: SensorInfo[] = []; const uartSensors: SensorInfo[] = [];
for (const sensorInfo of sensorInfos) { for (const sensorInfo of sensorInfos) {
const newConn = conns[sensorInfo.port] const newConn = conns[sensorInfo.port]
if (newConn == sensorInfo.connType if (newConn == sensorInfo.connType) {
&& sensorInfo.sensor // control.dmesg(`connection unchanged ${newConn} at ${sensorInfo.port}`)
&& sensorInfo.sensor.isActive()) {
if (newConn == DAL.CONN_INPUT_UART)
uartSensors.push(sensorInfo);
continue; continue;
} }
numChanged++ numChanged++
@@ -326,8 +321,7 @@ void cUiUpdatePower(void)
for (const sensorInfo of uartSensors) { for (const sensorInfo of uartSensors) {
let uinfo = readUartInfo(sensorInfo.port, 0) let uinfo = readUartInfo(sensorInfo.port, 0)
sensorInfo.devType = uinfo[TypesOff.Type] sensorInfo.devType = uinfo[TypesOff.Type]
const mode = uinfo[TypesOff.Mode]; control.dmesg(`UART type ${sensorInfo.devType}`)
control.dmesg(`UART type ${sensorInfo.devType} mode ${mode}`)
} }
} }
@@ -462,7 +456,7 @@ void cUiUpdatePower(void)
reset() { reset() {
if (this.isActive()) uartReset(this._port); if (this.isActive()) uartReset(this._port);
this.realmode = -1; this.realmode = 0;
} }
} }
@@ -540,6 +534,8 @@ void cUiUpdatePower(void)
function uartClearChange(port: number) { function uartClearChange(port: number) {
control.dmesg(`UART clear change`); control.dmesg(`UART clear change`);
const UART_DATA_READY = 8
const UART_PORT_CHANGED = 1
while (true) { while (true) {
let status = getUartStatus(port) let status = getUartStatus(port)
if (port < 0) break if (port < 0) break
@@ -560,7 +556,7 @@ void cUiUpdatePower(void)
} }
function setUartModes() { function setUartModes() {
control.dmesg(`UART set modes 0x${devcon.toHex()}`) control.dmesg(`UART set modes`)
uartMM.ioctl(IO.UART_SET_CONN, devcon) uartMM.ioctl(IO.UART_SET_CONN, devcon)
const ports: number[] = []; const ports: number[] = [];
for (let port = 0; port < DAL.NUM_INPUTS; ++port) { for (let port = 0; port < DAL.NUM_INPUTS; ++port) {
@@ -572,26 +568,22 @@ void cUiUpdatePower(void)
while (ports.length) { while (ports.length) {
const port = ports.pop(); const port = ports.pop();
const status = waitNonZeroUartStatus(port) const status = waitNonZeroUartStatus(port)
control.dmesg(`UART status ${status} at ${port}`); control.dmesg(`UART set mode ${status} at ${port}`);
if (!(status & UART_DATA_READY))
setUartMode(port, devcon[DevConOff.Mode + port]);
} }
} }
function updateUartMode(port: number, mode: number) { function updateUartMode(port: number, mode: number) {
control.dmesg(`UART update mode to ${mode} at ${port}`) control.dmesg(`UART set mode to ${mode} at ${port}`)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Connection + port, DAL.CONN_INPUT_UART) devcon.setNumber(NumberFormat.Int8LE, DevConOff.Connection + port, DAL.CONN_INPUT_UART)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Type + port, 33) devcon.setNumber(NumberFormat.Int8LE, DevConOff.Type + port, 33)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Mode + port, mode) devcon.setNumber(NumberFormat.Int8LE, DevConOff.Mode + port, mode)
} }
const UART_PORT_CHANGED = 1
const UART_DATA_READY = 8
function setUartMode(port: number, mode: number) { function setUartMode(port: number, mode: number) {
const UART_PORT_CHANGED = 1
while (true) { while (true) {
if (port < 0) return if (port < 0) return
updateUartMode(port, mode); updateUartMode(port, mode);
control.dmesg(`UART set mode 0x${devcon.toHex()}`)
uartMM.ioctl(IO.UART_SET_CONN, devcon) uartMM.ioctl(IO.UART_SET_CONN, devcon)
let status = waitNonZeroUartStatus(port) let status = waitNonZeroUartStatus(port)
if (status & UART_PORT_CHANGED) { if (status & UART_PORT_CHANGED) {
@@ -599,8 +591,7 @@ void cUiUpdatePower(void)
uartClearChange(port) uartClearChange(port)
} else { } else {
control.dmesg(`UART status ${status}`); control.dmesg(`UART status ${status}`);
if (status & UART_DATA_READY) break;
break;
} }
pause(10) pause(10)
} }

589
libs/core/linux.cpp Normal file
View File

@@ -0,0 +1,589 @@
#include "pxt.h"
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <cstdarg>
#include <pthread.h>
#include <unistd.h>
#include <dirent.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <malloc.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include "ev3const.h"
#define THREAD_DBG(...)
#define MALLOC_LIMIT (8 * 1024 * 1024)
#define MALLOC_CHECK_PERIOD (1024 * 1024)
void *xmalloc(size_t sz) {
static size_t allocBytes = 0;
allocBytes += sz;
if (allocBytes >= MALLOC_CHECK_PERIOD) {
allocBytes = 0;
auto info = mallinfo();
DMESG("malloc used: %d kb", info.uordblks / 1024);
if (info.uordblks > MALLOC_LIMIT) {
target_panic(904);
}
}
auto r = malloc(sz);
if (r == NULL)
target_panic(905); // shouldn't happen
return r;
}
void *operator new(size_t size) {
return xmalloc(size);
}
void *operator new[](size_t size) {
return xmalloc(size);
}
void operator delete(void *p) {
free(p);
}
void operator delete[](void *p) {
free(p);
}
namespace pxt {
static int startTime;
static pthread_mutex_t execMutex;
static pthread_mutex_t eventMutex;
static pthread_cond_t newEventBroadcast;
struct Thread {
struct Thread *next;
Action act;
TValue arg0;
pthread_t pid;
pthread_cond_t waitCond;
int waitSource;
int waitValue;
TValue data0;
TValue data1;
};
static struct Thread *allThreads;
static struct Event *eventHead, *eventTail;
static int usbFD;
static int dmesgPtr;
static int dmesgSerialPtr;
static char dmesgBuf[4096];
struct Event {
struct Event *next;
int source;
int value;
};
Event lastEvent;
Event *mkEvent(int source, int value) {
auto res = new Event();
memset(res, 0, sizeof(Event));
res->source = source;
res->value = value;
return res;
}
#define USB_MAGIC 0x3d3f
#define USB_SERIAL 1
#define USB_RESTART 2
#define USB_DMESG 3
struct UsbPacket {
uint16_t size;
uint16_t msgcount;
uint16_t magic;
uint16_t code;
char buf[1024 - 8];
};
void *usbThread(void *) {
UsbPacket pkt;
UsbPacket resp;
while (true) {
int len = read(usbFD, &pkt, sizeof(pkt));
if (len <= 4) {
sleep_core_us(20000);
continue;
}
resp.msgcount = pkt.msgcount;
if (pkt.magic == USB_MAGIC) {
if (pkt.code == USB_RESTART) {
target_reset();
} else if (pkt.code == USB_DMESG) {
dumpDmesg();
}
/*
resp.magic = pkt.magic;
resp.code = pkt.code;
resp.size = 8;
write(usbFD, &resp, sizeof(resp));
*/
} else {
resp.magic = 0xffff;
resp.size = 4;
write(usbFD, &resp, sizeof(resp));
}
sleep_core_us(1000);
}
}
static void startUsb() {
usbFD = open("/dev/lms_usbdev", O_RDWR, 0666);
pthread_t pid;
pthread_create(&pid, NULL, usbThread, NULL);
pthread_detach(pid);
}
static void *exitThread(void *) {
int fd = open("/dev/lms_ui", O_RDWR, 0666);
if (fd < 0)
return 0;
uint8_t *data =
(uint8_t *)mmap(NULL, NUM_BUTTONS, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
close(fd);
return 0;
}
for (;;) {
if (data[5])
target_reset();
sleep_core_us(50000);
}
}
static void startExitThread() {
pthread_t pid;
pthread_create(&pid, NULL, exitThread, NULL);
pthread_detach(pid);
}
void sendUsb(uint16_t code, const char *data, int len) {
while (len > 0) {
int sz = len;
if (sz > 1000)
sz = 1000;
UsbPacket pkt = {(uint16_t)(6 + sz), 0, USB_MAGIC, code, {}};
memcpy(pkt.buf, data, sz);
write(usbFD, &pkt, sizeof(pkt));
len -= sz;
data += sz;
}
}
void sendSerial(const char *data, int len) {
sendUsb(USB_SERIAL, data, len);
}
volatile bool paniced;
extern "C" void drawPanic(int code);
extern "C" void target_panic(int error_code) {
char buf[50];
paniced = true;
pthread_mutex_trylock(&execMutex);
snprintf(buf, sizeof(buf), "\nPANIC %d\n", error_code);
drawPanic(error_code);
DMESG("PANIC %d", error_code);
for (int i = 0; i < 10; ++i) {
sendSerial(buf, strlen(buf));
sleep_core_us(500 * 1000);
}
target_reset();
}
void startUser() {
pthread_mutex_lock(&execMutex);
}
void stopUser() {
pthread_mutex_unlock(&execMutex);
}
void sleep_core_us(uint64_t us) {
struct timespec ts;
ts.tv_sec = us / 1000000;
ts.tv_nsec = (us % 1000000) * 1000;
while (nanosleep(&ts, &ts))
;
}
void sleep_ms(uint32_t ms) {
stopUser();
sleep_core_us(ms * 1000);
startUser();
}
void sleep_us(uint64_t us) {
if (us > 50000) {
sleep_ms(us / 1000);
}
sleep_core_us(us);
}
uint64_t currTime() {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
int current_time_ms() {
return currTime() - startTime;
}
void disposeThread(Thread *t) {
if (allThreads == t) {
allThreads = t->next;
} else {
for (auto tt = allThreads; tt; tt = tt->next) {
if (tt->next == t) {
tt->next = t->next;
break;
}
}
}
decr(t->act);
decr(t->arg0);
decr(t->data0);
decr(t->data1);
pthread_cond_destroy(&t->waitCond);
delete t;
}
static void runAct(Thread *thr) {
startUser();
pxt::runAction1(thr->act, thr->arg0);
stopUser();
disposeThread(thr);
}
static void mainThread(Thread *) {}
void setupThread(Action a, TValue arg = 0, void (*runner)(Thread *) = NULL, TValue d0 = 0,
TValue d1 = 0) {
if (runner == NULL)
runner = runAct;
auto thr = new Thread();
memset(thr, 0, sizeof(Thread));
thr->next = allThreads;
allThreads = thr;
thr->act = incr(a);
thr->arg0 = incr(arg);
thr->data0 = incr(d0);
thr->data1 = incr(d1);
pthread_cond_init(&thr->waitCond, NULL);
if (runner == mainThread) {
thr->pid = pthread_self();
} else {
pthread_create(&thr->pid, NULL, (void *(*)(void *))runner, thr);
THREAD_DBG("setup thread: %p (pid %p)", thr, thr->pid);
pthread_detach(thr->pid);
}
}
void releaseFiber() {
stopUser();
pthread_exit(NULL);
}
void runInParallel(Action a) {
setupThread(a);
}
static void runFor(Thread *t) {
startUser();
while (true) {
pxt::runAction0(t->act);
sleep_ms(20);
}
}
void runForever(Action a) {
setupThread(a, 0, runFor);
}
void waitForEvent(int source, int value) {
THREAD_DBG("waitForEv: %d %d", source, value);
auto self = pthread_self();
for (auto t = allThreads; t; t = t->next) {
THREAD_DBG("t: %p", t);
if (t->pid == self) {
pthread_mutex_lock(&eventMutex);
t->waitSource = source;
t->waitValue = value;
stopUser();
// spourious wake ups may occur they say
while (t->waitSource) {
pthread_cond_wait(&t->waitCond, &eventMutex);
}
pthread_mutex_unlock(&eventMutex);
startUser();
return;
}
}
DMESG("current thread not registered!");
target_panic(901);
}
static void dispatchEvent(Event &e) {
lastEvent = e;
auto curr = findBinding(e.source, e.value);
if (curr)
setupThread(curr->action, fromInt(e.value));
curr = findBinding(e.source, DEVICE_EVT_ANY);
if (curr)
setupThread(curr->action, fromInt(e.value));
}
static void *evtDispatcher(void *dummy) {
pthread_mutex_lock(&eventMutex);
while (true) {
pthread_cond_wait(&newEventBroadcast, &eventMutex);
while (eventHead != NULL) {
if (paniced)
return 0;
Event *ev = eventHead;
eventHead = ev->next;
if (eventHead == NULL)
eventTail = NULL;
for (auto thr = allThreads; thr; thr = thr->next) {
if (paniced)
return 0;
if (thr->waitSource == 0)
continue;
if (thr->waitValue != ev->value && thr->waitValue != DEVICE_EVT_ANY)
continue;
if (thr->waitSource == ev->source) {
thr->waitSource = 0; // once!
pthread_cond_broadcast(&thr->waitCond);
} else if (thr->waitSource == DEVICE_ID_NOTIFY &&
ev->source == DEVICE_ID_NOTIFY_ONE) {
thr->waitSource = 0; // once!
pthread_cond_broadcast(&thr->waitCond);
break; // do not wake up any other threads
}
}
dispatchEvent(*ev);
delete ev;
}
}
}
int allocateNotifyEvent() {
static volatile int notifyId;
pthread_mutex_lock(&eventMutex);
int res = ++notifyId;
pthread_mutex_unlock(&eventMutex);
return res;
}
void raiseEvent(int id, int event) {
auto e = mkEvent(id, event);
pthread_mutex_lock(&eventMutex);
if (eventTail == NULL) {
if (eventHead != NULL)
target_panic(902);
eventHead = eventTail = e;
} else {
eventTail->next = e;
eventTail = e;
}
pthread_cond_broadcast(&newEventBroadcast);
pthread_mutex_unlock(&eventMutex);
}
void registerWithDal(int id, int event, Action a, int flags) {
// TODO support flags
setBinding(id, event, a);
}
static void runPoller(Thread *thr) {
Action query = thr->data0;
auto us = (uint64_t)toInt(thr->data1) * 1000;
// note that this is run without the user mutex held - it should not modify any state!
TValue prev = pxt::runAction0(query);
startUser();
pxt::runAction2(thr->act, prev, prev);
stopUser();
while (true) {
sleep_core_us(us);
if (paniced)
break;
TValue curr = pxt::runAction0(query);
if (curr != prev) {
startUser();
pxt::runAction2(thr->act, prev, curr);
stopUser();
if (paniced)
break;
decr(prev);
prev = curr;
}
}
// disposeThread(thr);
}
uint32_t afterProgramPage() {
return 0;
}
void dumpDmesg() {
auto len = dmesgPtr - dmesgSerialPtr;
if (len == 0)
return;
sendSerial(dmesgBuf + dmesgSerialPtr, len);
dmesgSerialPtr = dmesgPtr;
}
int lmsPid;
void stopLMS() {
struct dirent *ent;
DIR *dir;
dir = opendir("/proc");
if (dir == NULL)
return;
while ((ent = readdir(dir)) != NULL) {
int pid = atoi(ent->d_name);
if (!pid)
continue;
char namebuf[100];
snprintf(namebuf, 1000, "/proc/%d/cmdline", pid);
FILE *f = fopen(namebuf, "r");
if (f) {
fread(namebuf, 1, 99, f);
if (strcmp(namebuf, "./lms2012") == 0) {
lmsPid = pid;
}
fclose(f);
if (lmsPid)
break;
}
}
closedir(dir);
lmsPid = 0; // disable SIGSTOP for now - rethink if problems with I2C (runs on a thread)
if (lmsPid) {
DMESG("SIGSTOP to lmsPID=%d", lmsPid);
if (kill(lmsPid, SIGSTOP))
DMESG("SIGSTOP failed");
}
}
void runLMS() {
DMESG("re-starting LMS2012");
kill(lmsPid, SIGCONT);
sleep_core_us(200000);
exit(0);
/*
chdir("/home/root/lms2012/sys");
for (int fd = 3; fd < 9999; ++fd)
close(fd);
execl("lms2012", "./lms2012");
exit(100); // should not be reached
*/
}
void stopMotors() {
uint8_t cmd[3] = {opOutputStop, 0x0F, 0};
int fd = open("/dev/lms_pwm", O_RDWR);
write(fd, cmd, 3);
close(fd);
}
void stopProgram() {
uint8_t cmd[1] = {opOutputProgramStop};
int fd = open("/dev/lms_pwm", O_RDWR);
write(fd, cmd, 1);
close(fd);
}
extern "C" void target_reset() {
pthread_mutex_trylock(&execMutex);
stopMotors();
stopProgram();
if (lmsPid)
runLMS();
else
exit(0);
}
void screen_init();
void initRuntime() {
// daemon(1, 1);
startTime = currTime();
DMESG("runtime starting...");
stopLMS();
startUsb();
startExitThread();
pthread_t disp;
pthread_create(&disp, NULL, evtDispatcher, NULL);
pthread_detach(disp);
setupThread(0, 0, mainThread);
target_init();
screen_init();
startUser();
}
static FILE *dmesgFile;
void dmesgRaw(const char *buf, uint32_t len) {
if (!dmesgFile) {
dmesgFile = fopen("/tmp/dmesg.txt", "w");
if (!dmesgFile)
dmesgFile = stderr;
}
if (len > sizeof(dmesgBuf) / 2)
return;
if (dmesgPtr + len > sizeof(dmesgBuf)) {
dmesgPtr = 0;
dmesgSerialPtr = 0;
}
memcpy(dmesgBuf + dmesgPtr, buf, len);
dmesgPtr += len;
fwrite(buf, 1, len, dmesgFile);
}
void dmesg(const char *format, ...) {
char buf[500];
snprintf(buf, sizeof(buf), "[%8d] ", current_time_ms());
dmesgRaw(buf, strlen(buf));
va_list arg;
va_start(arg, format);
vsnprintf(buf, sizeof(buf), format, arg);
va_end(arg);
dmesgRaw(buf, strlen(buf));
dmesgRaw("\n", 1);
fflush(dmesgFile);
fdatasync(fileno(dmesgFile));
}
} // namespace pxt

View File

@@ -25,20 +25,13 @@ PXT_VTABLE_CTOR(MMap) {
} }
void MMap::print() { void MMap::print() {
DMESG("MMap %p len=%d fd=%d data=%p", this, length, fd, data); DMESG("MMap %p r=%d len=%d fd=%d data=%p", this, refcnt, length, fd, data);
} }
void MMap::destroy() { void MMap::destroy() {
munmap(data, length); munmap(data, length);
close(fd); close(fd);
} }
void MMap::scan(MMap *) {}
unsigned MMap::gcsize(MMap *) {
return TOWORDS(sizeof(MMap));
}
} }
namespace control { namespace control {
@@ -46,8 +39,8 @@ namespace control {
/** Create new file mapping in memory */ /** Create new file mapping in memory */
//% //%
MMap *mmap(String filename, int size, int offset) { MMap *mmap(String filename, int size, int offset) {
DMESG("mmap %s len=%d off=%d", filename->getUTF8Data(), size, offset); DMESG("mmap %s len=%d off=%d", filename->data, size, offset);
int fd = open(filename->getUTF8Data(), O_RDWR, 0); int fd = open(filename->data, O_RDWR, 0);
if (fd < 0) if (fd < 0)
return 0; return 0;

View File

@@ -159,7 +159,6 @@ namespace motors {
private _accelerationTime: number; private _accelerationTime: number;
private _decelerationSteps: number; private _decelerationSteps: number;
private _decelerationTime: number; private _decelerationTime: number;
private _inverted: boolean;
protected static output_types: number[] = [0x7, 0x7, 0x7, 0x7]; protected static output_types: number[] = [0x7, 0x7, 0x7, 0x7];
@@ -177,7 +176,6 @@ namespace motors {
this._accelerationTime = 0; this._accelerationTime = 0;
this._decelerationSteps = 0; this._decelerationSteps = 0;
this._decelerationTime = 0; this._decelerationTime = 0;
this._inverted = false;
} }
/** /**
@@ -227,11 +225,9 @@ namespace motors {
//% help=motors/motor/set-inverted //% help=motors/motor/set-inverted
setInverted(inverted: boolean) { setInverted(inverted: boolean) {
this.init(); this.init();
this._inverted = inverted; const b = mkCmd(this._port, DAL.opOutputPolarity, 1)
} b.setNumber(NumberFormat.Int8LE, 2, inverted ? 0 : 1);
writePWM(b)
protected invertedFactor(): number {
return this._inverted ? -1 : 1;
} }
/** /**
@@ -298,9 +294,8 @@ namespace motors {
} }
private normalizeSchedule(speed: number, step1: number, step2: number, step3: number, unit: MoveUnit): MoveSchedule { private normalizeSchedule(speed: number, step1: number, step2: number, step3: number, unit: MoveUnit): MoveSchedule {
// motor polarity is not supported at the firmware level for sync motor operations
const r: MoveSchedule = { const r: MoveSchedule = {
speed: Math.clamp(-100, 100, speed | 0) * this.invertedFactor(), speed: Math.clamp(-100, 100, speed >> 0),
useSteps: true, useSteps: true,
steps: [step1 || 0, step2 || 0, step3 || 0] steps: [step1 || 0, step2 || 0, step3 || 0]
} }
@@ -567,7 +562,6 @@ namespace motors {
private __init() { private __init() {
this.setOutputType(this._large); this.setOutputType(this._large);
this.setInverted(false);
} }
/** /**
@@ -747,7 +741,7 @@ namespace motors {
//% help=motors/synced/steer //% help=motors/synced/steer
steer(turnRatio: number, speed: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) { steer(turnRatio: number, speed: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
this.init(); this.init();
speed = Math.clamp(-100, 100, speed >> 0) * this.invertedFactor(); speed = Math.clamp(-100, 100, speed >> 0);
if (!speed) { if (!speed) {
this.stop(); this.stop();
return; return;
@@ -924,3 +918,9 @@ namespace motors {
writePWM(b) writePWM(b)
} }
} }
interface Buffer {
[index: number]: number;
// rest defined in buffer.cpp
}

View File

@@ -1,236 +0,0 @@
#include "pxt.h"
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <signal.h>
#include <dirent.h>
#include "ev3const.h"
namespace pxt {
static int usbFD;
#define USB_MAGIC 0x3d3f
#define USB_SERIAL 1
#define USB_RESTART 2
#define USB_DMESG 3
struct UsbPacket {
uint16_t size;
uint16_t msgcount;
uint16_t magic;
uint16_t code;
char buf[1024 - 8];
};
void *usbThread(void *) {
UsbPacket pkt;
UsbPacket resp;
while (true) {
int len = read(usbFD, &pkt, sizeof(pkt));
if (len <= 4) {
sleep_core_us(20000);
continue;
}
resp.msgcount = pkt.msgcount;
if (pkt.magic == USB_MAGIC) {
if (pkt.code == USB_RESTART) {
target_reset();
} else if (pkt.code == USB_DMESG) {
dumpDmesg();
}
/*
resp.magic = pkt.magic;
resp.code = pkt.code;
resp.size = 8;
write(usbFD, &resp, sizeof(resp));
*/
} else {
resp.magic = 0xffff;
resp.size = 4;
write(usbFD, &resp, sizeof(resp));
}
sleep_core_us(1000);
}
}
static void startUsb() {
usbFD = open("/dev/lms_usbdev", O_RDWR, 0666);
pthread_t pid;
pthread_create(&pid, NULL, usbThread, NULL);
pthread_detach(pid);
}
static void *exitThread(void *) {
int fd = open("/dev/lms_ui", O_RDWR, 0666);
if (fd < 0)
return 0;
uint8_t *data =
(uint8_t *)mmap(NULL, NUM_BUTTONS, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
close(fd);
return 0;
}
for (;;) {
if (data[5])
target_reset();
sleep_core_us(50000);
}
}
static void startExitThread() {
pthread_t pid;
pthread_create(&pid, NULL, exitThread, NULL);
pthread_detach(pid);
}
void sendUsb(uint16_t code, const char *data, int len) {
while (len > 0) {
int sz = len;
if (sz > 1000)
sz = 1000;
UsbPacket pkt = {(uint16_t)(6 + sz), 0, USB_MAGIC, code, {}};
memcpy(pkt.buf, data, sz);
write(usbFD, &pkt, sizeof(pkt));
len -= sz;
data += sz;
}
}
void sendSerial(const char *data, int len) {
sendUsb(USB_SERIAL, data, len);
}
int lmsPid;
void stopLMS() {
struct dirent *ent;
DIR *dir;
dir = opendir("/proc");
if (dir == NULL)
return;
while ((ent = readdir(dir)) != NULL) {
int pid = atoi(ent->d_name);
if (!pid)
continue;
char namebuf[100];
snprintf(namebuf, 100, "/proc/%d/cmdline", pid);
FILE *f = fopen(namebuf, "r");
if (f) {
fread(namebuf, 1, 99, f);
if (strcmp(namebuf, "./lms2012") == 0) {
lmsPid = pid;
}
fclose(f);
if (lmsPid)
break;
}
}
closedir(dir);
lmsPid = 0; // disable SIGSTOP for now - rethink if problems with I2C (runs on a thread)
if (lmsPid) {
DMESG("SIGSTOP to lmsPID=%d", lmsPid);
if (kill(lmsPid, SIGSTOP))
DMESG("SIGSTOP failed");
}
}
void runLMS() {
DMESG("re-starting LMS2012");
kill(lmsPid, SIGCONT);
sleep_core_us(200000);
exit(0);
/*
chdir("/home/root/lms2012/sys");
for (int fd = 3; fd < 9999; ++fd)
close(fd);
execl("lms2012", "./lms2012");
exit(100); // should not be reached
*/
}
void stopMotors() {
uint8_t cmd[3] = {opOutputStop, 0x0F, 0};
int fd = open("/dev/lms_pwm", O_RDWR);
write(fd, cmd, 3);
close(fd);
}
void stopProgram() {
uint8_t cmd[1] = {opOutputProgramStop};
int fd = open("/dev/lms_pwm", O_RDWR);
write(fd, cmd, 1);
close(fd);
}
extern "C" void target_reset() {
tryLockUser();
stopMotors();
stopProgram();
if (lmsPid)
runLMS();
else
exit(0);
}
void target_exit() {
target_reset();
}
void target_startup() {
stopLMS();
startUsb();
startExitThread();
}
void initKeys() {}
static const char *progPath = "/mnt/ramdisk/prjs/BrkProg_SAVE";
// These are disabled except when building File_manager.pdf
// %
void deletePrjFile(String filename) {
const char *d = filename->getUTF8Data();
if (strlen(d) > 500 || strchr(d, '/'))
return;
char buf[1024];
snprintf(buf, sizeof(buf), "%s/%s", progPath, d);
unlink(buf);
}
// %
RefCollection *listPrjFiles() {
auto res = Array_::mk();
registerGCObj(res);
auto dp = opendir(progPath);
for (;;) {
dirent *ep = dp ? readdir(dp) : NULL;
if (!ep)
break;
if (ep->d_name[0] == '.')
continue;
auto str = mkString(ep->d_name, -1);
registerGCObj(str);
res->head.push((TValue)str);
unregisterGCObj(str);
}
if (dp)
closedir(dp);
unregisterGCObj(res);
return res;
}
}

View File

@@ -1,3 +1 @@
#define PXT_GC_THREAD_LIST 1 // leave empty
#define PXT_IN_ISR() false

View File

@@ -11,7 +11,6 @@ int allocateNotifyEvent();
void sleep_core_us(uint64_t us); void sleep_core_us(uint64_t us);
void startUser(); void startUser();
void stopUser(); void stopUser();
int tryLockUser();
class Button; class Button;
typedef Button *Button_; typedef Button *Button_;
@@ -28,13 +27,9 @@ class MMap : public RefObject {
MMap(); MMap();
void destroy(); void destroy();
void print(); void print();
static void scan(MMap *);
static unsigned gcsize(MMap *);
}; };
extern volatile bool paniced; extern volatile bool paniced;
void target_exit();
// Buffer, Sound, and Image share representation. // Buffer, Sound, and Image share representation.
typedef Buffer Sound; typedef Buffer Sound;

View File

@@ -26,19 +26,11 @@
"icons.jres", "icons.jres",
"ns.ts", "ns.ts",
"platform.h", "platform.h",
"platform.cpp",
"dmesg.cpp",
"integrator.ts" "integrator.ts"
], ],
"testFiles": [ "testFiles": [
"test.ts" "test.ts"
], ],
"dalDTS": {
"includeDirs": [
"pxtapp"
]
},
"additionalFilePath": "../../node_modules/pxt-common-packages/libs/core---linux",
"npmDependencies": {}, "npmDependencies": {},
"public": true, "public": true,
"dependencies": { "dependencies": {

16
libs/core/pxtcore.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef __PXTCORE_H
#define __PXTCORE_H
#include <stdio.h>
namespace pxt {
void dmesg(const char *fmt, ...);
#define DMESG pxt::dmesg
}
static inline void itoa(int v, char *dst) {
snprintf(dst, 30, "%d", v);
}
#endif

View File

@@ -85,9 +85,10 @@ void updateScreen(Image_ img) {
lastImg = img; lastImg = img;
} }
if (lastImg && mappedFrameBuffer != MAP_FAILED) { if (lastImg && lastImg->isDirty() && mappedFrameBuffer != MAP_FAILED) {
if (lastImg->bpp() != 1 || lastImg->width() != LCD_WIDTH || lastImg->height() != LCD_HEIGHT) if (lastImg->bpp() != 1 || lastImg->width() != LCD_WIDTH || lastImg->height() != LCD_HEIGHT)
target_panic(906); target_panic(906);
lastImg->clearDirty();
bitBufferToFrameBufferSwap(lastImg->pix(), mappedFrameBuffer); bitBufferToFrameBufferSwap(lastImg->pix(), mappedFrameBuffer);
} }
} }

View File

@@ -25,8 +25,8 @@ struct hci_dev_list_req {
hci_dev_req dev_req[2]; hci_dev_req dev_req[2];
}; };
static uint64_t bt_addr() { static uint32_t bt_addr() {
uint64_t res = -1; uint32_t res = -1;
int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
if (fd < 0) { if (fd < 0) {
@@ -50,8 +50,11 @@ static uint64_t bt_addr() {
goto done; goto done;
} }
res = 0; memcpy(&res, di.bdaddr, 4);
memcpy(&res, di.bdaddr, 6); res *= 0x1000193;
res += di.bdaddr[4];
res *= 0x1000193;
res += di.bdaddr[5];
done: done:
close(fd); close(fd);
@@ -60,10 +63,14 @@ done:
namespace pxt { namespace pxt {
uint64_t getLongSerialNumber() { int getSerialNumber() {
static uint64_t serial; static int serial;
if (serial == 0)
serial = bt_addr(); if (serial != 0)
return serial;
serial = bt_addr() & 0x7fffffff;
return serial; return serial;
} }

View File

@@ -68,12 +68,6 @@ declare namespace control {
/** Write data to DMESG debugging buffer. */ /** Write data to DMESG debugging buffer. */
//% shim=control::dmesg //% shim=control::dmesg
function dmesg(s: string): void; function dmesg(s: string): void;
/**
* Determines if the USB has been enumerated.
*/
//% shim=control::isUSBInitialized
function isUSBInitialized(): boolean;
} }
declare namespace serial { declare namespace serial {

View File

@@ -1,13 +0,0 @@
namespace brick {
/**
* Exits the program to the main menu. (in the simulator restarts it)
*/
//% blockId=loopstop block="exit program"
//% help=reference/brick/exit-program
//% weight=10
//% blockGap=8
//% group="Buttons"
export function exitProgram() {
control.reset();
}
}

View File

@@ -20,7 +20,7 @@ namespace console._screen {
lines = []; lines = [];
console.addListener(log); console.addListener(log);
brick.buttonUp.onEvent(ButtonEvent.Bumped, () => scroll(-3)) brick.buttonUp.onEvent(ButtonEvent.Bumped, () => scroll(-3))
brick.buttonDown.onEvent(ButtonEvent.Bumped, () => scroll(3)) brick.buttonDown.onEvent(ButtonEvent.Bumped, () => scroll(3))
} }
} }
@@ -44,7 +44,7 @@ namespace console._screen {
printLog(); printLog();
} }
function log(priority: ConsolePriority, msg: string): void { function log(msg: string): void {
lines.push(msg); lines.push(msg);
if (lines.length + 5 > maxLines) { if (lines.length + 5 > maxLines) {
lines.splice(0, maxLines - lines.length); lines.splice(0, maxLines - lines.length);

View File

@@ -1,6 +1,6 @@
//% color="#68C3E2" weight=100 icon="\uf106" //% color="#68C3E2" weight=100 icon="\uf106"
//% groups='["Buttons", "Screen", "Power"]' //% groups='["Buttons", "Screen", "Battery"]'
//% labelLineWidth=60 //% labelLineWidth=60
namespace brick { namespace brick {
} }

View File

@@ -2,9 +2,8 @@
"name": "ev3", "name": "ev3",
"description": "The EV3 library", "description": "The EV3 library",
"files": [ "files": [
"README.md", "README.md",
"ns.ts", "ns.ts",
"brick.ts",
"startup.ts", "startup.ts",
"images.jres", "images.jres",
"images.ts", "images.ts",

View File

@@ -1,6 +1,10 @@
// This is the last thing executed before user code // This is the last thing executed before user code
console.addListener(function(priority: ConsolePriority, msg: string) { console.addListener(function(msg: string) {
control.dmesg(msg.substr(0, msg.length - 1)) control.dmesg(msg.substr(0, msg.length - 1))
}) })
// boot sequence // pulse green, play startup sound, turn off light
brick.showBoot(); brick.setStatusLight(StatusLight.GreenPulse);
// We pause for 100ms to give time to read sensor values, so they work in on_start block
pause(400)
// and we're ready
brick.setStatusLight(StatusLight.Off);

View File

@@ -1,10 +0,0 @@
namespace image {
/**
* Get the screen image
*/
//%
export function screenImage(): Image {
return screen;
}
}

View File

@@ -15,7 +15,7 @@ declare interface Image {
height: int32; height: int32;
/** /**
* True if the image is monochromatic (black and white) * True iff the image is monochromatic (black and white)
*/ */
//% property shim=ImageMethods::isMono //% property shim=ImageMethods::isMono
isMono: boolean; isMono: boolean;
@@ -45,18 +45,6 @@ declare interface Image {
//% shim=ImageMethods::fill //% shim=ImageMethods::fill
fill(c: int32): void; fill(c: int32): void;
/**
* Copy row(s) of pixel from image to buffer (8 bit per pixel).
*/
//% shim=ImageMethods::getRows
getRows(x: int32, dst: Buffer): void;
/**
* Copy row(s) of pixel from buffer to image.
*/
//% shim=ImageMethods::setRows
setRows(x: int32, src: Buffer): void;
/** /**
* Return a copy of the current image * Return a copy of the current image
*/ */

View File

@@ -129,8 +129,8 @@ namespace brick {
screenMode = ScreenMode.Ports; screenMode = ScreenMode.Ports;
renderPorts(); renderPorts();
control.runInParallel(function () { control.runInParallel(function() {
while (screenMode == ScreenMode.Ports) { while(screenMode == ScreenMode.Ports) {
renderPorts(); renderPorts();
pause(50); pause(50);
} }
@@ -140,18 +140,8 @@ namespace brick {
function renderPorts() { function renderPorts() {
const col = 44; const col = 44;
const lineHeight8 = image.font8.charHeight + 2; const lineHeight8 = image.font8.charHeight + 2;
const h = screen.height;
clearScreen(); clearScreen();
for (let i = 0; i < 4; ++i) {
const x = i * col + 2;
screen.print("ABCD"[i], x, 1 * lineHeight8, 1, image.font8)
screen.print((i + 1).toString(), x, h - lineHeight8, 1, image.font8)
}
screen.drawLine(0, 5 * lineHeight8, screen.width, 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) {
const k = Math.floor(x / 1000); const k = Math.floor(x / 1000);
@@ -165,38 +155,27 @@ namespace brick {
const datas = motors.getAllMotorData(); const datas = motors.getAllMotorData();
for (let i = 0; i < datas.length; ++i) { for (let i = 0; i < datas.length; ++i) {
const data = datas[i]; const data = datas[i];
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) const x = i * col;
screen.print(`${scale(data.count)}>`, x, 4 * lineHeight8, 1, image.font8) screen.print("ABCD"[i], x + 2, 1 * lineHeight8, 1, image.font8)
screen.print(`${scale(data.actualSpeed)}%`, x + 2, 3 * lineHeight8, 1, image.font8)
screen.print(`${scale(data.count)}>`, x + 2, 4 * lineHeight8, 1, image.font8)
} }
screen.drawLine(0, 5 * lineHeight8, screen.width, 5 * lineHeight8, 1);
// sensors // sensors
const sis = sensors.internal.getActiveSensors(); const sis = sensors.internal.getActiveSensors();
const h = screen.height;
screen.drawLine(0, h - 5 * lineHeight8, screen.width, h - 5 * lineHeight8, 1)
for (let i = 0; i < sis.length; ++i) { for (let i = 0; i < sis.length; ++i) {
const si = sis[i]; const si = sis[i];
const x = (si.port() - 1) * col + 2; const x = (si.port() - 1) * col;
const inf = si._info(); const inf = si._info();
if (inf) screen.print(si.port() + "", x, h - 4 * lineHeight8, 1, image.font8)
screen.print(inf, x, h - 2 * lineHeight8, 1, inf.length > 4 ? image.font5 : image.font8); screen.print(inf, x, h - 2 * lineHeight8, 1, inf.length > 4 ? image.font5 : image.font8);
} }
} }
export function showBoot() {
// pulse green, play startup sound, turn off light
brick.setStatusLight(StatusLight.GreenPulse);
// We pause for 100ms to give time to read sensor values, so they work in on_start block
pause(400)
// and we're ready
brick.setStatusLight(StatusLight.Off);
// always show port by default if no UI is set
control.runInParallel(function () {
// show ports if nothing is has been shown
if (screenMode != ScreenMode.None) return;
showPorts();
})
}
/** /**
* An image * An image
* @param image the image * @param image the image

View File

@@ -1,13 +1,12 @@
{ {
"name": "pxt-ev3", "name": "pxt-ev3",
"version": "1.4.18", "version": "1.2.22",
"description": "LEGO MINDSTORMS EV3 for Microsoft MakeCode", "description": "LEGO MINDSTORMS EV3 for Microsoft MakeCode",
"private": false, "private": false,
"keywords": [ "keywords": [
"JavaScript", "JavaScript",
"education", "education",
"LEGO", "lego",
"EV3",
"pxt", "pxt",
"MakeCode", "MakeCode",
"Microsoft" "Microsoft"
@@ -33,20 +32,15 @@
], ],
"devDependencies": { "devDependencies": {
"typescript": "2.6.1", "typescript": "2.6.1",
"react": "16.8.3",
"semantic-ui-less": "2.2.14", "semantic-ui-less": "2.2.14",
"@types/bluebird": "2.0.33", "@types/bluebird": "2.0.33",
"@types/marked": "0.3.0", "@types/marked": "0.3.0",
"@types/node": "8.0.53", "@types/node": "8.0.53",
"webfonts-generator": "^0.4.0", "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"
}, },
"dependencies": { "dependencies": {
"pxt-common-packages": "6.16.37", "pxt-common-packages": "0.23.61",
"pxt-core": "5.30.21" "pxt-core": "4.0.11"
}, },
"scripts": { "scripts": {
"test": "node node_modules/pxt-core/built/pxt.js travis" "test": "node node_modules/pxt-core/built/pxt.js travis"

View File

@@ -22,7 +22,7 @@
], ],
"simulator": { "simulator": {
"autoRun": true, "autoRun": true,
"autoRunLight": false, "streams": true,
"aspectRatio": 0.5, "aspectRatio": 0.5,
"parts": false, "parts": false,
"enableTrace": true, "enableTrace": true,
@@ -37,10 +37,7 @@
"publishing": true, "publishing": true,
"importing": true, "importing": true,
"preferredPackages": [], "preferredPackages": [],
"githubPackages": true, "githubPackages": true
"cloudProviders": {
"github": {}
}
}, },
"compile": { "compile": {
"isNative": true, "isNative": true,
@@ -53,16 +50,15 @@
"flashCodeAlign": 256, "flashCodeAlign": 256,
"floatingPoint": true, "floatingPoint": true,
"taggedInts": true, "taggedInts": true,
"stackAlign": 2, "stackAlign": 2
"gc": true
}, },
"serial": { "serial": {
"vendorId": "0x0694", "vendorId": "0x0694",
"productId": "0x0005", "productId": "0x0005",
"rawHID": true, "rawHID": true,
"useEditor": true, "useEditor": true,
"log": true "log": true
}, },
"runtime": { "runtime": {
"mathBlocks": true, "mathBlocks": true,
"loopsBlocks": true, "loopsBlocks": true,
@@ -76,9 +72,7 @@
"onStartColor": "#58AB41", "onStartColor": "#58AB41",
"pauseUntilBlock": { "pauseUntilBlock": {
"category": "loops" "category": "loops"
}, }
"bannedCategories": [
]
}, },
"compileService": { "compileService": {
"buildEngine": "dockermake", "buildEngine": "dockermake",
@@ -88,7 +82,7 @@
"appTheme": { "appTheme": {
"accentColor": "#0089BF", "accentColor": "#0089BF",
"logoWide": true, "logoWide": true,
"logoUrl": "https://education.lego.com/", "logoUrl": "https://education.lego.com/",
"logo": "./static/lego_education_logo.png", "logo": "./static/lego_education_logo.png",
"docsLogo": "./static/lego_education_logo.png", "docsLogo": "./static/lego_education_logo.png",
"portraitLogo": "./static/lego_education_logo.png", "portraitLogo": "./static/lego_education_logo.png",
@@ -157,12 +151,6 @@
"usbHelp": [], "usbHelp": [],
"extendEditor": true, "extendEditor": true,
"extendFieldEditors": true, "extendFieldEditors": true,
"scriptManager": true,
"importExtensionFiles": true,
"experiments": [
"python",
"alwaysGithubItemBlocks"
],
"disableBlockIcons": true, "disableBlockIcons": true,
"blocklyOptions": { "blocklyOptions": {
"grid": { "grid": {
@@ -198,12 +186,7 @@
"editor.background": "#f9f9f9" "editor.background": "#f9f9f9"
}, },
"fileNameExclusiveFilter": "[^a-zA-Z0-9]", "fileNameExclusiveFilter": "[^a-zA-Z0-9]",
"qrCode": true,
"shareFinishedTutorials": true,
"nameProjectFirst": true,
"alwaysGithubItem": true,
"enableTrace": true "enableTrace": true
}, },
"ignoreDocsErrors": true, "ignoreDocsErrors": true
"uploadDocs": true }
}

View File

@@ -1,97 +0,0 @@
//% shim=pxt::listPrjFiles
function getPrjs() {
let programs = [
"pxt",
"my amazing robot",
]
for (let i = 1; i < 6; ++i)
programs.push("Untitled-" + i)
return programs
}
//% shim=pxt::deletePrjFile
function delPrj(fn: string) {
return
}
const programs = getPrjs()
.filter(s => s.substr(s.length - 4, 4) == ".rbf")
.map(s => s.substr(0, s.length - 4))
.filter(s => s != "File_manager")
programs.push("")
programs.push("Cancel")
programs.push("Delete 0 files")
let todel: boolean[] = []
let scrollTop = 0
let cursor = 0
let confirm = false
function showMenu() {
if (cursor < scrollTop + 2)
scrollTop = cursor - 2
else if (cursor > scrollTop + 11)
scrollTop = cursor - 11
if (scrollTop < 0)
scrollTop = 0
let num = 0
for (let i = 0; i < todel.length; ++i)
if (todel[i]) num++
programs[programs.length - 1] =
confirm ? "Enter to confirm" : "Delete " + num + " file(s)"
brick.clearScreen()
const h = brick.lineHeight()
for (let i = 0; i < 13; ++i) {
const y = i * h
const idx = scrollTop + i
const fg = idx == cursor ? 0 : 1
const bg = idx == cursor ? 1 : 0
// screen.fillRect(0, y, screen.width, h, bg);
let text = (idx == cursor ? ">" : " ")
+ (todel[idx] ? "*" : " ")
+ " "
+ (programs[scrollTop + i] || "")
screen.print(text, 0, y, fg, brick.font);
}
}
function move(d: number) {
confirm = false
const nc = cursor + d
if (0 <= nc && nc < programs.length)
cursor = nc
showMenu()
}
brick.buttonDown.onEvent(ButtonEvent.Pressed, () => move(1))
brick.buttonUp.onEvent(ButtonEvent.Pressed, () => move(-1))
brick.buttonEnter.onEvent(ButtonEvent.Pressed, function () {
if (cursor < programs.length - 3) {
todel[cursor] = !todel[cursor]
move(1)
} else if (cursor == programs.length - 3) {
// nothing
} else if (cursor == programs.length - 2) {
control.reset()
} else if (cursor == programs.length - 1) {
if (todel.every(x => !x))
return
if (confirm) {
brick.clearScreen()
brick.showString("deleting...", 6)
for (let i = 0; i < todel.length; ++i) {
if (todel[i]) {
delPrj(programs[i] + ".elf")
delPrj(programs[i] + ".rbf")
}
}
pause(1000)
control.reset()
} else {
confirm = true
showMenu()
}
}
})
showMenu()

View File

@@ -5,7 +5,6 @@
namespace pxsim { namespace pxsim {
export class EV3Board extends CoreBoard { export class EV3Board extends CoreBoard {
viewHost: visuals.BoardHost;
view: SVGSVGElement; view: SVGSVGElement;
outputState: EV3OutputState; outputState: EV3OutputState;
@@ -84,8 +83,7 @@ namespace pxsim {
highContrast: msg.highContrast, highContrast: msg.highContrast,
light: msg.light light: msg.light
}; };
this.viewHost = new visuals.BoardHost(pxsim.visuals.mkBoardView({ const viewHost = new visuals.BoardHost(pxsim.visuals.mkBoardView({
boardDef,
visual: boardDef.visual, visual: boardDef.visual,
highContrast: msg.highContrast, highContrast: msg.highContrast,
light: msg.light light: msg.light
@@ -93,7 +91,7 @@ namespace pxsim {
document.body.innerHTML = ""; // clear children document.body.innerHTML = ""; // clear children
document.body.className = msg.light ? "light" : ""; document.body.className = msg.light ? "light" : "";
document.body.appendChild(this.view = this.viewHost.getView() as SVGSVGElement); document.body.appendChild(this.view = viewHost.getView() as SVGSVGElement);
this.inputNodes = []; this.inputNodes = [];
this.outputNodes = []; this.outputNodes = [];
@@ -104,8 +102,8 @@ namespace pxsim {
return Promise.resolve(); return Promise.resolve();
} }
screenshotAsync(width?: number): Promise<ImageData> { screenshot(): string {
return this.viewHost.screenshotAsync(width); return svg.toDataUri(new XMLSerializer().serializeToString(this.view));
} }
getBrickNode() { getBrickNode() {

View File

@@ -9,6 +9,7 @@ namespace pxsim {
private angle: number = 0; private angle: number = 0;
private tacho: number = 0; private tacho: number = 0;
private speed: number = 0; private speed: number = 0;
private polarity: number = 1; // -1, 1 or -1
private started: boolean; private started: boolean;
private speedCmd: DAL; private speedCmd: DAL;
@@ -30,7 +31,7 @@ namespace pxsim {
} }
getSpeed() { getSpeed() {
return Math.round(this.speed); return Math.round(this.speed * (!this._synchedMotor && this.polarity == 0 ? -1 : 1));
} }
getAngle() { getAngle() {
@@ -81,6 +82,16 @@ namespace pxsim {
return this.id == NodeType.LargeMotor; return this.id == NodeType.LargeMotor;
} }
setPolarity(polarity: number) {
// Either 1 or 255 (reverse)
/*
-1 : Motor will run backward
0 : Motor will run opposite direction
1 : Motor will run forward
*/
this.polarity = polarity;
}
reset() { reset() {
// not sure what reset does... // not sure what reset does...
} }

View File

@@ -119,7 +119,11 @@ namespace pxsim {
return 2; return 2;
} }
case DAL.opOutputPolarity: { case DAL.opOutputPolarity: {
console.error("opOutputPolarity not supported"); // reverse
const port = buf.data[1];
const polarity = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 2);
const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.setPolarity(polarity));
return 2; return 2;
} }
case DAL.opOutputSetType: { case DAL.opOutputSetType: {

View File

@@ -1,7 +1,7 @@
namespace pxsim.music { namespace pxsim.music {
export function fromWAV(buf: RefBuffer) { export function fromWAV(buf: RefBuffer) {
return buf return incr(buf)
} }
export function stopAllSounds() { export function stopAllSounds() {
@@ -13,7 +13,7 @@ namespace pxsim.SoundMethods {
let audio: HTMLAudioElement; let audio: HTMLAudioElement;
export function buffer(buf: RefBuffer) { export function buffer(buf: RefBuffer) {
return buf return incr(buf)
} }
export function play(buf: RefBuffer) { export function play(buf: RefBuffer) {

View File

@@ -176,7 +176,7 @@ namespace pxsim.visuals {
const dalBoard = board(); const dalBoard = board();
dalBoard.updateSubscribers.push(() => this.updateState()); dalBoard.updateSubscribers.push(() => this.updateState());
if (props && props.wireframe) if (props && props.wireframe)
U.addClass(this.element, "sim-wireframe"); svg.addClass(this.element, "sim-wireframe");
if (props && props.theme) if (props && props.theme)
this.updateTheme(); this.updateTheme();

View File

@@ -24,7 +24,7 @@ namespace pxsim.visuals {
protected buildDomCore() { protected buildDomCore() {
// Setup buttons // Setup buttons
this.buttons = this.btnids.map(n => this.content.getElementById(this.normalizeId(n)) as SVGElement); this.buttons = this.btnids.map(n => this.content.getElementById(this.normalizeId(n)) as SVGElement);
this.buttons.forEach(b => U.addClass(b, "sim-button")); this.buttons.forEach(b => svg.addClass(b, "sim-button"));
this.light = this.content.getElementById(this.normalizeId(BrickView.EV3_LIGHT_ID)) as SVGElement; this.light = this.content.getElementById(this.normalizeId(BrickView.EV3_LIGHT_ID)) as SVGElement;
} }

View File

@@ -24,9 +24,9 @@
"Design Engineering": "design-engineering", "Design Engineering": "design-engineering",
"Coding": "coding", "Coding": "coding",
"Maker": "maker", "Maker": "maker",
"Tutorial Videos": "videos" "Videos": "videos"
}, },
"electronManifest": { "electronManifest": {
"latest": "v1.2.26" "latest": "v1.1.22"
} }
} }

View File

@@ -16,10 +16,6 @@
/******************************* /*******************************
Add your custom CSS here Add your custom CSS here
*******************************/ *******************************/
.simframe.ui.embed {
background: transparent;
}
/* Open Sans font */ /* Open Sans font */
@font-face { @font-face {