diff --git a/.gitignore b/.gitignore index f31db3d8..755e65e8 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ clients/**/bin/** clients/**/obj/** clients/electron/projects libs/**/_locales/** +package-lock.json videos/** diff --git a/cmds/cmds.ts b/cmds/cmds.ts deleted file mode 100644 index 2084f8b5..00000000 --- a/cmds/cmds.ts +++ /dev/null @@ -1,14 +0,0 @@ -/// - -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" - }) - }) -} diff --git a/cmds/tsconfig.json b/cmds/tsconfig.json deleted file mode 100644 index 4ebfccad..00000000 --- a/cmds/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "noImplicitAny": true, - "noImplicitReturns": true, - "declaration": true, - "outDir": "../built", - "module": "commonjs", - "rootDir": ".", - "newLine": "LF", - "sourceMap": false, - "types": ["node"] - } -} diff --git a/docs/projects.md b/docs/projects.md index 7efe8e2e..c5a54b97 100644 --- a/docs/projects.md +++ b/docs/projects.md @@ -1,9 +1,88 @@ # Projects -Here are some cool projects that you can build with your @boardname@! +```codecard +[ + { + "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" + } +] +``` -## Basic +## See Also -Basic projects to build with your EV3 Brick. +[Getting Started](/getting-started), +[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. \ No newline at end of file diff --git a/docs/projects/SUMMARY.md b/docs/projects/SUMMARY.md new file mode 100644 index 00000000..d0d4ea0d --- /dev/null +++ b/docs/projects/SUMMARY.md @@ -0,0 +1,69 @@ +# 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) diff --git a/editor/deploy.ts b/editor/deploy.ts index 09a85db4..497676d6 100644 --- a/editor/deploy.ts +++ b/editor/deploy.ts @@ -3,20 +3,15 @@ import UF2 = pxtc.UF2; import { Ev3Wrapper } from "./wrap"; +import { bluetoothTryAgainAsync } from "./dialogs"; export let ev3: Ev3Wrapper; -let confirmAsync: (options: any) => Promise; - -export function setConfirmAsync(cf: (options: any) => Promise) { - confirmAsync = cf; -} export function debug() { return initHidAsync() .then(w => w.downloadFileAsync("/tmp/dmesg.txt", v => console.log(pxt.Util.uint8ArrayToString(v)))) } - // Web Serial API https://wicg.github.io/serial/ // chromium bug https://bugs.chromium.org/p/chromium/issues/detail?id=884928 // Under experimental features in Chrome Desktop 77+ @@ -167,7 +162,7 @@ export function initAsync(): Promise { useHID = false } else { const nodehid = /nodehid/i.test(window.location.href); - if (pxt.Cloud.isLocalHost() && pxt.Cloud.localToken && nodehid) + if (pxt.BrowserUtils.isLocalHost() && pxt.Cloud.localToken && nodehid) useHID = true; } @@ -283,22 +278,9 @@ export function deployCoreAsync(resp: pxtc.CompileResult) { return w.reconnectAsync(false) .catch(e => { // user easily forgets to stop robot - if (confirmAsync) - return confirmAsync({ - header: lf("Bluetooth download failed..."), - htmlBody: - `
    -
  • ${lf("Make sure to stop your program or exit portview on the EV3.")}
  • -
  • ${lf("Check your battery level.")}
  • -
  • ${lf("Close EV3 LabView or other MakeCode editor tabs.")} -
`, - hasCloseIcon: true, - hideCancel: true, - hideAgree: false, - agreeLbl: lf("Try again"), - }).then(() => w.disconnectAsync()) - .then(() => Promise.delay(1000)) - .then(() => w.reconnectAsync()); + bluetoothTryAgainAsync().then(() => w.disconnectAsync()) + .then(() => Promise.delay(1000)) + .then(() => w.reconnectAsync()); // nothing we can do return Promise.reject(e); diff --git a/editor/dialogs.tsx b/editor/dialogs.tsx new file mode 100644 index 00000000..cafedf34 --- /dev/null +++ b/editor/dialogs.tsx @@ -0,0 +1,145 @@ +import * as React from "react"; +import { canUseWebSerial, enableWebSerialAsync } from "./deploy"; +import { projectView } from "./extension"; + +let confirmAsync: (options: any) => Promise; + +export function bluetoothTryAgainAsync(): Promise { + return confirmAsync({ + header: lf("Bluetooth download failed..."), + jsx:
    +
  • {lf("Make sure to stop your program or exit portview on the EV3.")}
  • +
  • {lf("Check your battery level.")}
  • +
  • {lf("Close EV3 LabView or other MakeCode editor tabs.")}
  • +
, + 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 { + 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:

+ {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.")} +

+ }).then(() => { }) +} + +export function showUploadDialogAsync(fn: string, url: string, _confirmAsync: (options: any) => Promise): Promise { + 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 = +
+
+
{lf("First time here?")}
+ {lf("You must have version 1.10E or above of the firmware")} +
+ +
+ {lf("Check your firmware version here and update if needed")} +
+
+
+
+
+
+
+
+
+ +
+
+
+ 1 + {lf("Connect the EV3 to your computer with a USB cable")} +
+ {lf("Use the miniUSB port on the top of the EV3 Brick")} +
+
+
+
+
+
+
+ +
+
+
+ 2 + {lf("Move the .uf2 file to the EV3 Brick")} +
+ {lf("Locate the downloaded .uf2 file and drag it to the EV3 USB drive")} +
+
+
+
+
+
+
+
+
+
; + + 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(() => { }); +} \ No newline at end of file diff --git a/editor/extension.ts b/editor/extension.ts index 67817159..866a173e 100644 --- a/editor/extension.ts +++ b/editor/extension.ts @@ -1,144 +1,26 @@ +/// +/// +/// +/// /// /// -import { deployCoreAsync, initAsync, canUseWebSerial, enableWebSerialAsync, setConfirmAsync } from "./deploy"; +import { deployCoreAsync, initAsync } from "./deploy"; +import { showUploadDialogAsync } from "./dialogs"; + +export let projectView: pxt.editor.IProjectView; -let bluetoothDialogShown = false; pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise { - const projectView = opts.projectView; pxt.debug('loading pxt-ev3 target extensions...') - - function enableWebSerialAndCompileAsync() { - return enableWebSerialAsync() - .then(() => Promise.delay(500)) - .then(() => projectView.compile()); - } + projectView = opts.projectView; const res: pxt.editor.ExtensionResult = { - deployCoreAsync, - showUploadInstructionsAsync: (fn: string, url: string, confirmAsync: (options: any) => Promise) => { - 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 = ` -
-
-
${lf("First time here?")}
- ${lf("You must have version 1.10E or above of the firmware")} -
- -
- ${lf("Check your firmware version here and update if needed")} -
-
-
-
-
-
-
-
-
- -
-
-
- 1 - ${lf("Connect the EV3 to your computer with a USB cable")} -
- ${lf("Use the miniUSB port on the top of the EV3 Brick")} -
-
-
-
-
-
-
- -
-
-
- 2 - ${lf("Move the .uf2 file to the EV3 Brick")} -
- ${lf("Locate the downloaded .uf2 file and drag it to the EV3 USB drive")} -
-
-
-
-
-
-
-
-
-
`; - - 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: `

-${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.")} -

-` - }).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(() => { }); - } + deployAsync: deployCoreAsync, + showUploadInstructionsAsync: showUploadDialogAsync }; + initAsync().catch(e => { // probably no HID - we'll try this again upon deployment }) return Promise.resolve(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") diff --git a/editor/tsconfig.json b/editor/tsconfig.json index 35979843..6cdec447 100644 --- a/editor/tsconfig.json +++ b/editor/tsconfig.json @@ -1,14 +1,17 @@ { "compilerOptions": { "target": "es5", - "noImplicitAny": false, + "noImplicitAny": true, "noImplicitReturns": true, + "noImplicitThis": true, + "declaration": true, "module": "commonjs", + "moduleResolution": "node", + "isolatedModules": false, "outDir": "../built/editor", "rootDir": ".", "newLine": "LF", "sourceMap": false, - "allowSyntheticDefaultImports": true, - "declaration": true + "jsx": "react" } } \ No newline at end of file diff --git a/fieldeditors/extension.ts b/fieldeditors/extension.ts index c687c6c5..10944a73 100644 --- a/fieldeditors/extension.ts +++ b/fieldeditors/extension.ts @@ -3,9 +3,7 @@ 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"; @@ -19,15 +17,9 @@ 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 diff --git a/fieldeditors/field_brickbuttons.ts b/fieldeditors/field_brickbuttons.ts index f55ed62b..9e941db6 100644 --- a/fieldeditors/field_brickbuttons.ts +++ b/fieldeditors/field_brickbuttons.ts @@ -121,17 +121,17 @@ export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly. Blockly.DropDownDiv.setColour('#ffffff', '#dddddd'); // Calculate positioning based on the field position. - var scale = this.sourceBlock_.workspace.scale; - var bBox = { width: this.size_.width, height: this.size_.height }; + let scale = (this.sourceBlock_.workspace).scale; + let bBox = { width: this.size_.width, height: this.size_.height }; bBox.width *= scale; bBox.height *= scale; - var position = this.fieldGroup_.getBoundingClientRect(); - var primaryX = position.left + bBox.width / 2; - var primaryY = position.top + bBox.height; - var secondaryX = primaryX; - var secondaryY = position.top; + let position = this.fieldGroup_.getBoundingClientRect(); + let primaryX = position.left + bBox.width / 2; + let primaryY = position.top + bBox.height; + let secondaryX = primaryX; + let secondaryY = position.top; // Set bounds to workspace; show the drop-down. - (Blockly.DropDownDiv as any).setBoundsElement(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,9 +152,10 @@ export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly. * Callback for when the drop-down is hidden. */ private onHide_ = function () { - Blockly.DropDownDiv.content_.removeAttribute('role'); - Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup'); - Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant'); - Blockly.DropDownDiv.getContentDiv().style.width = ''; + const content = Blockly.DropDownDiv.getContentDiv(); + content.removeAttribute('role'); + content.removeAttribute('aria-haspopup'); + content.removeAttribute('aria-activedescendant'); + (content as HTMLElement).style.width = ''; }; } \ No newline at end of file diff --git a/fieldeditors/field_color.ts b/fieldeditors/field_color.ts index 778f6811..857f0677 100644 --- a/fieldeditors/field_color.ts +++ b/fieldeditors/field_color.ts @@ -44,7 +44,7 @@ export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Block * @return {string} Current colour in '#rrggbb' format. */ getValue(opt_asHex?: boolean) { - var colour = this.mapColour(this.colour_); + const colour = this.mapColour(this.value_); if (!opt_asHex && colour.indexOf('#') > -1) { 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. */ setValue(colorStr: string) { - var colour = this.mapEnum(colorStr); + let colour = this.mapEnum(colorStr); if (this.sourceBlock_ && Blockly.Events.isEnabled() && - this.colour_ != colour) { + this.value_ != colour) { Blockly.Events.fire(new (Blockly as any).Events.BlockChange( - this.sourceBlock_, 'field', this.name, this.colour_, colour)); + this.sourceBlock_, 'field', this.name, this.value_, colour)); } - this.colour_ = colour; + this.value_ = colour; if (this.sourceBlock_) { this.sourceBlock_.setColour(colour, colour, colour); } diff --git a/fieldeditors/field_motors.ts b/fieldeditors/field_motors.ts index a9212afd..4e5587ad 100644 --- a/fieldeditors/field_motors.ts +++ b/fieldeditors/field_motors.ts @@ -46,31 +46,31 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC (this as any).arrowX_ = 0; /** @type {Number} */ this.arrowY_ = 11; - this.arrow_ = Blockly.utils.createSvgElement('image', { + this.arrow_ = Blockly.utils.dom.createSvgElement('image', { 'height': (this as any).arrowSize_ + 'px', 'width': (this as any).arrowSize_ + 'px' - }); + }, null); this.arrow_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI); - this.arrow2_ = Blockly.utils.createSvgElement('image', { + this.arrow2_ = Blockly.utils.dom.createSvgElement('image', { 'height': (this as any).arrowSize_ + 'px', 'width': (this as any).arrowSize_ + 'px' - }); + }, null); this.arrow2_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI); (this as any).className_ += ' blocklyDropdownText'; // Build the DOM. - this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null); + this.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); if (!this.visible_) { (this.fieldGroup_ as any).style.display = 'none'; } // Adjust X to be flipped for RTL. Position is relative to horizontal start of source block. - var size = this.getSize(); - var fieldX = (this.sourceBlock_.RTL) ? -size.width / 2 : size.width / 2; + let size = this.getSize(); + let fieldX = (this.sourceBlock_.RTL) ? -size.width / 2 : size.width / 2; /** @type {!Element} */ - this.textElement_ = Blockly.utils.createSvgElement('text', + this.textElement_ = Blockly.utils.dom.createSvgElement('text', { 'class': (this as any).className_, 'x': fieldX, @@ -79,7 +79,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC }, this.fieldGroup_); fieldX += 10; // size of first group. - this.textElement2_ = Blockly.utils.createSvgElement('text', + this.textElement2_ = Blockly.utils.dom.createSvgElement('text', { 'class': (this as any).className_, 'x': fieldX, @@ -89,17 +89,17 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC this.fieldGroup_); this.updateEditable(); - this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); + (this.sourceBlock_ as Blockly.BlockSvg).getSvgRoot().appendChild(this.fieldGroup_); // Force a render. this.render_(); - this.size_.width = 0; + this.isDirty_ = true; (this as any).mouseDownWrapper_ = Blockly.bindEventWithChecks_((this as any).getClickTarget_(), 'mousedown', this, (this as any).onMouseDown_); // Add second dropdown if (this.shouldShowRect_()) { - this.box_ = Blockly.utils.createSvgElement('rect', { + this.box_ = Blockly.utils.dom.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_ = Blockly.utils.createSvgElement('rect', { + this.box2_ = Blockly.utils.dom.createSvgElement('rect', { 'rx': (Blockly.BlockSvg as any).CORNER_RADIUS, 'ry': (Blockly.BlockSvg as any).CORNER_RADIUS, '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. - var text = this.text_; + let text = this.text_; this.text_ = null; this.setText(text); } @@ -179,7 +179,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC // Not rendered yet. return; } - var text = this.text_; + let text = this.text_; if (text.length > this.maxDisplayLength) { // Truncate displayed string and add an ellipsis ('...'). 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. text = Blockly.Field.NBSP; } - var textNode = document.createTextNode(text); + let textNode = document.createTextNode(text); this.textElement2_.appendChild(textNode); // Cached width is obsolete. Clear it. - this.size_.width = 0; + this.isDirty_ = true; }; patchDualMotorText(text: string) { @@ -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_ && this.sourceBlock_.rendered) { - this.sourceBlock_.render(); + if (this.sourceBlock_ && (this.sourceBlock_).rendered) { + (this.sourceBlock_).render(); this.sourceBlock_.bumpNeighbours_(); } } @@ -244,7 +244,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC return 0; } - var addedWidth = 0; + let addedWidth = 0; if (this.sourceBlock_.RTL) { (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; @@ -263,10 +263,10 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC return addedWidth; }; - updateWidth() { + updateSize_() { // Calculate width of field - var width = Blockly.Field.getCachedWidth(this.textElement_); - var width2 = Blockly.Field.getCachedWidth(this.textElement2_); + let width = Blockly.Field.getCachedWidth(this.textElement_); + let width2 = Blockly.Field.getCachedWidth(this.textElement2_); // Add padding to left and right of text. if (this.EDITABLE) { @@ -311,15 +311,15 @@ 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(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(this.value_)); + const textNode2 = document.createTextNode(this.getSecondValue(this.value_)); this.textElement2_.appendChild(textNode2); } - this.updateWidth(); + this.updateSize_(); // Update text centering, based on newly calculated width. 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. - var width = Blockly.Field.getCachedWidth(this.textElement_); - var newX = centerTextX - width / 2; + let width = Blockly.Field.getCachedWidth(this.textElement_); + let newX = centerTextX - width / 2; this.textElement_.setAttribute('x', `${newX}`); // 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. - var width2 = Blockly.Field.getCachedWidth(this.textElement2_); - var newX2 = centerTextX2 - width2 / 2; + let width2 = Blockly.Field.getCachedWidth(this.textElement2_); + let newX2 = centerTextX2 - width2 / 2; 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)) { return; } - this.isFirst_ = e.clientX - this.getScaledBBox_().left < ((this as any).width1 * 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(); @@ -411,14 +411,14 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC // Accessibility properties contentDiv.setAttribute('role', 'menu'); contentDiv.setAttribute('aria-haspopup', 'true'); - let options = this.getOptions(); + const foptions = this.getOptions(); // [img info, text] let opts = {}; let conts = {}; let vals = {}; // Go through all option values and split them into groups - for (let opt = 0; opt < options.length; opt++) { - const value = options[opt][1]; + for (let opt = 0; opt < foptions.length; opt++) { + const value = foptions[opt][1]; const motorValue = value.substring(value.indexOf('.') + 1); const typeValue = motorValue.indexOf('large') == 0 ? 'large' : 'medium'; const portValue = motorValue.indexOf('large') == 0 ? motorValue.substring(5) : motorValue.substring(6); @@ -429,13 +429,14 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC if (!opts[key]) opts[key] = []; opts[key].push(portValue); - conts[text] = options[opt][0]; + conts[text] = foptions[opt][0]; vals[text] = value; } - const currentFirst = this.getFirstValue(this.value_); - const currentSecond = this.getSecondValue(this.value_); + const currentFirst = this.getFirstValue(this.value_); + //const currentSecond = this.getSecondValue(this.value_); + let options: string[]; if (!this.isFirst_) { options = opts[currentFirst]; } else { @@ -526,7 +527,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 = 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 +539,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(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,10 +562,11 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC * Callback for when the drop-down is hidden. */ protected onHide_() { - Blockly.DropDownDiv.content_.removeAttribute('role'); - Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup'); - Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant'); - Blockly.DropDownDiv.getContentDiv().style.width = ''; + const content = Blockly.DropDownDiv.getContentDiv(); + content.removeAttribute('role'); + content.removeAttribute('aria-haspopup'); + content.removeAttribute('aria-activedescendant'); + (content as HTMLElement).style.width = ''; if (this.isFirst_ && this.box_) { this.box_.setAttribute('fill', this.sourceBlock_.getColour()); } else if (!this.isFirst_ && this.box2_) { diff --git a/fieldeditors/field_music.ts b/fieldeditors/field_music.ts index 359d5793..53ffddf6 100644 --- a/fieldeditors/field_music.ts +++ b/fieldeditors/field_music.ts @@ -26,7 +26,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC this.width_ = parseInt(options.width) || 380; this.setText = Blockly.FieldDropdown.prototype.setText; - this.updateWidth = (Blockly.Field as any).prototype.updateWidth; + this.updateSize_ = (Blockly.Field as any).prototype.updateSize_; this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_; 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.cssFloat = 'left'; - dropdownDiv.style.maxHeight = `410px`; + (dropdownDiv as HTMLElement).style.maxHeight = `410px`; dropdownDiv.appendChild(categoriesDiv); dropdownDiv.appendChild(contentDiv); Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary()); // Calculate positioning based on the field position. - let scale = 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(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)); @@ -236,7 +236,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC protected onHide_() { super.onHide_(); - Blockly.DropDownDiv.getContentDiv().style.maxHeight = ''; + (Blockly.DropDownDiv.getContentDiv() as HTMLElement).style.maxHeight = ''; this.stopSounds(); } diff --git a/fieldeditors/field_ports.ts b/fieldeditors/field_ports.ts index 16adbcac..31e65cc3 100644 --- a/fieldeditors/field_ports.ts +++ b/fieldeditors/field_ports.ts @@ -17,7 +17,7 @@ export class FieldPorts extends pxtblockly.FieldImages implements Blockly.FieldC this.width_ = parseInt(options.width) || 300; this.setText = Blockly.FieldDropdown.prototype.setText; - this.updateWidth = (Blockly.Field as any).prototype.updateWidth; + this.updateSize_ = (Blockly.Field as any).prototype.updateSize_; this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_; } diff --git a/fieldeditors/field_speed.ts b/fieldeditors/field_speed.ts deleted file mode 100644 index cd095485..00000000 --- a/fieldeditors/field_speed.ts +++ /dev/null @@ -1,98 +0,0 @@ -/// -/// - -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; - } -} \ No newline at end of file diff --git a/fieldeditors/field_turnratio.ts b/fieldeditors/field_turnratio.ts deleted file mode 100644 index 3ecfe284..00000000 --- a/fieldeditors/field_turnratio.ts +++ /dev/null @@ -1,108 +0,0 @@ -/// -/// - -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_(); - } -} \ No newline at end of file diff --git a/libs/base/enums.d.ts b/libs/base/enums.d.ts index bd7fcd0e..f457764b 100644 --- a/libs/base/enums.d.ts +++ b/libs/base/enums.d.ts @@ -22,13 +22,8 @@ } - declare const enum ValType { - Undefined = 0, - Boolean = 1, - Number = 2, - String = 3, - Object = 4, - Function = 5, + declare const enum PerfCounters { + GC = 0, } // Auto-generated. Do not edit. Really. diff --git a/libs/base/shims.d.ts b/libs/base/shims.d.ts index bc035e08..ece391a3 100644 --- a/libs/base/shims.d.ts +++ b/libs/base/shims.d.ts @@ -4,6 +4,18 @@ //% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte 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. */ @@ -42,6 +54,12 @@ 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. */ @@ -72,6 +90,13 @@ 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 { @@ -101,6 +126,12 @@ declare namespace control { //% blockId=control_running_time block="millis (ms)" shim=control::millis function millis(): int32; + /** + * Gets current time in microseconds. Overflows every ~18 minutes. + */ + //% shim=control::micros + function micros(): int32; + /** * Used internally */ @@ -143,11 +174,54 @@ declare namespace control { //% help=control/device-serial-number shim=control::deviceSerialNumber 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 - function __log(text: string): void; + 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; + + /** + * 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. diff --git a/libs/core/control.cpp b/libs/core/control.cpp deleted file mode 100644 index 2b53bada..00000000 --- a/libs/core/control.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#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(); - } -} \ No newline at end of file diff --git a/libs/core/dal.d.ts b/libs/core/dal.d.ts index bf9e6fdd..4507f801 100644 --- a/libs/core/dal.d.ts +++ b/libs/core/dal.d.ts @@ -1,6 +1,305 @@ // Auto-generated. Do not edit. declare const enum DAL { - // built/dockermake/pxtapp/ev3const.h + // /pxtapp/configkeys.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_OUTPUTS = 4, LCD_WIDTH = 178, @@ -46,44 +345,66 @@ declare const enum DAL { CONN_OUTPUT_TACHO = 125, CONN_NONE = 126, CONN_ERROR = 127, - opProgramStart = 0x03, - opOutputGetType = 0xA0, - opOutputSetType = 0xA1, - opOutputReset = 0xA2, - opOutputStop = 0xA3, - opOutputPower = 0xA4, - opOutputSpeed = 0xA5, - opOutputStart = 0xA6, - opOutputPolarity = 0xA7, - opOutputRead = 0xA8, - opOutputTest = 0xA9, - opOutputReady = 0xAA, - opOutputPosition = 0xAB, - opOutputStepPower = 0xAC, - opOutputTimePower = 0xAD, - opOutputStepSpeed = 0xAE, - opOutputTimeSpeed = 0xAF, - opOutputStepSync = 0xB0, - opOutputTimeSync = 0xB1, - opOutputClearCount = 0xB2, - opOutputGetCount = 0xB3, - opOutputProgramStop = 0xB4, - BUTTON_ID_UP = 0x01, - BUTTON_ID_ENTER = 0x02, - BUTTON_ID_DOWN = 0x04, - BUTTON_ID_RIGHT = 0x08, - BUTTON_ID_LEFT = 0x10, - BUTTON_ID_ESCAPE = 0x20, - // built/dockermake/pxtapp/pxt.h + opProgramStart = 3, + opOutputGetType = 160, + opOutputSetType = 161, + opOutputReset = 162, + opOutputStop = 163, + opOutputPower = 164, + opOutputSpeed = 165, + opOutputStart = 166, + opOutputPolarity = 167, + opOutputRead = 168, + opOutputTest = 169, + opOutputReady = 170, + opOutputPosition = 171, + opOutputStepPower = 172, + opOutputTimePower = 173, + opOutputStepSpeed = 174, + opOutputTimeSpeed = 175, + opOutputStepSync = 176, + opOutputTimeSync = 177, + opOutputClearCount = 178, + opOutputGetCount = 179, + opOutputProgramStop = 180, + BUTTON_ID_UP = 1, + BUTTON_ID_ENTER = 2, + BUTTON_ID_DOWN = 4, + BUTTON_ID_RIGHT = 8, + BUTTON_ID_LEFT = 16, + BUTTON_ID_ESCAPE = 32, + // /pxtapp/platform.h + PXT_GC_THREAD_LIST = 1, + // /pxtapp/pxt.h DEVICE_EVT_ANY = 0, DEVICE_ID_NOTIFY = 10000, DEVICE_ID_NOTIFY_ONE = 10001, - // built/dockermake/pxtapp/pxtbase.h - PXT_REF_TAG_STRING = 1, - PXT_REF_TAG_BUFFER = 2, - PXT_REF_TAG_IMAGE = 3, - PXT_REF_TAG_NUMBER = 32, - PXT_REF_TAG_ACTION = 33, + IMAGE_BITS = 1, + // /pxtapp/pxtbase.h + PXT32 = 1, + PXT64 = 1, + PXT_VTABLE_SHIFT = 2, + PXT_REFCNT_FLASH = 65534, + 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, UInt8LE = 2, Int16LE = 3, @@ -100,12 +421,10 @@ declare const enum DAL { Float64LE = 14, Float32BE = 15, Float64BE = 16, - Undefined = 0, - Boolean = 1, - Number = 2, - String = 3, - Object = 4, - Function = 5, - // built/dockermake/pxtapp/pxtconfig.h - // built/dockermake/pxtapp/pxtcore.h + NUM_TRY_FRAME_REGS = 3, + GC = 0, + // /pxtapp/pxtconfig.h + PXT_GC = 1, + // /pxtapp/pxtcore.h + PXT_HARD_FLOAT = 1, } diff --git a/libs/core/linux.cpp b/libs/core/linux.cpp deleted file mode 100644 index 39f21ef1..00000000 --- a/libs/core/linux.cpp +++ /dev/null @@ -1,589 +0,0 @@ -#include "pxt.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 diff --git a/libs/core/mmap.cpp b/libs/core/mmap.cpp index c11ffd17..9b17e730 100644 --- a/libs/core/mmap.cpp +++ b/libs/core/mmap.cpp @@ -25,13 +25,20 @@ PXT_VTABLE_CTOR(MMap) { } void MMap::print() { - DMESG("MMap %p r=%d len=%d fd=%d data=%p", this, refcnt, length, fd, data); + DMESG("MMap %p len=%d fd=%d data=%p", this, length, fd, data); } void MMap::destroy() { munmap(data, length); close(fd); } + +void MMap::scan(MMap *) {} + +unsigned MMap::gcsize(MMap *) { + return TOWORDS(sizeof(MMap)); +} + } namespace control { @@ -39,8 +46,8 @@ namespace control { /** Create new file mapping in memory */ //% MMap *mmap(String filename, int size, int offset) { - DMESG("mmap %s len=%d off=%d", filename->data, size, offset); - int fd = open(filename->data, O_RDWR, 0); + DMESG("mmap %s len=%d off=%d", filename->getUTF8Data(), size, offset); + int fd = open(filename->getUTF8Data(), O_RDWR, 0); if (fd < 0) return 0; diff --git a/libs/core/output.ts b/libs/core/output.ts index cba65479..6710a1c7 100644 --- a/libs/core/output.ts +++ b/libs/core/output.ts @@ -918,9 +918,3 @@ namespace motors { writePWM(b) } } - - -interface Buffer { - [index: number]: number; - // rest defined in buffer.cpp -} \ No newline at end of file diff --git a/libs/core/platform.cpp b/libs/core/platform.cpp new file mode 100644 index 00000000..fd994729 --- /dev/null +++ b/libs/core/platform.cpp @@ -0,0 +1,199 @@ +#include "pxt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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, 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() { + tryLockUser(); + stopMotors(); + stopProgram(); + if (lmsPid) + runLMS(); + else + exit(0); +} + +void target_exit() { + target_reset(); +} + + +void target_startup() { + stopLMS(); + startUsb(); + startExitThread(); +} + +void initKeys() {} + + +} diff --git a/libs/core/platform.h b/libs/core/platform.h index ff35a37e..67e813bb 100644 --- a/libs/core/platform.h +++ b/libs/core/platform.h @@ -1 +1,3 @@ -// leave empty \ No newline at end of file +#define PXT_GC_THREAD_LIST 1 + +#define PXT_IN_ISR() false diff --git a/libs/core/pxt.h b/libs/core/pxt.h index debeff6f..2b321615 100644 --- a/libs/core/pxt.h +++ b/libs/core/pxt.h @@ -11,6 +11,7 @@ int allocateNotifyEvent(); void sleep_core_us(uint64_t us); void startUser(); void stopUser(); +int tryLockUser(); class Button; typedef Button *Button_; @@ -27,9 +28,13 @@ class MMap : public RefObject { MMap(); void destroy(); void print(); + + static void scan(MMap *); + static unsigned gcsize(MMap *); }; extern volatile bool paniced; +void target_exit(); // Buffer, Sound, and Image share representation. typedef Buffer Sound; diff --git a/libs/core/pxt.json b/libs/core/pxt.json index b392b009..3b3fa916 100644 --- a/libs/core/pxt.json +++ b/libs/core/pxt.json @@ -26,11 +26,19 @@ "icons.jres", "ns.ts", "platform.h", + "platform.cpp", + "dmesg.cpp", "integrator.ts" ], "testFiles": [ "test.ts" ], + "dalDTS": { + "includeDirs": [ + "pxtapp" + ] + }, + "additionalFilePath": "../../node_modules/pxt-common-packages/libs/core---linux", "npmDependencies": {}, "public": true, "dependencies": { diff --git a/libs/core/pxtcore.h b/libs/core/pxtcore.h deleted file mode 100644 index 032d490b..00000000 --- a/libs/core/pxtcore.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __PXTCORE_H -#define __PXTCORE_H - -#include - -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 diff --git a/libs/core/screen.cpp b/libs/core/screen.cpp index e6839a83..149b7f32 100644 --- a/libs/core/screen.cpp +++ b/libs/core/screen.cpp @@ -85,10 +85,9 @@ void updateScreen(Image_ img) { lastImg = img; } - if (lastImg && lastImg->isDirty() && mappedFrameBuffer != MAP_FAILED) { + if (lastImg && mappedFrameBuffer != MAP_FAILED) { if (lastImg->bpp() != 1 || lastImg->width() != LCD_WIDTH || lastImg->height() != LCD_HEIGHT) target_panic(906); - lastImg->clearDirty(); bitBufferToFrameBufferSwap(lastImg->pix(), mappedFrameBuffer); } } diff --git a/libs/core/serialnumber.cpp b/libs/core/serialnumber.cpp index af448f81..f69217e4 100644 --- a/libs/core/serialnumber.cpp +++ b/libs/core/serialnumber.cpp @@ -25,8 +25,8 @@ struct hci_dev_list_req { hci_dev_req dev_req[2]; }; -static uint32_t bt_addr() { - uint32_t res = -1; +static uint64_t bt_addr() { + uint64_t res = -1; int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (fd < 0) { @@ -50,11 +50,8 @@ static uint32_t bt_addr() { goto done; } - memcpy(&res, di.bdaddr, 4); - res *= 0x1000193; - res += di.bdaddr[4]; - res *= 0x1000193; - res += di.bdaddr[5]; + res = 0; + memcpy(&res, di.bdaddr, 6); done: close(fd); @@ -63,14 +60,10 @@ done: namespace pxt { -int getSerialNumber() { - static int serial; - - if (serial != 0) - return serial; - - serial = bt_addr() & 0x7fffffff; - +uint64_t getLongSerialNumber() { + static uint64_t serial; + if (serial == 0) + serial = bt_addr(); return serial; } diff --git a/libs/core/shims.d.ts b/libs/core/shims.d.ts index 8e35f2b5..23fccb50 100644 --- a/libs/core/shims.d.ts +++ b/libs/core/shims.d.ts @@ -68,6 +68,12 @@ declare namespace control { /** Write data to DMESG debugging buffer. */ //% shim=control::dmesg function dmesg(s: string): void; + + /** + * Determines if the USB has been enumerated. + */ + //% shim=control::isUSBInitialized + function isUSBInitialized(): boolean; } declare namespace serial { diff --git a/libs/ev3/console.ts b/libs/ev3/console.ts index 310ce735..8c95a185 100644 --- a/libs/ev3/console.ts +++ b/libs/ev3/console.ts @@ -20,7 +20,7 @@ namespace console._screen { lines = []; console.addListener(log); 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(); } - function log(msg: string): void { + function log(priority: ConsolePriority, msg: string): void { lines.push(msg); if (lines.length + 5 > maxLines) { lines.splice(0, maxLines - lines.length); diff --git a/libs/ev3/startup.ts b/libs/ev3/startup.ts index 93941d60..6affe4d0 100644 --- a/libs/ev3/startup.ts +++ b/libs/ev3/startup.ts @@ -1,5 +1,5 @@ // This is the last thing executed before user code -console.addListener(function(msg: string) { +console.addListener(function(priority: ConsolePriority, msg: string) { control.dmesg(msg.substr(0, msg.length - 1)) }) // pulse green, play startup sound, turn off light diff --git a/libs/screen/screenimage.ts b/libs/screen/screenimage.ts new file mode 100644 index 00000000..43aeda5a --- /dev/null +++ b/libs/screen/screenimage.ts @@ -0,0 +1,10 @@ + +namespace image { + /** + * Get the screen image + */ + //% + export function screenImage(): Image { + return screen; + } +} diff --git a/libs/screen/shims.d.ts b/libs/screen/shims.d.ts index f8a5b06d..4d243974 100644 --- a/libs/screen/shims.d.ts +++ b/libs/screen/shims.d.ts @@ -15,7 +15,7 @@ declare interface Image { height: int32; /** - * True iff the image is monochromatic (black and white) + * True if the image is monochromatic (black and white) */ //% property shim=ImageMethods::isMono isMono: boolean; @@ -45,6 +45,18 @@ 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 */ diff --git a/package.json b/package.json index 15230af2..db1da66f 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { "name": "pxt-ev3", - "version": "1.2.23", + "version": "1.4.0", "description": "LEGO MINDSTORMS EV3 for Microsoft MakeCode", "private": false, "keywords": [ "JavaScript", "education", - "lego", + "LEGO", + "EV3", "pxt", "MakeCode", "Microsoft" @@ -32,15 +33,20 @@ ], "devDependencies": { "typescript": "2.6.1", + "react": "16.8.3", "semantic-ui-less": "2.2.14", "@types/bluebird": "2.0.33", "@types/marked": "0.3.0", "@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": { - "pxt-common-packages": "0.23.61", - "pxt-core": "4.0.11" + "pxt-common-packages": "6.16.7", + "pxt-core": "5.25.6" }, "scripts": { "test": "node node_modules/pxt-core/built/pxt.js travis" diff --git a/pxtarget.json b/pxtarget.json index 3b1bacd7..9a78d354 100644 --- a/pxtarget.json +++ b/pxtarget.json @@ -22,7 +22,7 @@ ], "simulator": { "autoRun": true, - "streams": true, + "autoRunLight": false, "aspectRatio": 0.5, "parts": false, "enableTrace": true, @@ -50,15 +50,16 @@ "flashCodeAlign": 256, "floatingPoint": true, "taggedInts": true, - "stackAlign": 2 + "stackAlign": 2, + "gc": true }, "serial": { - "vendorId": "0x0694", - "productId": "0x0005", - "rawHID": true, - "useEditor": true, - "log": true - }, + "vendorId": "0x0694", + "productId": "0x0005", + "rawHID": true, + "useEditor": true, + "log": true + }, "runtime": { "mathBlocks": true, "loopsBlocks": true, @@ -72,7 +73,10 @@ "onStartColor": "#58AB41", "pauseUntilBlock": { "category": "loops" - } + }, + "bannedCategories": [ + "image" + ] }, "compileService": { "buildEngine": "dockermake", @@ -82,7 +86,7 @@ "appTheme": { "accentColor": "#0089BF", "logoWide": true, - "logoUrl": "https://education.lego.com/", + "logoUrl": "https://education.lego.com/", "logo": "./static/lego_education_logo.png", "docsLogo": "./static/lego_education_logo.png", "portraitLogo": "./static/lego_education_logo.png", @@ -151,6 +155,12 @@ "usbHelp": [], "extendEditor": true, "extendFieldEditors": true, + "scriptManager": true, + "importExtensionFiles": true, + "experiments": [ + "python", + "alwaysGithubItemBlocks" + ], "disableBlockIcons": true, "blocklyOptions": { "grid": { @@ -186,7 +196,11 @@ "editor.background": "#f9f9f9" }, "fileNameExclusiveFilter": "[^a-zA-Z0-9]", + "qrCode": true, + "shareFinishedTutorials": true, + "nameProjectFirst": true, + "alwaysGithubItem": true, "enableTrace": true }, "ignoreDocsErrors": true -} +} \ No newline at end of file diff --git a/sim/dalboard.ts b/sim/dalboard.ts index 9ccbe149..c778866c 100644 --- a/sim/dalboard.ts +++ b/sim/dalboard.ts @@ -5,6 +5,7 @@ namespace pxsim { export class EV3Board extends CoreBoard { + viewHost: visuals.BoardHost; view: SVGSVGElement; outputState: EV3OutputState; @@ -83,7 +84,8 @@ namespace pxsim { highContrast: msg.highContrast, light: msg.light }; - const viewHost = new visuals.BoardHost(pxsim.visuals.mkBoardView({ + this.viewHost = new visuals.BoardHost(pxsim.visuals.mkBoardView({ + boardDef, visual: boardDef.visual, highContrast: msg.highContrast, light: msg.light @@ -91,7 +93,7 @@ namespace pxsim { document.body.innerHTML = ""; // clear children document.body.className = msg.light ? "light" : ""; - document.body.appendChild(this.view = viewHost.getView() as SVGSVGElement); + document.body.appendChild(this.view = this.viewHost.getView() as SVGSVGElement); this.inputNodes = []; this.outputNodes = []; @@ -102,8 +104,8 @@ namespace pxsim { return Promise.resolve(); } - screenshot(): string { - return svg.toDataUri(new XMLSerializer().serializeToString(this.view)); + screenshotAsync(width?: number): Promise { + return this.viewHost.screenshotAsync(width); } getBrickNode() { diff --git a/sim/state/sounds.ts b/sim/state/sounds.ts index 533b0509..82ee4233 100644 --- a/sim/state/sounds.ts +++ b/sim/state/sounds.ts @@ -1,7 +1,7 @@ namespace pxsim.music { export function fromWAV(buf: RefBuffer) { - return incr(buf) + return buf } export function stopAllSounds() { @@ -13,7 +13,7 @@ namespace pxsim.SoundMethods { let audio: HTMLAudioElement; export function buffer(buf: RefBuffer) { - return incr(buf) + return buf } export function play(buf: RefBuffer) { diff --git a/sim/visuals/board.ts b/sim/visuals/board.ts index 6c11d3b6..45079740 100644 --- a/sim/visuals/board.ts +++ b/sim/visuals/board.ts @@ -176,7 +176,7 @@ namespace pxsim.visuals { const dalBoard = board(); dalBoard.updateSubscribers.push(() => this.updateState()); if (props && props.wireframe) - svg.addClass(this.element, "sim-wireframe"); + U.addClass(this.element, "sim-wireframe"); if (props && props.theme) this.updateTheme(); diff --git a/sim/visuals/nodes/brickView.ts b/sim/visuals/nodes/brickView.ts index 81a62b79..551ba4ea 100644 --- a/sim/visuals/nodes/brickView.ts +++ b/sim/visuals/nodes/brickView.ts @@ -24,7 +24,7 @@ namespace pxsim.visuals { protected buildDomCore() { // Setup buttons this.buttons = this.btnids.map(n => this.content.getElementById(this.normalizeId(n)) as SVGElement); - this.buttons.forEach(b => svg.addClass(b, "sim-button")); + this.buttons.forEach(b => U.addClass(b, "sim-button")); this.light = this.content.getElementById(this.normalizeId(BrickView.EV3_LIGHT_ID)) as SVGElement; } diff --git a/targetconfig.json b/targetconfig.json index 30366ba0..aaa01a00 100644 --- a/targetconfig.json +++ b/targetconfig.json @@ -24,7 +24,7 @@ "Design Engineering": "design-engineering", "Coding": "coding", "Maker": "maker", - "Videos": "videos" + "Tutorial Videos": "videos" }, "electronManifest": { "latest": "v1.2.22" diff --git a/theme/style.less b/theme/style.less index 6598c49e..12ee46e9 100644 --- a/theme/style.less +++ b/theme/style.less @@ -16,6 +16,10 @@ /******************************* Add your custom CSS here *******************************/ +.simframe.ui.embed { + background: transparent; +} + /* Open Sans font */ @font-face {