Compare commits

..

26 Commits

Author SHA1 Message Date
348964c888 1.1.10 2019-08-28 22:43:42 -07:00
8b3461bebd Add exitThread() polling the exit button (#888)
* Add exitThread() polling the exit button

* Add missing includes

* Remove redundant code
2019-08-28 22:43:21 -07:00
e511630c2e Update README.md 2019-08-28 16:27:03 -07:00
db156d5df0 Update README.md 2019-08-28 16:24:55 -07:00
93c6975400 1.1.9 2019-08-28 16:21:41 -07:00
abc93dd7da Multi sensor fix (#887)
* more logging

* set uart mode all at once

* updated logging

* pr feedback
2019-08-28 16:21:06 -07:00
85cfc86bf8 1.1.8 2019-08-28 13:36:50 -07:00
b66d4f2d64 enable storage extension (#886)
* enable storage extension

* fix -beta
2019-08-28 13:36:23 -07:00
5843deab11 1.1.7 2019-08-28 11:39:18 -07:00
8d5edc38bb bump common version (#885) 2019-08-28 11:30:59 -07:00
0309e50058 1.1.6 2019-08-28 08:52:24 -07:00
aa40e7b169 Endprogram (#884)
* moving end program logic to c++

* typo

* always stop on reset
2019-08-28 08:52:01 -07:00
75cf8da396 1.1.5 2019-08-27 17:57:44 -07:00
Max
db9b6a995b IIC added (#870)
* IIC added

* Fixed bug with not detecting device
2019-08-27 17:57:21 -07:00
fb255edafe 1.1.4 2019-08-27 17:28:57 -07:00
f4c39f74e8 1.1.3 2019-08-27 17:05:49 -07:00
3e56e2c3e2 Rgb raw tuning of blocs (#883)
* refactor blocks

* make non-private
2019-08-27 17:05:16 -07:00
79b5f8cc88 Add rgb and reflection raw mods for color sensor (#876)
* Add reflection raw value

Add reflection raw value for color sensor

* update

* Combined rgbraw and refraw
2019-08-27 16:45:12 -07:00
312729142f 1.1.2 2019-08-27 16:42:36 -07:00
Max
5bd4aed0e1 Multiple sensors 2 (#877)
* Fixed -1 mode in libs

* Deleted todo
2019-08-27 16:34:55 -07:00
cfaa4ae3ef migrate build to travis 2019-08-27 16:29:18 -07:00
faa839d59f 1.1.1 2019-08-27 16:26:37 -07:00
630687bfce bump to 1.1 2019-08-27 16:26:19 -07:00
2b300a4094 Maximmasterr set settle (#882)
* Added set settle time

* updated blocks
2019-08-27 14:57:28 -07:00
5fb8c0de6e delete package-lock.json 2019-08-27 14:45:25 -07:00
1f65cd59a8 Fixes to "Line Following in Loop" Sample Solutions (#871)
Sample Solutions were wrong for both Methods of Line Following in a Loop
2019-08-27 14:27:20 -07:00
31 changed files with 661 additions and 5020 deletions

9
.travis.yml Normal file
View File

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

View File

@ -1,10 +1,8 @@
# LEGO® MINDSTORMS® Education EV3 for Microsoft MakeCode
[![Build Status](https://ci2.dot.net/buildStatus/icon?job=Private/pxt_project_rainbow/master/pxt-ev3_Push)](https://ci2.dot.net/job/Private/job/pxt_project_rainbow/job/master/job/pxt-ev3_Push/)
# LEGO® MINDSTORMS® Education EV3 for Microsoft MakeCode [![Build Status](https://travis-ci.org/microsoft/pxt-ev3.svg?branch=master)](https://travis-ci.org/microsoft/pxt-ev3)
This repo contains the editor target hosted at https://makecode.mindstorms.com
## Local Dev setup
## Local setup
These instructions assume familiarity with dev tools and languages.
@ -12,10 +10,6 @@ These instructions assume familiarity with dev tools and languages.
* install Docker; make sure `docker` command is in your `PATH`
* (optional) install [Visual Studio Code](https://code.visualstudio.com/)
In a common folder,
* clone https://github.com/Microsoft/pxt to ``pxt`` folder
* clone https://github.com/Microsoft/pxt-common-packages to ``pxt-common-packages`` folder
* clone https://github.com/Microsoft/pxt-ev3 to ``pxt-ev3`` folder
* go to ``pxt`` and run
@ -23,6 +17,18 @@ In a common folder,
npm install
```
* to run the local server,
```
pxt serve --cloud
```
## Local Dev setup
In the common folder,
* clone https://github.com/Microsoft/pxt to ``pxt`` folder
* clone https://github.com/Microsoft/pxt-common-packages to ``pxt-common-packages`` folder
* go to ``pxt-common-packages`` and run
```
@ -54,9 +60,6 @@ cd libs/core
pxt deploy
```
### Jenkins build
https://ci2.dot.net/job/Private/job/pxt_project_rainbow/job/master/
## License
MIT

View File

@ -190,12 +190,10 @@ if (true) {
```blocks
forever(function () {
while (true) {
sensors.color3.pauseUntilColorDetected(ColorSensorColor.Black)
while (sensors.color3.color() == ColorSensorColor.Black) {
motors.largeBC.steer(-30, 50)
}
while (true) {
sensors.color3.pauseUntilColorDetected(ColorSensorColor.White)
while (sensors.color3.color() == ColorSensorColor.White) {
motors.largeBC.steer(30, 50)
}
})
@ -209,11 +207,9 @@ Else the Color Sensor detects the color white, start motors ``B`` and ``C`` (dri
```blocks
forever(function () {
if (true) {
sensors.color3.pauseUntilColorDetected(ColorSensorColor.Black)
if (sensors.color3.color() == ColorSensorColor.Black) {
motors.largeBC.steer(-30, 50)
} else {
sensors.color3.pauseUntilColorDetected(ColorSensorColor.White)
motors.largeBC.steer(30, 50)
}
})

View File

@ -1,46 +1,9 @@
# Projects
```codecard
[
{
"name": "Getting Started",
"url": "/getting-started",
"imageUrl": "/static/lessons/firmware.png"
},
{
"name": "Tutorials",
"url": "/tutorials",
"imageUrl": "/static/tutorials/wake-up.png"
},
{
"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": "Videos",
"url": "/videos",
"imageUrl": "https://legoeducation.videomarketingplatform.co/27288170/35719444/5d009e5f93fbf479c2e5ed2bf87a7990/thumbnail.png"
}
]
```
Here are some cool projects that you can build with your @boardname@!
## See Also
## Basic
[Getting Started](/getting-started),
[Tutorials](/tutorials),
[Design Engineering](/design-engineering),
[Coding](/coding),
[Maker](/maker),
[Videos](/videos)
Basic projects to build with your EV3 Brick.
Coming soon.

View File

@ -1,35 +0,0 @@
# Projects
* [Getting Started](/getting-started)
* [Prepare](https://makecode.mindstorms.com/troubleshoot)
* [Try](/getting-started/try)
* [Use](/getting-started/use)
* [Tutorials](/tutorials)
* [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)
* [Run Motors](/tutorials/run-motors)
* [Touch to Run](/tutorials/touch-to-run)
* [Touch Sensor Values](/tutorials/touch-sensor-values)
* [What Color?](/tutorials/what-color)
* [Line Following](/tutorials/line-following)
* [Red Light, Green Light](/tutorials/redlight-greenlight)
* [Security Alert](/tutorials/security-alert)
* [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)
* [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

@ -33,7 +33,7 @@ export function initAsync() {
canHID = false
} else {
const forceHexDownload = /forceHexDownload/i.test(window.location.href);
if (pxt.BrowserUtils.isLocalHost() && pxt.Cloud.localToken && !forceHexDownload)
if (pxt.Cloud.isLocalHost() && pxt.Cloud.localToken && !forceHexDownload)
canHID = true
}

View File

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

View File

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

View File

@ -53,7 +53,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
this.arrow_.setAttributeNS('http://www.w3.org/1999/xlink',
'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI);
this.arrow2_ = <SVGImageElement>Blockly.utils.createSvgElement('image', {
this.arrow2_ = Blockly.utils.createSvgElement('image', {
'height': (this as any).arrowSize_ + 'px',
'width': (this as any).arrowSize_ + 'px'
});
@ -79,7 +79,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
},
this.fieldGroup_);
fieldX += 10; // size of first group.
this.textElement2_ = <SVGTextElement>Blockly.utils.createSvgElement('text',
this.textElement2_ = Blockly.utils.createSvgElement('text',
{
'class': (this as any).className_,
'x': fieldX,
@ -89,7 +89,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
this.fieldGroup_);
this.updateEditable();
(this.sourceBlock_ as Blockly.BlockSvg).getSvgRoot().appendChild(this.fieldGroup_);
this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_);
// Force a render.
this.render_();
this.size_.width = 0;
@ -99,7 +99,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
// Add second dropdown
if (this.shouldShowRect_()) {
this.box_ = <SVGRectElement>Blockly.utils.createSvgElement('rect', {
this.box_ = Blockly.utils.createSvgElement('rect', {
'rx': (Blockly.BlockSvg as any).CORNER_RADIUS,
'ry': (Blockly.BlockSvg as any).CORNER_RADIUS,
'x': 0,
@ -112,7 +112,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
'fill-opacity': 1
}, null);
this.fieldGroup_.insertBefore(this.box_, this.textElement_);
this.box2_ = <SVGRectElement>Blockly.utils.createSvgElement('rect', {
this.box2_ = Blockly.utils.createSvgElement('rect', {
'rx': (Blockly.BlockSvg as any).CORNER_RADIUS,
'ry': (Blockly.BlockSvg as any).CORNER_RADIUS,
'x': 0,
@ -149,9 +149,9 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
getFirstValueI11n(value: string) {
const firstValue = this.getFirstValue(value);
const motorOptions = {
'medium motor': lf("medium motor"),
'large motor': lf("large motor"),
'large motors': lf("large motors")
'medium motor': lf('medium motor'),
'large motor': lf('large motor'),
'large motors': lf('large motors')
}
return motorOptions[firstValue];
}
@ -233,8 +233,8 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
if (this.textElement2_) {
this.textElement2_.parentNode.appendChild(this.arrow2_);
}
if (this.sourceBlock_ && (<Blockly.BlockSvg>this.sourceBlock_).rendered) {
(<Blockly.BlockSvg>this.sourceBlock_).render();
if (this.sourceBlock_ && this.sourceBlock_.rendered) {
this.sourceBlock_.render();
this.sourceBlock_.bumpNeighbours_();
}
}
@ -311,12 +311,12 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
// First dropdown
// 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);
// Second dropdown, no need to translate. Only port numbers
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.updateWidth();
@ -401,7 +401,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
if (Blockly.DropDownDiv.hideIfOwner(this)) {
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.
Blockly.DropDownDiv.hideWithoutAnimation();
Blockly.DropDownDiv.clearContent();
@ -433,8 +433,8 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
vals[text] = value;
}
const currentFirst = this.getFirstValue(<string>this.value_);
const currentSecond = this.getSecondValue(<string>this.value_);
const currentFirst = this.getFirstValue(this.value_);
const currentSecond = this.getSecondValue(this.value_);
if (!this.isFirst_) {
options = opts[currentFirst];
@ -526,7 +526,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
Blockly.DropDownDiv.setColour(this.backgroundColour_, this.borderColour_);
// 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 bBox = { width: this.size_.width, height: this.size_.height };
width *= scale;
@ -538,7 +538,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
let secondaryX = primaryX;
let secondaryY = position.top;
// Set bounds to workspace; show the drop-down.
(Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode);
(Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode);
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
this.onHide_.bind(this));
@ -561,11 +561,10 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
* Callback for when the drop-down is hidden.
*/
protected onHide_() {
const content = Blockly.DropDownDiv.getContentDiv();
content.removeAttribute('role');
content.removeAttribute('aria-haspopup');
content.removeAttribute('aria-activedescendant');
content.style.width = '';
Blockly.DropDownDiv.content_.removeAttribute('role');
Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup');
Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant');
Blockly.DropDownDiv.getContentDiv().style.width = '';
if (this.isFirst_ && this.box_) {
this.box_.setAttribute('fill', this.sourceBlock_.getColour());
} else if (!this.isFirst_ && this.box2_) {

View File

@ -85,7 +85,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary());
// 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 };
bBox.width *= scale;
bBox.height *= scale;
@ -95,7 +95,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
let secondaryX = primaryX;
let secondaryY = position.top;
// Set bounds to workspace; show the drop-down.
(Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode);
(Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode);
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
this.onHide_.bind(this));

View File

@ -0,0 +1,97 @@
/// <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) {
this.updateSpeed(parseFloat(value));
// Update reporter
this.reporter.textContent = `${value}%`;
}
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_), '-100', '100', 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()), -100, 100);
if (isNaN(v)) {
v = 0;
}
const x = goog.math.clamp(parseFloat(this.getText()), -100, 100) / 100;
const theta = x * Math.PI / 2;
const cx = FieldTurnRatio.HALF;
const cy = FieldTurnRatio.HALF - 14;
const gamma = Math.PI - 2 * theta;
const r = FieldTurnRatio.RADIUS;
const alpha = 0.2 + Math.abs(x) * 0.5;
const x1 = 0;
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

@ -1,41 +0,0 @@
import jobs.generation.Utilities;
import jobs.generation.InternalUtilities;
def project = GithubProject
def projectName = "pxt-ev3"
[true, false].each { isPR ->
def newJobName = projectName
if (isPR) {
newJobName += "_PR"
} else {
newJobName += "_Push"
}
def newJob = job(newJobName) {
steps {
shell("chmod +x ./jenkins.sh")
shell("./jenkins.sh ${isPR}")
}
if (!isPR) {
wrappers {
credentialsBinding {
string("PXT_ACCESS_TOKEN", "pxt_access_token")
string("PXT_RELEASE_REPO", "pxt_release_repo_ev3")
string("CROWDIN_KEY", "pxt_crowdin_key")
}
}
}
}
Utilities.setMachineAffinity(newJob, "Ubuntu", "20161020")
InternalUtilities.standardJobSetup(newJob, project, isPR, "*/*")
if (isPR) {
Utilities.addGithubPRTrigger(newJob, "Default Testing")
} else {
Utilities.addGithubPushTrigger(newJob)
}
}

View File

@ -1,56 +0,0 @@
#!/usr/bin/env bash
# Set up NVM
export NVM_DIR="/home/dotnet-bot/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
nvm install 8
# Set up build environment variables
echo ---------- Setting build environment variables
echo Git branch: $GIT_BRANCH
echo isPR: $1
originRegex="^origin/.*"
branchRegex="^origin/\K.*(?=$)"
releaseBranchRegex="^(master|v\d+)$"
if [[ "$GIT_BRANCH" =~ $originRegex ]]; then
branchName=$(echo ${GIT_BRANCH} | grep -oP $branchRegex)
echo Setting TRAVIS_BRANCH to ${branchName}
export TRAVIS_BRANCH=${branchName}
else
echo Setting TRAVIS_BRANCH to $GIT_BRANCH
export TRAVIS_BRANCH=$GIT_BRANCH
fi
if [ "$1" == "false" ]; then
echo Setting TRAVIS_PULL_REQUEST to false
export TRAVIS_PULL_REQUEST=false
if [[ "$TRAVIS_BRANCH" =~ $releaseBranchRegex ]]; then
if [[ -z $PXT_RELEASE_REPO ]]; then
echo Cannot find release repo\; skipping tag checks
else
gitTag=$(git describe --tags --exact-match 2> /dev/null)
builtTag=$(git ls-remote --tags $PXT_RELEASE_REPO | grep -o "refs/tags/$gitTag$")
echo Current tag: $gitTag
echo Built tag: $builtTag
if [[ ! -z $gitTag && -z $builtTag ]]; then
echo Built tag not found\; building tag
echo Setting TRAVIS_BRANCH to $gitTag
export TRAVIS_BRANCH=$gitTag
echo Setting TRAVIS_TAG to $gitTag
export TRAVIS_TAG=$gitTag
else
echo Not a tag build
fi
fi
fi
fi
# Perform build
npm install
npm test

View File

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

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

@ -42,12 +42,6 @@ declare interface Buffer {
//% start.defl=0 length.defl=-1 shim=BufferMethods::shift
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.
*/
@ -78,13 +72,6 @@ declare namespace control {
*/
//% shim=control::createBuffer
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 {
@ -160,31 +147,7 @@ declare namespace control {
*
*/
//% shim=control::__log
function __log(prority: int32, 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;
/**
* Return true if profiling is enabled in the current build.
*/
//% shim=control::profilingEnabled
function profilingEnabled(): boolean;
function __log(text: string): void;
}
// Auto-generated. Do not edit. Really.

View File

@ -1,5 +1,5 @@
const enum ColorSensorMode {
None = -1,
None = 0,
//% block="reflected light intensity"
ReflectedLightIntensity = 0,
//% block="ambient light intensity"
@ -15,7 +15,9 @@ enum LightIntensityMode {
//% block="reflected light"
Reflected = ColorSensorMode.ReflectedLightIntensity,
//% block="ambient light"
Ambient = ColorSensorMode.AmbientLightIntensity
Ambient = ColorSensorMode.AmbientLightIntensity,
//% block="reflected light (raw)"
ReflectedRaw = ColorSensorMode.RefRaw
}
const enum ColorSensorColor {
@ -93,6 +95,8 @@ namespace sensors {
|| this.mode == ColorSensorMode.AmbientLightIntensity
|| this.mode == ColorSensorMode.ReflectedLightIntensity)
return this.getNumber(NumberFormat.UInt8LE, 0)
if (this.mode == ColorSensorMode.RefRaw || this.mode == ColorSensorMode.RgbRaw)
return this.getNumber(NumberFormat.UInt16LE, 0)
return 0
}
@ -114,7 +118,7 @@ namespace sensors {
_update(prev: number, curr: number) {
if (this.calibrating) return; // simply ignore data updates while calibrating
if (this.mode == ColorSensorMode.Color)
if (this.mode == ColorSensorMode.Color || this.mode == ColorSensorMode.RgbRaw || this.mode == ColorSensorMode.RefRaw)
control.raiseEvent(this._id, this._colorEventValue(curr));
else
this.thresholdDetector.setLevel(curr);
@ -179,6 +183,22 @@ namespace sensors {
return this.getNumber(NumberFormat.UInt8LE, 0)
}
/**
* Get the current raw rgb values from the color sensor.
* @param sensor the color sensor to query the request
*/
//% help=sensors/color-sensor/rgbraw
//% parts="colorsensor"
//% blockNamespace=sensors
//% this.fieldEditor="ports"
//% weight=98
//% group="Color Sensor"
//% blockGap=8
rgbRaw(): number[] {
this.setMode(ColorSensorMode.RgbRaw);
return [this.getNumber(NumberFormat.UInt16LE, 0), this.getNumber(NumberFormat.UInt16LE, 2), this.getNumber(NumberFormat.UInt16LE, 4)];
}
/**
* Registers code to run when the ambient light changes.
* @param condition the light condition
@ -229,7 +249,12 @@ namespace sensors {
//% group="Color Sensor"
light(mode: LightIntensityMode) {
this.setMode(<ColorSensorMode><number>mode)
return this.getNumber(NumberFormat.UInt8LE, 0)
switch(mode) {
case LightIntensityMode.ReflectedRaw:
return this.reflectedLightRaw();
default:
return this.getNumber(NumberFormat.UInt8LE, 0)
}
}
/**
@ -248,6 +273,15 @@ namespace sensors {
return this.light(LightIntensityMode.Reflected);
}
/**
* Gets the raw reflection light value
*/
//%
reflectedLightRaw(): number {
this.setMode(ColorSensorMode.RefRaw);
return this.getNumber(NumberFormat.UInt16LE, 0);
}
/**
* Set a threshold value
* @param condition the dark or bright light condition

View File

@ -159,12 +159,6 @@ namespace brick {
if (sl[i])
ret |= 1 << i
}
// this needs to be done in query(), which is run without the main JS execution mutex
// otherwise, while(true){} will lock the device
if (ret & DAL.BUTTON_ID_ESCAPE) {
motors.stopAll(); // ensuring that all motors are off
control.reset()
}
return ret
}

View File

@ -25,8 +25,17 @@ namespace sensors.internal {
})
}
export function bufferToString(buf: Buffer): string {
let s = ''
for (let i = 0; i < buf.length; i++)
s += String.fromCharCode(buf[i])
return s
}
let analogMM: MMap
let uartMM: MMap
let IICMM: MMap
let devcon: Buffer
let sensorInfos: SensorInfo[]
@ -36,11 +45,13 @@ namespace sensors.internal {
sensors: Sensor[]
connType: number
devType: number
iicid: string
constructor(p: number) {
this.port = p
this.connType = DAL.CONN_NONE
this.devType = DAL.DEVICE_TYPE_NONE
this.iicid = ''
this.sensors = []
}
}
@ -57,20 +68,21 @@ namespace sensors.internal {
uartMM = control.mmap("/dev/lms_uart", UartOff.Size, 0)
if (!uartMM) control.fail("no uart sensor")
forever(() => {
detectDevices()
pause(500)
})
IICMM = control.mmap("/dev/lms_iic", IICOff.Size, 0)
if (!IICMM) control.fail("no iic sensor")
for (let info_ of sensorInfos) {
let info = info_
unsafePollForChanges(500,
() => { return hashDevices(); },
(prev, curr) => { detectDevices();
});
sensorInfos.forEach(info => {
unsafePollForChanges(50, () => {
if (info.sensor) return info.sensor._query()
return 0
}, (prev, curr) => {
if (info.sensor) info.sensor._update(prev, curr)
})
}
})
}
@ -89,6 +101,15 @@ namespace sensors.internal {
//serial.writeLine("UART " + port + " / " + mode + " - " + info)
}
export function readIICID(port: number) {
const buf = output.createBuffer(IICStr.Size)
buf[IICStr.Port] = port
IICMM.ioctl(IO.IIC_READ_TYPE_INFO, buf)
const manufacturer = bufferToString(buf.slice(IICStr.Manufacturer, 8))
const sensorType = bufferToString(buf.slice(IICStr.SensorType, 8))
return manufacturer + sensorType;
}
export function getBatteryInfo(): { temp: number; current: number } {
init();
return {
@ -97,52 +118,87 @@ namespace sensors.internal {
}
}
function detectDevices() {
let conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS)
let numChanged = 0
function hashDevices(): number {
const conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS)
let r = 0;
for(let i = 0; i < conns.length; ++i) {
r = (r << 8 | conns[i]);
}
return r;
}
for (let info of sensorInfos) {
let newConn = conns[info.port]
if (newConn == info.connType)
continue
let nonActivated = 0;
function detectDevices() {
control.dmesg(`detect devices (${nonActivated} na)`)
const conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS)
let numChanged = 0;
const uartSensors: SensorInfo[] = [];
for (const sensorInfo of sensorInfos) {
const newConn = conns[sensorInfo.port]
if (newConn == sensorInfo.connType) {
// control.dmesg(`connection unchanged ${newConn} at ${sensorInfo.port}`)
continue;
}
numChanged++
info.connType = newConn
info.devType = DAL.DEVICE_TYPE_NONE
sensorInfo.connType = newConn
sensorInfo.devType = DAL.DEVICE_TYPE_NONE
if (newConn == DAL.CONN_INPUT_UART) {
control.dmesg(`new UART connection at ${info.port}`)
setUartMode(info.port, 0)
let uinfo = readUartInfo(info.port, 0)
info.devType = uinfo[TypesOff.Type]
control.dmesg(`UART type ${info.devType}`)
control.dmesg(`new UART connection at ${sensorInfo.port}`)
updateUartMode(sensorInfo.port, 0);
uartSensors.push(sensorInfo);
} else if (newConn == DAL.CONN_NXT_IIC) {
control.dmesg(`new IIC connection at ${sensorInfo.port}`)
sensorInfo.devType = DAL.DEVICE_TYPE_IIC_UNKNOWN
sensorInfo.iicid = readIICID(sensorInfo.port)
control.dmesg(`IIC ID ${sensorInfo.iicid.length}`)
} else if (newConn == DAL.CONN_INPUT_DUMB) {
control.dmesg(`new DUMB connection at ${info.port}`)
control.dmesg(`new DUMB connection at ${sensorInfo.port}`)
// TODO? for now assume touch
info.devType = DAL.DEVICE_TYPE_TOUCH
sensorInfo.devType = DAL.DEVICE_TYPE_TOUCH
} else if (newConn == DAL.CONN_NONE || newConn == 0) {
control.dmesg(`disconnect at ${info.port}`)
control.dmesg(`disconnect at port ${sensorInfo.port}`)
} else {
control.dmesg(`unknown connection type: ${newConn} at ${info.port}`)
control.dmesg(`unknown connection type: ${newConn} at ${sensorInfo.port}`)
}
}
if (numChanged == 0)
if (uartSensors.length > 0) {
setUartModes();
for (const sensorInfo of uartSensors) {
let uinfo = readUartInfo(sensorInfo.port, 0)
sensorInfo.devType = uinfo[TypesOff.Type]
control.dmesg(`UART type ${sensorInfo.devType}`)
}
}
if (numChanged == 0 && nonActivated == 0)
return
for (let si of sensorInfos) {
if (si.sensor && si.sensor._deviceType() != si.devType) {
si.sensor = null
}
if (si.devType != DAL.DEVICE_TYPE_NONE) {
// TODO figure out compiler problem when '|| null' is added here!
si.sensor = si.sensors.filter(s => s._deviceType() == si.devType)[0]
if (si.sensor == null) {
control.dmesg(`sensor not found for type=${si.devType} at ${si.port}`)
control.dmesg(`updating sensor status`)
nonActivated = 0;
for (const sensorInfo of sensorInfos) {
if (sensorInfo.devType == DAL.DEVICE_TYPE_IIC_UNKNOWN) {
sensorInfo.sensor = sensorInfo.sensors.filter(s => s._IICId() == sensorInfo.iicid)[0]
if (!sensorInfo.sensor) {
control.dmesg(`sensor not found for iicid=${sensorInfo.iicid} at ${sensorInfo.port}`)
nonActivated++;
} else {
control.dmesg(`sensor connected type=${si.devType} at ${si.port}`)
si.sensor._activated()
control.dmesg(`sensor connected iicid=${sensorInfo.iicid} at ${sensorInfo.port}`)
sensorInfo.sensor._activated()
}
} else if (sensorInfo.devType != DAL.DEVICE_TYPE_NONE) {
sensorInfo.sensor = sensorInfo.sensors.filter(s => s._deviceType() == sensorInfo.devType)[0]
if (!sensorInfo.sensor) {
control.dmesg(`sensor not found for type=${sensorInfo.devType} at ${sensorInfo.port}`)
nonActivated++;
} else {
control.dmesg(`sensor connected type=${sensorInfo.devType} at ${sensorInfo.port}`)
sensorInfo.sensor._activated()
}
}
}
control.dmesg(`detect devices done`)
}
export class Sensor extends control.Component {
@ -187,6 +243,10 @@ namespace sensors.internal {
_deviceType() {
return 0
}
_IICId() {
return ''
}
}
export class AnalogSensor extends Sensor {
@ -212,7 +272,6 @@ namespace sensors.internal {
_activated() {
this.realmode = 0
// uartReset(this.port) // TODO is it ever needed?
this._setMode(this.mode)
}
@ -243,6 +302,55 @@ namespace sensors.internal {
}
}
export class IICSensor extends Sensor {
protected mode: number // the mode user asked for
protected realmode: number // the mode the hardware is in
private readLength: number
constructor(port: number) {
super(port)
this.mode = 0
this.realmode = 0
this.readLength = 1;
}
_activated() {
this.realmode = 0
this._setMode(this.mode)
}
protected _setMode(m: number) {
let v = m | 0
this.mode = v
if (!this.isActive()) return
if (this.realmode != this.mode) {
this.realmode = v
setIICMode(this._port, this._deviceType(), v)
}
}
getBytes(): Buffer {
return getIICBytes(this.isActive() ? this._port : -1, this.readLength)
}
getNumber(fmt: NumberFormat, off: number) {
if (!this.isActive())
return 0
return getIICNumber(this.readLength, fmt, off, this._port)
}
transaction(deviceAddress: number, write: number[], read: number) {
this.readLength = read;
transactionIIC(this._port, deviceAddress, write, read)
}
_deviceType() {
return DAL.DEVICE_TYPE_IIC_UNKNOWN
}
}
export const iicsensor = new IICSensor(3)
function uartReset(port: number) {
if (port < 0) return
control.dmesg(`UART reset at ${port}`)
@ -267,6 +375,7 @@ namespace sensors.internal {
}
function uartClearChange(port: number) {
control.dmesg(`UART clear change`);
const UART_DATA_READY = 8
const UART_PORT_CHANGED = 1
while (true) {
@ -288,20 +397,43 @@ namespace sensors.internal {
}
}
function setUartModes() {
control.dmesg(`UART set modes`)
uartMM.ioctl(IO.UART_SET_CONN, devcon)
const ports: number[] = [];
for (let port = 0; port < DAL.NUM_INPUTS; ++port) {
if (devcon.getNumber(NumberFormat.Int8LE, DevConOff.Connection + port) == DAL.CONN_INPUT_UART) {
ports.push(port);
}
}
while (ports.length) {
const port = ports.pop();
const status = waitNonZeroUartStatus(port)
control.dmesg(`UART set mode ${status} at ${port}`);
}
}
function updateUartMode(port: number, mode: number) {
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.Type + port, 33)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Mode + port, mode)
}
function setUartMode(port: number, mode: number) {
const UART_PORT_CHANGED = 1
while (true) {
if (port < 0) return
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.Type + port, 33)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Mode + port, mode)
updateUartMode(port, mode);
uartMM.ioctl(IO.UART_SET_CONN, devcon)
let status = waitNonZeroUartStatus(port)
if (status & UART_PORT_CHANGED) {
control.dmesg(`UART clear changed at ${port}`)
uartClearChange(port)
} else {
break
control.dmesg(`UART status ${status}`);
break;
}
pause(10)
}
@ -322,6 +454,48 @@ namespace sensors.internal {
UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index + off)
}
export function setIICMode(port: number, type: number, mode: number) {
if (port < 0) return;
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Connection + port, DAL.CONN_NXT_IIC)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Type + port, type)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Mode + port, mode)
IICMM.ioctl(IO.IIC_SET_CONN, devcon)
}
export function transactionIIC(port: number, deviceAddress: number, writeBuf: number[], readLen: number) {
if (port < 0) return;
let iicdata = output.createBuffer(IICDat.Size)
iicdata.setNumber(NumberFormat.Int8LE, IICDat.Port, port)
iicdata.setNumber(NumberFormat.Int8LE, IICDat.Repeat, 0)
iicdata.setNumber(NumberFormat.Int16LE, IICDat.Time, 0)
iicdata.setNumber(NumberFormat.Int8LE, IICDat.WrLng, writeBuf.length + 1)
for (let i = 0; i < writeBuf.length; i++)
iicdata.setNumber(NumberFormat.Int8LE, IICDat.WrData + i + 1, writeBuf[i])
iicdata.setNumber(NumberFormat.Int8LE, IICDat.WrData, deviceAddress)
iicdata.setNumber(NumberFormat.Int8LE, IICDat.RdLng, readLen)
IICMM.ioctl(IO.IIC_SETUP, iicdata)
}
export function getIICBytes(port: number, length: number) {
if (port < 0) return output.createBuffer(length);
let index = IICMM.getNumber(NumberFormat.UInt16LE, IICOff.Actual + port * 2);
let buf = IICMM.slice(
IICOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index,
length
);
// Reverse
for (let i = 0; i < length / 2; i++) {
let c = buf[i]
buf[i] = buf[length - i - 1]
buf[length - i - 1] = c
}
return buf;
}
export function getIICNumber(length: number, format: NumberFormat, off: number, port: number) {
return getIICBytes(port, length).getNumber(format, off)
}
const enum NxtColOff {
Calibration = 0, // uint32[4][3]
@ -405,6 +579,52 @@ namespace sensors.internal {
Size = 58
}
const enum IICOff {
TypeData = 0, // Types[8][4]
Repeat = 1792, // uint16[300][4]
Raw = 4192, // int8[32][300][4]
Actual = 42592, // uint16[4]
LogIn = 42600, // uint16[4]
Status = 42608, // int8[4]
Output = 42612, // int8[32][4]
OutputLength = 42740, // int8[4]
Size = 42744
}
const enum IICCtlOff {
TypeData = 0, // Types
Port = 56, // int8
Mode = 57, // int8
Size = 58
}
const enum IICDat {
Result = 0, // result
Port = 4, // int8
Repeat = 5, // int8
Time = 6, // int16
WrLng = 8, // int8
WrData = 9, // int8[32]
RdLng = 41, // int8
RdData = 42, //int8[32]
Size = 74,
}
const enum IICStr {
Port = 0, // int8
Time = 2, // int16
Type = 4, // int8
Mode = 5, // int8
Manufacturer = 6, // int8[9]
SensorType = 15, // int[9]
SetupLng = 24, // int8
SetupString = 28, // ulong
PollLng = 32, // int8
PollString = 36, // ulong
ReadLng = 40, // int8
Size = 44
}
const enum IO {
UART_SET_CONN = 0xc00c7500,
UART_READ_MODE_INFO = 0xc03c7501,
@ -472,7 +692,7 @@ namespace sensors {
}
public threshold(t: ThresholdState): number {
switch(t) {
switch (t) {
case ThresholdState.High: return this.highThreshold;
case ThresholdState.Low: return this.lowThreshold;
default: return (this.max - this.min) / 2;
@ -512,5 +732,5 @@ namespace sensors {
break;
}
}
}
}
}

View File

@ -14,6 +14,9 @@
#include <errno.h>
#include <fcntl.h>
#include <malloc.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include "ev3const.h"
#define THREAD_DBG(...)
@ -144,6 +147,29 @@ static void startUsb() {
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;
@ -489,14 +515,22 @@ void runLMS() {
}
void stopMotors() {
uint8_t cmd[2] = { 0xA3, 0x0F };
uint8_t cmd[3] = {opOutputStop, 0x0F, 0};
int fd = open("/dev/lms_pwm", O_RDWR);
write(fd, cmd, 2);
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() {
stopMotors();
stopProgram();
if (lmsPid)
runLMS();
else
@ -510,6 +544,7 @@ void initRuntime() {
DMESG("runtime starting...");
stopLMS();
startUsb();
startExitThread();
pthread_t disp;
pthread_create(&disp, NULL, evtDispatcher, NULL);
pthread_detach(disp);

View File

@ -134,6 +134,7 @@ namespace motors {
protected _brake: boolean;
private _pauseOnRun: boolean;
private _initialized: boolean;
private _brakeSettleTime: number;
private _init: () => void;
private _run: (speed: number) => void;
private _move: (steps: boolean, stepsOrTime: number, speed: number) => void;
@ -147,6 +148,7 @@ namespace motors {
this._brake = false;
this._pauseOnRun = true;
this._initialized = false;
this._brakeSettleTime = 10;
this._init = init;
this._run = run;
this._move = move;
@ -204,6 +206,20 @@ namespace motors {
writePWM(b)
}
/**
* Set the settle time after braking in milliseconds (default is 10ms).
*/
//% blockId=motorSetBrakeSettleTime block="set %motor|brake settle time %millis|ms"
//% motor.fieldEditor="motors"
//% weight=1 blockGap=8
//% group="Properties"
//% millis.defl=200 millis.min=0 millis.max=500
setBrakeSettleTime(millis: number) {
this.init();
// ensure in [0,500]
this._brakeSettleTime = Math.max(0, Math.min(500, millis | 0))
}
/**
* Stops the motor(s).
*/
@ -221,8 +237,8 @@ namespace motors {
protected settle() {
// if we've recently completed a motor command with brake
// allow 500ms for robot to settle
if (this._brake)
pause(500);
if (this._brake && this._brakeSettleTime > 0)
pause(this._brakeSettleTime);
}
protected pauseOnRun(stepsOrTime: number) {
@ -396,7 +412,7 @@ namespace motors {
*/
//% blockId=outputMotorSetRegulated block="set %motor|regulated %value=toggleOnOff"
//% motor.fieldEditor="motors"
//% weight=58
//% weight=58 blockGap=8
//% group="Properties"
//% help=motors/motor/set-regulated
setRegulated(value: boolean) {
@ -749,3 +765,9 @@ namespace motors {
control.dmesg('end step')
}
}
interface Buffer {
[index: number]: number;
// rest defined in buffer.cpp
}

View File

@ -44,7 +44,7 @@ namespace console._screen {
printLog();
}
function log(priority: ConsolePriority, msg: string): void {
function log(msg: string): void {
lines.push(msg);
if (lines.length + 5 > maxLines) {
lines.splice(0, maxLines - lines.length);

View File

@ -1,5 +1,5 @@
const enum GyroSensorMode {
None = -1,
None = 0,
Angle = 0,
Rate = 1,
}

View File

@ -1,5 +1,5 @@
const enum InfraredSensorMode {
None = -1,
None = 0,
Proximity = 0,
Seek = 1,
RemoteControl = 2,

View File

@ -45,18 +45,6 @@ declare interface Image {
//% shim=ImageMethods::fill
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
*/

View File

@ -1,6 +1,6 @@
{
"name": "storage",
"description": "USB Pen-drive support and flash storage",
"description": "USB Pen-drive support and flash storage - beta",
"files": [
"storage.cpp",
"storage-core.ts",

4670
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
{
"name": "pxt-ev3",
"version": "1.1.0",
"version": "1.1.10",
"description": "LEGO MINDSTORMS EV3 for Microsoft MakeCode",
"private": true,
"private": false,
"keywords": [
"JavaScript",
"education",
@ -39,8 +39,8 @@
"webfonts-generator": "^0.4.0"
},
"dependencies": {
"pxt-common-packages": "6.4.13",
"pxt-core": "5.5.18"
"pxt-common-packages": "0.23.61",
"pxt-core": "4.0.9"
},
"scripts": {
"test": "node node_modules/pxt-core/built/pxt.js travis"

View File

@ -16,7 +16,8 @@
"libs/infrared-sensor",
"libs/gyro-sensor",
"libs/screen",
"libs/ev3"
"libs/ev3",
"libs/storage"
],
"simulator": {
"autoRun": true,

View File

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

View File

@ -27,6 +27,7 @@ namespace pxsim.sensors {
export function __sensorUsed(port: number, type: number) {
//console.log("SENSOR INIT " + port + ", type: " + type);
if (type == DAL.DEVICE_TYPE_IIC_UNKNOWN) return; // Ignore IIC
if (!ev3board().hasSensor(port)) {
const sensor = ev3board().getSensor(port, type);
runtime.queueDisplayUpdate();