update to pxt 5 and pxt-common-packages 6 (#934)
* bump pxt * fix build issues * Auto-gen of projects/summary * removing feild editors moved to pxt * various typing fixes * more typing fixes * fixing various typing issues * Start on integration of new pxt * serial number fixes * gc-ify MMap object * Re-build generated files * fix console listeners * clear lf() warnings * More generated files * also auto-generated * Compilation fixes * fix merge * mostly fixing blocks * fix sim * fix field motors * enable a few features * moving to tsx * try to fix edtiro compilation * more defs * removing commands * removing extra $ * fix blockly warning * hiding images * enabling more pxt features * hide images * setup autorun * add lock on target_reset * update deps * return trylock result * updated pxt * rename video section * add alpha channel * upgraded pxt * bump pxt/version * removed alpha ref * var ceanup * don't do major bump
This commit is contained in:
		
				
					committed by
					
						 Peli de Halleux
						Peli de Halleux
					
				
			
			
				
	
			
			
			
						parent
						
							ba94322d4c
						
					
				
				
					commit
					c5cec3a6ba
				
			
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -17,6 +17,7 @@ clients/**/bin/** | |||||||
| clients/**/obj/** | clients/**/obj/** | ||||||
| clients/electron/projects | clients/electron/projects | ||||||
| libs/**/_locales/** | libs/**/_locales/** | ||||||
|  | package-lock.json | ||||||
|  |  | ||||||
| videos/** | videos/** | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								cmds/cmds.ts
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								cmds/cmds.ts
									
									
									
									
									
								
							| @@ -1,14 +0,0 @@ | |||||||
| /// <reference path="../node_modules/pxt-core/built/pxtlib.d.ts" /> |  | ||||||
|  |  | ||||||
| import * as fs from 'fs'; |  | ||||||
|  |  | ||||||
| const deploy = require("./editor/deploy") |  | ||||||
|  |  | ||||||
| export function deployCoreAsync(resp: pxtc.CompileResult) { |  | ||||||
|     return deploy.deployCoreAsync(resp, process.env["PXT_SERIAL"] ? false : true) |  | ||||||
|         .then(() => { |  | ||||||
|             fs.writeFileSync("built/full-" + pxtc.BINARY_UF2, resp.outfiles[pxtc.BINARY_UF2], { |  | ||||||
|                 encoding: "base64" |  | ||||||
|             }) |  | ||||||
|         }) |  | ||||||
| } |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| { |  | ||||||
|     "compilerOptions": { |  | ||||||
|         "target": "es5", |  | ||||||
|         "noImplicitAny": true, |  | ||||||
|         "noImplicitReturns": true, |  | ||||||
|         "declaration": true, |  | ||||||
|         "outDir": "../built", |  | ||||||
|         "module": "commonjs", |  | ||||||
|         "rootDir": ".", |  | ||||||
|         "newLine": "LF", |  | ||||||
|         "sourceMap": false, |  | ||||||
|         "types": ["node"] |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,9 +1,88 @@ | |||||||
| # Projects | # 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. |  | ||||||
							
								
								
									
										69
									
								
								docs/projects/SUMMARY.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								docs/projects/SUMMARY.md
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||||
| @@ -3,20 +3,15 @@ | |||||||
|  |  | ||||||
| import UF2 = pxtc.UF2; | import UF2 = pxtc.UF2; | ||||||
| import { Ev3Wrapper } from "./wrap"; | import { Ev3Wrapper } from "./wrap"; | ||||||
|  | import { bluetoothTryAgainAsync } from "./dialogs"; | ||||||
|  |  | ||||||
| export let ev3: Ev3Wrapper; | export let ev3: Ev3Wrapper; | ||||||
| let confirmAsync: (options: any) => Promise<number>; |  | ||||||
|  |  | ||||||
| export function setConfirmAsync(cf: (options: any) => Promise<number>) { |  | ||||||
|     confirmAsync = cf; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function debug() { | export function debug() { | ||||||
|     return initHidAsync() |     return initHidAsync() | ||||||
|         .then(w => w.downloadFileAsync("/tmp/dmesg.txt", v => console.log(pxt.Util.uint8ArrayToString(v)))) |         .then(w => w.downloadFileAsync("/tmp/dmesg.txt", v => console.log(pxt.Util.uint8ArrayToString(v)))) | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| // Web Serial API https://wicg.github.io/serial/ | // Web Serial API https://wicg.github.io/serial/ | ||||||
| // chromium bug https://bugs.chromium.org/p/chromium/issues/detail?id=884928 | // chromium bug https://bugs.chromium.org/p/chromium/issues/detail?id=884928 | ||||||
| // Under experimental features in Chrome Desktop 77+ | // Under experimental features in Chrome Desktop 77+ | ||||||
| @@ -167,7 +162,7 @@ export function initAsync(): Promise<void> { | |||||||
|         useHID = false |         useHID = false | ||||||
|     } else { |     } else { | ||||||
|         const nodehid = /nodehid/i.test(window.location.href); |         const nodehid = /nodehid/i.test(window.location.href); | ||||||
|         if (pxt.Cloud.isLocalHost() && pxt.Cloud.localToken && nodehid) |         if (pxt.BrowserUtils.isLocalHost() && pxt.Cloud.localToken && nodehid) | ||||||
|             useHID = true; |             useHID = true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -283,20 +278,7 @@ export function deployCoreAsync(resp: pxtc.CompileResult) { | |||||||
|             return w.reconnectAsync(false) |             return w.reconnectAsync(false) | ||||||
|                 .catch(e => { |                 .catch(e => { | ||||||
|                     // user easily forgets to stop robot |                     // user easily forgets to stop robot | ||||||
|                     if (confirmAsync) |                     bluetoothTryAgainAsync().then(() => w.disconnectAsync()) | ||||||
|                         return confirmAsync({ |  | ||||||
|                             header: lf("Bluetooth download failed..."), |  | ||||||
|                             htmlBody: |  | ||||||
|                                 `<ul> |  | ||||||
| <li>${lf("Make sure to stop your program or exit portview on the EV3.")}</li> |  | ||||||
| <li>${lf("Check your battery level.")}</li> |  | ||||||
| <li>${lf("Close EV3 LabView or other MakeCode editor tabs.")} |  | ||||||
| </ul>`, |  | ||||||
|                             hasCloseIcon: true, |  | ||||||
|                             hideCancel: true, |  | ||||||
|                             hideAgree: false, |  | ||||||
|                             agreeLbl: lf("Try again"), |  | ||||||
|                         }).then(() => w.disconnectAsync()) |  | ||||||
|                         .then(() => Promise.delay(1000)) |                         .then(() => Promise.delay(1000)) | ||||||
|                         .then(() => w.reconnectAsync()); |                         .then(() => w.reconnectAsync()); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										145
									
								
								editor/dialogs.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								editor/dialogs.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,145 @@ | |||||||
|  | import * as React from "react"; | ||||||
|  | import { canUseWebSerial, enableWebSerialAsync } from "./deploy"; | ||||||
|  | import { projectView } from "./extension"; | ||||||
|  |  | ||||||
|  | let confirmAsync: (options: any) => Promise<number>; | ||||||
|  |  | ||||||
|  | export function bluetoothTryAgainAsync(): Promise<void> { | ||||||
|  |     return confirmAsync({ | ||||||
|  |         header: lf("Bluetooth download failed..."), | ||||||
|  |         jsx: <ul> | ||||||
|  |             <li>{lf("Make sure to stop your program or exit portview on the EV3.")}</li> | ||||||
|  |             <li>{lf("Check your battery level.")}</li> | ||||||
|  |             <li>{lf("Close EV3 LabView or other MakeCode editor tabs.")}</li> | ||||||
|  |         </ul>, | ||||||
|  |         hasCloseIcon: false, | ||||||
|  |         hideCancel: true, | ||||||
|  |         hideAgree: false, | ||||||
|  |         agreeLbl: lf("Try again") | ||||||
|  |     }).then(r => {}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function enableWebSerialAndCompileAsync() { | ||||||
|  |     return enableWebSerialAsync() | ||||||
|  |         .then(() => Promise.delay(500)) | ||||||
|  |         .then(() => projectView.compile()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | let bluetoothDialogShown = false; | ||||||
|  | function explainWebSerialPairingAsync(): Promise<void> { | ||||||
|  |     if (!confirmAsync || bluetoothDialogShown) return Promise.resolve(); | ||||||
|  |  | ||||||
|  |     bluetoothDialogShown = true; | ||||||
|  |     return confirmAsync({ | ||||||
|  |         header: lf("Bluetooth pairing"), | ||||||
|  |         hasCloseIcon: false, | ||||||
|  |         hideCancel: true, | ||||||
|  |         buttons: [{ | ||||||
|  |             label: lf("Help"), | ||||||
|  |             icon: "question circle", | ||||||
|  |             className: "lightgrey", | ||||||
|  |             url: "/bluetooth" | ||||||
|  |         }], | ||||||
|  |         jsx: <p> | ||||||
|  |             {lf("You will be prompted to select a serial port.")} | ||||||
|  |             {pxt.BrowserUtils.isWindows() | ||||||
|  |                 ? lf("Look for 'Standard Serial over Bluetooth link'.") | ||||||
|  |                 : lf("Loop for 'cu.EV3-SerialPort'.")} | ||||||
|  |             {lf("If you have paired multiple EV3, you might have to try out multiple ports until you find the correct one.")} | ||||||
|  |         </p> | ||||||
|  |     }).then(() => { }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function showUploadDialogAsync(fn: string, url: string, _confirmAsync: (options: any) => Promise<number>): Promise<void> { | ||||||
|  |     confirmAsync = _confirmAsync; | ||||||
|  |     // https://msdn.microsoft.com/en-us/library/cc848897.aspx | ||||||
|  |     // "For security reasons, data URIs are restricted to downloaded resources.  | ||||||
|  |     // Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements" | ||||||
|  |     const downloadAgain = !pxt.BrowserUtils.isIE() && !pxt.BrowserUtils.isEdge(); | ||||||
|  |     const docUrl = pxt.appTarget.appTheme.usbDocs; | ||||||
|  |  | ||||||
|  |     const jsx = | ||||||
|  |         <div className="ui grid stackable"> | ||||||
|  |             <div className="column five wide" style={{ backgroundColor: "#E2E2E2" }}> | ||||||
|  |                 <div className="ui header">{lf("First time here?")}</div> | ||||||
|  |                 <strong style={{ fontSize: "small" }}>{lf("You must have version 1.10E or above of the firmware")}</strong> | ||||||
|  |                 <div style={{ justifyContent: "center", display: "flex", padding: "1rem" }}> | ||||||
|  |                     <img className="ui image" src="/static/download/firmware.png" style={{ height: "100px" }} /> | ||||||
|  |                 </div> | ||||||
|  |                 <a href="/troubleshoot" target="_blank">{lf("Check your firmware version here and update if needed")}</a> | ||||||
|  |             </div> | ||||||
|  |             <div className="column eleven wide"> | ||||||
|  |                 <div className="ui grid"> | ||||||
|  |                     <div className="row"> | ||||||
|  |                         <div className="column"> | ||||||
|  |                             <div className="ui two column grid padded"> | ||||||
|  |                                 <div className="column"> | ||||||
|  |                                     <div className="ui"> | ||||||
|  |                                         <div className="image"> | ||||||
|  |                                             <img className="ui medium rounded image" src="/static/download/connect.svg" style={{ height: "109px", width: "261px", marginBottom: "1rem" }} /> | ||||||
|  |                                         </div> | ||||||
|  |                                         <div className="content"> | ||||||
|  |                                             <div className="description"> | ||||||
|  |                                                 <span className="ui yellow circular label">1</span> | ||||||
|  |                                                 <strong>{lf("Connect the EV3 to your computer with a USB cable")}</strong> | ||||||
|  |                                                 <br /> | ||||||
|  |                                                 <span style={{ fontSize: "small" }}>{lf("Use the miniUSB port on the top of the EV3 Brick")}</span> | ||||||
|  |                                             </div> | ||||||
|  |                                         </div> | ||||||
|  |                                     </div> | ||||||
|  |                                 </div> | ||||||
|  |                                 <div className="column"> | ||||||
|  |                                     <div className="ui"> | ||||||
|  |                                         <div className="image"> | ||||||
|  |                                             <img className="ui medium rounded image" src="/static/download/transfer.svg" style={{ height: "109px", width: "261px", marginBottom: "1rem" }} /> | ||||||
|  |                                         </div> | ||||||
|  |                                         <div className="content"> | ||||||
|  |                                             <div className="description"> | ||||||
|  |                                                 <span className="ui yellow circular label">2</span> | ||||||
|  |                                                 <strong>{lf("Move the .uf2 file to the EV3 Brick")}</strong> | ||||||
|  |                                                 <br /> | ||||||
|  |                                                 <span style={{ fontSize: "small" }}>{lf("Locate the downloaded .uf2 file and drag it to the EV3 USB drive")}</span> | ||||||
|  |                                             </div> | ||||||
|  |                                         </div> | ||||||
|  |                                     </div> | ||||||
|  |                                 </div> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div>; | ||||||
|  |  | ||||||
|  |     return confirmAsync({ | ||||||
|  |         header: lf("Download to your EV3"), | ||||||
|  |         jsx, | ||||||
|  |         hasCloseIcon: true, | ||||||
|  |         hideCancel: true, | ||||||
|  |         hideAgree: false, | ||||||
|  |         agreeLbl: lf("I got it"), | ||||||
|  |         className: 'downloaddialog', | ||||||
|  |         buttons: [canUseWebSerial() ? { | ||||||
|  |             label: lf("Bluetooth"), | ||||||
|  |             icon: "bluetooth", | ||||||
|  |             className: "bluetooth focused", | ||||||
|  |             onclick: () => { | ||||||
|  |                 pxt.tickEvent("bluetooth.enable"); | ||||||
|  |                 explainWebSerialPairingAsync() | ||||||
|  |                     .then(() => enableWebSerialAndCompileAsync()) | ||||||
|  |                     .done(); | ||||||
|  |             } | ||||||
|  |         } : undefined, downloadAgain ? { | ||||||
|  |             label: fn, | ||||||
|  |             icon: "download", | ||||||
|  |             className: "lightgrey focused", | ||||||
|  |             url, | ||||||
|  |             fileName: fn | ||||||
|  |         } : undefined, docUrl ? { | ||||||
|  |             label: lf("Help"), | ||||||
|  |             icon: "help", | ||||||
|  |             className: "lightgrey", | ||||||
|  |             url: docUrl | ||||||
|  |         } : undefined] | ||||||
|  |         //timeout: 20000 | ||||||
|  |     }).then(() => { }); | ||||||
|  | } | ||||||
| @@ -1,144 +1,26 @@ | |||||||
|  | /// <reference path="../node_modules/pxt-core/localtypings/pxtarget.d.ts" /> | ||||||
|  | /// <reference path="../node_modules/pxt-core/built/pxtblocks.d.ts" /> | ||||||
|  | /// <reference path="../node_modules/pxt-core/built/pxtcompiler.d.ts" /> | ||||||
|  | /// <reference path="../node_modules/pxt-core/built/pxtlib.d.ts" /> | ||||||
| /// <reference path="../node_modules/pxt-core/built/pxteditor.d.ts"/> | /// <reference path="../node_modules/pxt-core/built/pxteditor.d.ts"/> | ||||||
| /// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/> | /// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/> | ||||||
|  |  | ||||||
| import { deployCoreAsync, initAsync, 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<pxt.editor.ExtensionResult> { | pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> { | ||||||
|     const projectView = opts.projectView; |  | ||||||
|     pxt.debug('loading pxt-ev3 target extensions...') |     pxt.debug('loading pxt-ev3 target extensions...') | ||||||
|  |     projectView = opts.projectView; | ||||||
|     function enableWebSerialAndCompileAsync() { |  | ||||||
|         return enableWebSerialAsync() |  | ||||||
|         .then(() => Promise.delay(500)) |  | ||||||
|         .then(() => projectView.compile()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const res: pxt.editor.ExtensionResult = { |     const res: pxt.editor.ExtensionResult = { | ||||||
|         deployCoreAsync, |         deployAsync: deployCoreAsync, | ||||||
|         showUploadInstructionsAsync: (fn: string, url: string, confirmAsync: (options: any) => Promise<number>) => { |         showUploadInstructionsAsync: showUploadDialogAsync | ||||||
|             setConfirmAsync(confirmAsync); |  | ||||||
|             // https://msdn.microsoft.com/en-us/library/cc848897.aspx |  | ||||||
|             // "For security reasons, data URIs are restricted to downloaded resources.  |  | ||||||
|             // Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements" |  | ||||||
|             const downloadAgain = !pxt.BrowserUtils.isIE() && !pxt.BrowserUtils.isEdge(); |  | ||||||
|             const docUrl = pxt.appTarget.appTheme.usbDocs; |  | ||||||
|  |  | ||||||
|             const htmlBody = ` |  | ||||||
|             <div class="ui grid stackable"> |  | ||||||
|                 <div class="column five wide" style="background-color: #E2E2E2;"> |  | ||||||
|                     <div class="ui header">${lf("First time here?")}</div> |  | ||||||
|                     <strong style="font-size:small">${lf("You must have version 1.10E or above of the firmware")}</strong> |  | ||||||
|                     <div style="justify-content: center;display: flex;padding: 1rem;"> |  | ||||||
|                         <img class="ui image" src="/static/download/firmware.png" style="height:100px;" /> |  | ||||||
|                     </div> |  | ||||||
|                     <a href="/troubleshoot" target="_blank">${lf("Check your firmware version here and update if needed")}</a> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="column eleven wide"> |  | ||||||
|                     <div class="ui grid"> |  | ||||||
|                         <div class="row"> |  | ||||||
|                             <div class="column"> |  | ||||||
|                                 <div class="ui two column grid padded"> |  | ||||||
|                                     <div class="column"> |  | ||||||
|                                         <div class="ui"> |  | ||||||
|                                             <div class="image"> |  | ||||||
|                                                 <img class="ui medium rounded image" src="/static/download/connect.svg" style="height:109px;width:261px;margin-bottom:1rem;" /> |  | ||||||
|                                             </div> |  | ||||||
|                                             <div class="content"> |  | ||||||
|                                                 <div class="description"> |  | ||||||
|                                                     <span class="ui yellow circular label">1</span> |  | ||||||
|                                                     <strong>${lf("Connect the EV3 to your computer with a USB cable")}</strong> |  | ||||||
|                                                     <br /> |  | ||||||
|                                                     <span style="font-size:small">${lf("Use the miniUSB port on the top of the EV3 Brick")}</span> |  | ||||||
|                                                 </div> |  | ||||||
|                                             </div> |  | ||||||
|                                         </div> |  | ||||||
|                                     </div> |  | ||||||
|                                     <div class="column"> |  | ||||||
|                                         <div class="ui"> |  | ||||||
|                                             <div class="image"> |  | ||||||
|                                                 <img class="ui medium rounded image" src="/static/download/transfer.svg" style="height:109px;width:261px;margin-bottom:1rem;" /> |  | ||||||
|                                             </div> |  | ||||||
|                                             <div class="content"> |  | ||||||
|                                                 <div class="description"> |  | ||||||
|                                                     <span class="ui yellow circular label">2</span> |  | ||||||
|                                                     <strong>${lf("Move the .uf2 file to the EV3 Brick")}</strong> |  | ||||||
|                                                     <br /> |  | ||||||
|                                                     <span style="font-size:small">${lf("Locate the downloaded .uf2 file and drag it to the EV3 USB drive")}</span> |  | ||||||
|                                                 </div> |  | ||||||
|                                             </div> |  | ||||||
|                                         </div> |  | ||||||
|                                     </div> |  | ||||||
|                                 </div> |  | ||||||
|                             </div> |  | ||||||
|                         </div> |  | ||||||
|                     </div> |  | ||||||
|                 </div> |  | ||||||
|             </div>`; |  | ||||||
|  |  | ||||||
|             return confirmAsync({ |  | ||||||
|                 header: lf("Download to your EV3"), |  | ||||||
|                 htmlBody, |  | ||||||
|                 hasCloseIcon: true, |  | ||||||
|                 hideCancel: true, |  | ||||||
|                 hideAgree: false, |  | ||||||
|                 agreeLbl: lf("I got it"), |  | ||||||
|                 className: 'downloaddialog', |  | ||||||
|                 buttons: [canUseWebSerial() ? { |  | ||||||
|                     label: lf("Bluetooth"), |  | ||||||
|                     icon: "bluetooth", |  | ||||||
|                     className: "bluetooth focused", |  | ||||||
|                     onclick: () => { |  | ||||||
|                         pxt.tickEvent("bluetooth.enable"); |  | ||||||
|                         if (bluetoothDialogShown) { |  | ||||||
|                             enableWebSerialAndCompileAsync().done(); |  | ||||||
|                         } else { |  | ||||||
|                             bluetoothDialogShown = true; |  | ||||||
|                             confirmAsync({ |  | ||||||
|                                 header: lf("Bluetooth pairing"), |  | ||||||
|                                 hasCloseIcon: true, |  | ||||||
|                                 hideCancel: true, |  | ||||||
|                                 buttons: [{ |  | ||||||
|                                     label: lf("Help"), |  | ||||||
|                                     icon: "question circle", |  | ||||||
|                                     className: "lightgrey", |  | ||||||
|                                     url: "/bluetooth" |  | ||||||
|                                 }], |  | ||||||
|                                 htmlBody: `<p> |  | ||||||
| ${lf("You will be prompted to select a serial port.")} |  | ||||||
| ${pxt.BrowserUtils.isWindows()  |  | ||||||
|     ? lf("Look for 'Standard Serial over Bluetooth link'.")  |  | ||||||
|     : lf("Loop for 'cu.EV3-SerialPort'.")} |  | ||||||
| ${lf("If you have paired multiple EV3, you might have to try out multiple ports until you find the correct one.")} |  | ||||||
| </p> |  | ||||||
| ` |  | ||||||
|                             }).then(() => enableWebSerialAndCompileAsync()) |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } : undefined, downloadAgain ? { |  | ||||||
|                     label: fn, |  | ||||||
|                     icon: "download", |  | ||||||
|                     className: "lightgrey focused", |  | ||||||
|                     url, |  | ||||||
|                     fileName: fn |  | ||||||
|                 } : undefined, docUrl ? { |  | ||||||
|                     label: lf("Help"), |  | ||||||
|                     icon: "help", |  | ||||||
|                     className: "lightgrey", |  | ||||||
|                     url: docUrl |  | ||||||
|                 } : undefined] |  | ||||||
|                 //timeout: 20000 |  | ||||||
|             }).then(() => { }); |  | ||||||
|         } |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     initAsync().catch(e => { |     initAsync().catch(e => { | ||||||
|         // probably no HID - we'll try this again upon deployment |         // probably no HID - we'll try this again upon deployment | ||||||
|     }) |     }) | ||||||
|     return Promise.resolve<pxt.editor.ExtensionResult>(res); |     return Promise.resolve<pxt.editor.ExtensionResult>(res); | ||||||
| } | } | ||||||
|  |  | ||||||
| // When require()d from node, bind the global pxt namespace |  | ||||||
| // namespace pxt { |  | ||||||
| //     export const dummyExport = 1; |  | ||||||
| // } |  | ||||||
| // eval("if (typeof process === 'object' && process + '' === '[object process]') pxt = global.pxt") |  | ||||||
|   | |||||||
| @@ -1,14 +1,17 @@ | |||||||
| { | { | ||||||
|     "compilerOptions": { |     "compilerOptions": { | ||||||
|         "target": "es5", |         "target": "es5", | ||||||
|         "noImplicitAny": false, |         "noImplicitAny": true, | ||||||
|         "noImplicitReturns": true, |         "noImplicitReturns": true, | ||||||
|  |         "noImplicitThis": true, | ||||||
|  |         "declaration": true, | ||||||
|         "module": "commonjs", |         "module": "commonjs", | ||||||
|  |         "moduleResolution": "node", | ||||||
|  |         "isolatedModules": false, | ||||||
|         "outDir": "../built/editor", |         "outDir": "../built/editor", | ||||||
|         "rootDir": ".", |         "rootDir": ".", | ||||||
|         "newLine": "LF", |         "newLine": "LF", | ||||||
|         "sourceMap": false, |         "sourceMap": false, | ||||||
|         "allowSyntheticDefaultImports": true, |         "jsx": "react" | ||||||
|         "declaration": true |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -3,9 +3,7 @@ | |||||||
|  |  | ||||||
| import { FieldPorts } from "./field_ports"; | import { FieldPorts } from "./field_ports"; | ||||||
| import { FieldMotors } from "./field_motors"; | import { FieldMotors } from "./field_motors"; | ||||||
| import { FieldSpeed } from "./field_speed"; |  | ||||||
| import { FieldBrickButtons } from "./field_brickbuttons"; | import { FieldBrickButtons } from "./field_brickbuttons"; | ||||||
| import { FieldTurnRatio } from "./field_turnratio"; |  | ||||||
| import { FieldColorEnum } from "./field_color"; | import { FieldColorEnum } from "./field_color"; | ||||||
| import { FieldMusic } from "./field_music"; | import { FieldMusic } from "./field_music"; | ||||||
|  |  | ||||||
| @@ -19,15 +17,9 @@ pxt.editor.initFieldExtensionsAsync = function (opts: pxt.editor.FieldExtensionO | |||||||
|         }, { |         }, { | ||||||
|             selector: "motors", |             selector: "motors", | ||||||
|             editor: FieldMotors |             editor: FieldMotors | ||||||
|         }, { |  | ||||||
|             selector: "speed", |  | ||||||
|             editor: FieldSpeed |  | ||||||
|         }, { |         }, { | ||||||
|             selector: "brickbuttons", |             selector: "brickbuttons", | ||||||
|             editor: FieldBrickButtons |             editor: FieldBrickButtons | ||||||
|         }, { |  | ||||||
|             selector: "turnratio", |  | ||||||
|             editor: FieldTurnRatio |  | ||||||
|         }, { |         }, { | ||||||
|             selector: "colorenum", |             selector: "colorenum", | ||||||
|             editor: FieldColorEnum |             editor: FieldColorEnum | ||||||
|   | |||||||
| @@ -121,17 +121,17 @@ export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly. | |||||||
|         Blockly.DropDownDiv.setColour('#ffffff', '#dddddd'); |         Blockly.DropDownDiv.setColour('#ffffff', '#dddddd'); | ||||||
|  |  | ||||||
|         // Calculate positioning based on the field position. |         // Calculate positioning based on the field position. | ||||||
|         var scale = this.sourceBlock_.workspace.scale; |         let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale; | ||||||
|         var bBox = { width: this.size_.width, height: this.size_.height }; |         let bBox = { width: this.size_.width, height: this.size_.height }; | ||||||
|         bBox.width *= scale; |         bBox.width *= scale; | ||||||
|         bBox.height *= scale; |         bBox.height *= scale; | ||||||
|         var position = this.fieldGroup_.getBoundingClientRect(); |         let position = this.fieldGroup_.getBoundingClientRect(); | ||||||
|         var primaryX = position.left + bBox.width / 2; |         let primaryX = position.left + bBox.width / 2; | ||||||
|         var primaryY = position.top + bBox.height; |         let primaryY = position.top + bBox.height; | ||||||
|         var secondaryX = primaryX; |         let secondaryX = primaryX; | ||||||
|         var secondaryY = position.top; |         let secondaryY = position.top; | ||||||
|         // Set bounds to workspace; show the drop-down. |         // Set bounds to workspace; show the drop-down. | ||||||
|         (Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode); |         (Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode); | ||||||
|         (Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY, |         (Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY, | ||||||
|             this.onHide_.bind(this)); |             this.onHide_.bind(this)); | ||||||
|     } |     } | ||||||
| @@ -152,9 +152,10 @@ export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly. | |||||||
|      * Callback for when the drop-down is hidden. |      * Callback for when the drop-down is hidden. | ||||||
|      */ |      */ | ||||||
|     private onHide_ = function () { |     private onHide_ = function () { | ||||||
|         Blockly.DropDownDiv.content_.removeAttribute('role'); |         const content = Blockly.DropDownDiv.getContentDiv(); | ||||||
|         Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup'); |         content.removeAttribute('role'); | ||||||
|         Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant'); |         content.removeAttribute('aria-haspopup'); | ||||||
|         Blockly.DropDownDiv.getContentDiv().style.width = ''; |         content.removeAttribute('aria-activedescendant'); | ||||||
|  |         (content as HTMLElement).style.width = ''; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| @@ -44,7 +44,7 @@ export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Block | |||||||
|      * @return {string} Current colour in '#rrggbb' format. |      * @return {string} Current colour in '#rrggbb' format. | ||||||
|      */ |      */ | ||||||
|     getValue(opt_asHex?: boolean) { |     getValue(opt_asHex?: boolean) { | ||||||
|         var colour = this.mapColour(this.colour_); |         const colour = this.mapColour(this.value_); | ||||||
|         if (!opt_asHex && colour.indexOf('#') > -1) { |         if (!opt_asHex && colour.indexOf('#') > -1) { | ||||||
|             return `0x${colour.replace(/^#/, '')}`; |             return `0x${colour.replace(/^#/, '')}`; | ||||||
|         } |         } | ||||||
| @@ -56,13 +56,13 @@ export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Block | |||||||
|      * @param {string} colour The new colour in '#rrggbb' format. |      * @param {string} colour The new colour in '#rrggbb' format. | ||||||
|      */ |      */ | ||||||
|     setValue(colorStr: string) { |     setValue(colorStr: string) { | ||||||
|         var colour = this.mapEnum(colorStr); |         let colour = this.mapEnum(colorStr); | ||||||
|         if (this.sourceBlock_ && Blockly.Events.isEnabled() && |         if (this.sourceBlock_ && Blockly.Events.isEnabled() && | ||||||
|             this.colour_ != colour) { |             this.value_ != colour) { | ||||||
|             Blockly.Events.fire(new (Blockly as any).Events.BlockChange( |             Blockly.Events.fire(new (Blockly as any).Events.BlockChange( | ||||||
|                 this.sourceBlock_, 'field', this.name, this.colour_, colour)); |                 this.sourceBlock_, 'field', this.name, this.value_, colour)); | ||||||
|         } |         } | ||||||
|         this.colour_ = colour; |         this.value_ = colour; | ||||||
|         if (this.sourceBlock_) { |         if (this.sourceBlock_) { | ||||||
|             this.sourceBlock_.setColour(colour, colour, colour); |             this.sourceBlock_.setColour(colour, colour, colour); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -46,31 +46,31 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|         (this as any).arrowX_ = 0; |         (this as any).arrowX_ = 0; | ||||||
|         /** @type {Number} */ |         /** @type {Number} */ | ||||||
|         this.arrowY_ = 11; |         this.arrowY_ = 11; | ||||||
|         this.arrow_ = Blockly.utils.createSvgElement('image', { |         this.arrow_ = Blockly.utils.dom.createSvgElement('image', { | ||||||
|             'height': (this as any).arrowSize_ + 'px', |             'height': (this as any).arrowSize_ + 'px', | ||||||
|             'width': (this as any).arrowSize_ + 'px' |             'width': (this as any).arrowSize_ + 'px' | ||||||
|         }); |         }, null); | ||||||
|         this.arrow_.setAttributeNS('http://www.w3.org/1999/xlink', |         this.arrow_.setAttributeNS('http://www.w3.org/1999/xlink', | ||||||
|             'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI); |             'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI); | ||||||
|  |  | ||||||
|         this.arrow2_ = Blockly.utils.createSvgElement('image', { |         this.arrow2_ = <SVGImageElement>Blockly.utils.dom.createSvgElement('image', { | ||||||
|             'height': (this as any).arrowSize_ + 'px', |             'height': (this as any).arrowSize_ + 'px', | ||||||
|             'width': (this as any).arrowSize_ + 'px' |             'width': (this as any).arrowSize_ + 'px' | ||||||
|         }); |         }, null); | ||||||
|         this.arrow2_.setAttributeNS('http://www.w3.org/1999/xlink', |         this.arrow2_.setAttributeNS('http://www.w3.org/1999/xlink', | ||||||
|             'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI); |             'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI); | ||||||
|         (this as any).className_ += ' blocklyDropdownText'; |         (this as any).className_ += ' blocklyDropdownText'; | ||||||
|  |  | ||||||
|         // Build the DOM. |         // Build the DOM. | ||||||
|         this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null); |         this.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); | ||||||
|         if (!this.visible_) { |         if (!this.visible_) { | ||||||
|             (this.fieldGroup_ as any).style.display = 'none'; |             (this.fieldGroup_ as any).style.display = 'none'; | ||||||
|         } |         } | ||||||
|         // Adjust X to be flipped for RTL. Position is relative to horizontal start of source block. |         // Adjust X to be flipped for RTL. Position is relative to horizontal start of source block. | ||||||
|         var size = this.getSize(); |         let size = this.getSize(); | ||||||
|         var fieldX = (this.sourceBlock_.RTL) ? -size.width / 2 : size.width / 2; |         let fieldX = (this.sourceBlock_.RTL) ? -size.width / 2 : size.width / 2; | ||||||
|         /** @type {!Element} */ |         /** @type {!Element} */ | ||||||
|         this.textElement_ = Blockly.utils.createSvgElement('text', |         this.textElement_ = Blockly.utils.dom.createSvgElement('text', | ||||||
|             { |             { | ||||||
|                 'class': (this as any).className_, |                 'class': (this as any).className_, | ||||||
|                 'x': fieldX, |                 'x': fieldX, | ||||||
| @@ -79,7 +79,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|             }, |             }, | ||||||
|             this.fieldGroup_); |             this.fieldGroup_); | ||||||
|         fieldX += 10; // size of first group. |         fieldX += 10; // size of first group. | ||||||
|         this.textElement2_ = Blockly.utils.createSvgElement('text', |         this.textElement2_ = <SVGTextElement>Blockly.utils.dom.createSvgElement('text', | ||||||
|             { |             { | ||||||
|                 'class': (this as any).className_, |                 'class': (this as any).className_, | ||||||
|                 'x': fieldX, |                 'x': fieldX, | ||||||
| @@ -89,17 +89,17 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|             this.fieldGroup_); |             this.fieldGroup_); | ||||||
|  |  | ||||||
|         this.updateEditable(); |         this.updateEditable(); | ||||||
|         this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); |         (this.sourceBlock_ as Blockly.BlockSvg).getSvgRoot().appendChild(this.fieldGroup_); | ||||||
|         // Force a render. |         // Force a render. | ||||||
|         this.render_(); |         this.render_(); | ||||||
|         this.size_.width = 0; |         this.isDirty_ = true; | ||||||
|         (this as any).mouseDownWrapper_ = |         (this as any).mouseDownWrapper_ = | ||||||
|             Blockly.bindEventWithChecks_((this as any).getClickTarget_(), 'mousedown', this, |             Blockly.bindEventWithChecks_((this as any).getClickTarget_(), 'mousedown', this, | ||||||
|                 (this as any).onMouseDown_); |                 (this as any).onMouseDown_); | ||||||
|  |  | ||||||
|         // Add second dropdown  |         // Add second dropdown  | ||||||
|         if (this.shouldShowRect_()) { |         if (this.shouldShowRect_()) { | ||||||
|             this.box_ = Blockly.utils.createSvgElement('rect', { |             this.box_ = <SVGRectElement>Blockly.utils.dom.createSvgElement('rect', { | ||||||
|                 'rx': (Blockly.BlockSvg as any).CORNER_RADIUS, |                 'rx': (Blockly.BlockSvg as any).CORNER_RADIUS, | ||||||
|                 'ry': (Blockly.BlockSvg as any).CORNER_RADIUS, |                 'ry': (Blockly.BlockSvg as any).CORNER_RADIUS, | ||||||
|                 'x': 0, |                 'x': 0, | ||||||
| @@ -112,7 +112,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|                 'fill-opacity': 1 |                 'fill-opacity': 1 | ||||||
|             }, null); |             }, null); | ||||||
|             this.fieldGroup_.insertBefore(this.box_, this.textElement_); |             this.fieldGroup_.insertBefore(this.box_, this.textElement_); | ||||||
|             this.box2_ = Blockly.utils.createSvgElement('rect', { |             this.box2_ = <SVGRectElement>Blockly.utils.dom.createSvgElement('rect', { | ||||||
|                 'rx': (Blockly.BlockSvg as any).CORNER_RADIUS, |                 'rx': (Blockly.BlockSvg as any).CORNER_RADIUS, | ||||||
|                 'ry': (Blockly.BlockSvg as any).CORNER_RADIUS, |                 'ry': (Blockly.BlockSvg as any).CORNER_RADIUS, | ||||||
|                 'x': 0, |                 'x': 0, | ||||||
| @@ -128,7 +128,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Force a reset of the text to add the arrow. |         // Force a reset of the text to add the arrow. | ||||||
|         var text = this.text_; |         let text = this.text_; | ||||||
|         this.text_ = null; |         this.text_ = null; | ||||||
|         this.setText(text); |         this.setText(text); | ||||||
|     } |     } | ||||||
| @@ -179,7 +179,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|             // Not rendered yet. |             // Not rendered yet. | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         var text = this.text_; |         let text = this.text_; | ||||||
|         if (text.length > this.maxDisplayLength) { |         if (text.length > this.maxDisplayLength) { | ||||||
|             // Truncate displayed string and add an ellipsis ('...'). |             // Truncate displayed string and add an ellipsis ('...'). | ||||||
|             text = text.substring(0, this.maxDisplayLength - 2) + '\u2026'; |             text = text.substring(0, this.maxDisplayLength - 2) + '\u2026'; | ||||||
| @@ -200,11 +200,11 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|             // Prevent the field from disappearing if empty. |             // Prevent the field from disappearing if empty. | ||||||
|             text = Blockly.Field.NBSP; |             text = Blockly.Field.NBSP; | ||||||
|         } |         } | ||||||
|         var textNode = document.createTextNode(text); |         let textNode = document.createTextNode(text); | ||||||
|         this.textElement2_.appendChild(textNode); |         this.textElement2_.appendChild(textNode); | ||||||
|  |  | ||||||
|         // Cached width is obsolete.  Clear it. |         // Cached width is obsolete.  Clear it. | ||||||
|         this.size_.width = 0; |         this.isDirty_ = true; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     patchDualMotorText(text: string) { |     patchDualMotorText(text: string) { | ||||||
| @@ -233,8 +233,8 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|         if (this.textElement2_) { |         if (this.textElement2_) { | ||||||
|             this.textElement2_.parentNode.appendChild(this.arrow2_); |             this.textElement2_.parentNode.appendChild(this.arrow2_); | ||||||
|         } |         } | ||||||
|         if (this.sourceBlock_ && this.sourceBlock_.rendered) { |         if (this.sourceBlock_ && (<Blockly.BlockSvg>this.sourceBlock_).rendered) { | ||||||
|             this.sourceBlock_.render(); |             (<Blockly.BlockSvg>this.sourceBlock_).render(); | ||||||
|             this.sourceBlock_.bumpNeighbours_(); |             this.sourceBlock_.bumpNeighbours_(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -244,7 +244,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|             return 0; |             return 0; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         var addedWidth = 0; |         let addedWidth = 0; | ||||||
|         if (this.sourceBlock_.RTL) { |         if (this.sourceBlock_.RTL) { | ||||||
|             (this as any).arrow2X_ = (this as any).arrowSize_ - (Blockly.BlockSvg as any).DROPDOWN_ARROW_PADDING; |             (this as any).arrow2X_ = (this as any).arrowSize_ - (Blockly.BlockSvg as any).DROPDOWN_ARROW_PADDING; | ||||||
|             addedWidth = (this as any).arrowSize_ + (Blockly.BlockSvg as any).DROPDOWN_ARROW_PADDING; |             addedWidth = (this as any).arrowSize_ + (Blockly.BlockSvg as any).DROPDOWN_ARROW_PADDING; | ||||||
| @@ -263,10 +263,10 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|         return addedWidth; |         return addedWidth; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     updateWidth() { |     updateSize_() { | ||||||
|         // Calculate width of field |         // Calculate width of field | ||||||
|         var width = Blockly.Field.getCachedWidth(this.textElement_); |         let width = Blockly.Field.getCachedWidth(this.textElement_); | ||||||
|         var width2 = Blockly.Field.getCachedWidth(this.textElement2_); |         let width2 = Blockly.Field.getCachedWidth(this.textElement2_); | ||||||
|  |  | ||||||
|         // Add padding to left and right of text. |         // Add padding to left and right of text. | ||||||
|         if (this.EDITABLE) { |         if (this.EDITABLE) { | ||||||
| @@ -311,15 +311,15 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|  |  | ||||||
|             // First dropdown |             // First dropdown | ||||||
|             // Use one of the following options, medium motor, large motor or large motors (translated) |             // Use one of the following options, medium motor, large motor or large motors (translated) | ||||||
|             const textNode1 = document.createTextNode(this.getFirstValueI11n(this.value_)); |             const textNode1 = document.createTextNode(this.getFirstValueI11n(<string>this.value_)); | ||||||
|             this.textElement_.appendChild(textNode1); |             this.textElement_.appendChild(textNode1); | ||||||
|  |  | ||||||
|             // Second dropdown, no need to translate. Only port numbers |             // Second dropdown, no need to translate. Only port numbers | ||||||
|             if (this.textElement2_) { |             if (this.textElement2_) { | ||||||
|                 const textNode2 = document.createTextNode(this.getSecondValue(this.value_)); |                 const textNode2 = document.createTextNode(this.getSecondValue(<string>this.value_)); | ||||||
|                 this.textElement2_.appendChild(textNode2); |                 this.textElement2_.appendChild(textNode2); | ||||||
|             } |             } | ||||||
|             this.updateWidth(); |             this.updateSize_(); | ||||||
|  |  | ||||||
|             // Update text centering, based on newly calculated width. |             // Update text centering, based on newly calculated width. | ||||||
|             let centerTextX = ((this as any).width1 - this.arrowWidth_) / 2; |             let centerTextX = ((this as any).width1 - this.arrowWidth_) / 2; | ||||||
| @@ -347,8 +347,8 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Apply new text element x position. |             // Apply new text element x position. | ||||||
|             var width = Blockly.Field.getCachedWidth(this.textElement_); |             let width = Blockly.Field.getCachedWidth(this.textElement_); | ||||||
|             var newX = centerTextX - width / 2; |             let newX = centerTextX - width / 2; | ||||||
|             this.textElement_.setAttribute('x', `${newX}`); |             this.textElement_.setAttribute('x', `${newX}`); | ||||||
|  |  | ||||||
|             // Update text centering, based on newly calculated width. |             // Update text centering, based on newly calculated width. | ||||||
| @@ -377,8 +377,8 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Apply new text element x position. |             // Apply new text element x position. | ||||||
|             var width2 = Blockly.Field.getCachedWidth(this.textElement2_); |             let width2 = Blockly.Field.getCachedWidth(this.textElement2_); | ||||||
|             var newX2 = centerTextX2 - width2 / 2; |             let newX2 = centerTextX2 - width2 / 2; | ||||||
|             this.textElement2_.setAttribute('x', `${newX2 + (this as any).width1 + Blockly.BlockSvg.BOX_FIELD_PADDING}`); |             this.textElement2_.setAttribute('x', `${newX2 + (this as any).width1 + Blockly.BlockSvg.BOX_FIELD_PADDING}`); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -401,7 +401,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|         if (Blockly.DropDownDiv.hideIfOwner(this)) { |         if (Blockly.DropDownDiv.hideIfOwner(this)) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         this.isFirst_ = e.clientX - this.getScaledBBox_().left < ((this as any).width1 * this.sourceBlock_.workspace.scale); |         this.isFirst_ = e.clientX - this.getScaledBBox_().left < ((this as any).width1 * (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale); | ||||||
|         // If there is an existing drop-down someone else owns, hide it immediately and clear it. |         // If there is an existing drop-down someone else owns, hide it immediately and clear it. | ||||||
|         Blockly.DropDownDiv.hideWithoutAnimation(); |         Blockly.DropDownDiv.hideWithoutAnimation(); | ||||||
|         Blockly.DropDownDiv.clearContent(); |         Blockly.DropDownDiv.clearContent(); | ||||||
| @@ -411,14 +411,14 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|         // Accessibility properties |         // Accessibility properties | ||||||
|         contentDiv.setAttribute('role', 'menu'); |         contentDiv.setAttribute('role', 'menu'); | ||||||
|         contentDiv.setAttribute('aria-haspopup', 'true'); |         contentDiv.setAttribute('aria-haspopup', 'true'); | ||||||
|         let options = this.getOptions(); |         const foptions = this.getOptions(); // [img info, text] | ||||||
|  |  | ||||||
|         let opts = {}; |         let opts = {}; | ||||||
|         let conts = {}; |         let conts = {}; | ||||||
|         let vals = {}; |         let vals = {}; | ||||||
|         // Go through all option values and split them into groups |         // Go through all option values and split them into groups | ||||||
|         for (let opt = 0; opt < options.length; opt++) { |         for (let opt = 0; opt < foptions.length; opt++) { | ||||||
|             const value = options[opt][1]; |             const value = foptions[opt][1]; | ||||||
|             const motorValue = value.substring(value.indexOf('.') + 1); |             const motorValue = value.substring(value.indexOf('.') + 1); | ||||||
|             const typeValue = motorValue.indexOf('large') == 0 ? 'large' : 'medium'; |             const typeValue = motorValue.indexOf('large') == 0 ? 'large' : 'medium'; | ||||||
|             const portValue = motorValue.indexOf('large') == 0 ? motorValue.substring(5) : motorValue.substring(6); |             const portValue = motorValue.indexOf('large') == 0 ? motorValue.substring(5) : motorValue.substring(6); | ||||||
| @@ -429,13 +429,14 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|             if (!opts[key]) opts[key] = []; |             if (!opts[key]) opts[key] = []; | ||||||
|             opts[key].push(portValue); |             opts[key].push(portValue); | ||||||
|  |  | ||||||
|             conts[text] = options[opt][0]; |             conts[text] = foptions[opt][0]; | ||||||
|             vals[text] = value; |             vals[text] = value; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const currentFirst = this.getFirstValue(this.value_); |         const currentFirst = this.getFirstValue(<string>this.value_); | ||||||
|         const currentSecond = this.getSecondValue(this.value_); |         //const currentSecond = this.getSecondValue(<string>this.value_); | ||||||
|  |  | ||||||
|  |         let options: string[]; | ||||||
|         if (!this.isFirst_) { |         if (!this.isFirst_) { | ||||||
|             options = opts[currentFirst]; |             options = opts[currentFirst]; | ||||||
|         } else { |         } else { | ||||||
| @@ -526,7 +527,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|         Blockly.DropDownDiv.setColour(this.backgroundColour_, this.borderColour_); |         Blockly.DropDownDiv.setColour(this.backgroundColour_, this.borderColour_); | ||||||
|  |  | ||||||
|         // Calculate positioning based on the field position. |         // Calculate positioning based on the field position. | ||||||
|         let scale = this.sourceBlock_.workspace.scale; |         let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale; | ||||||
|         let width = this.isFirst_ ? (this as any).width1 : (this as any).width2; |         let width = this.isFirst_ ? (this as any).width1 : (this as any).width2; | ||||||
|         let bBox = { width: this.size_.width, height: this.size_.height }; |         let bBox = { width: this.size_.width, height: this.size_.height }; | ||||||
|         width *= scale; |         width *= scale; | ||||||
| @@ -538,7 +539,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|         let secondaryX = primaryX; |         let secondaryX = primaryX; | ||||||
|         let secondaryY = position.top; |         let secondaryY = position.top; | ||||||
|         // Set bounds to workspace; show the drop-down. |         // Set bounds to workspace; show the drop-down. | ||||||
|         (Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode); |         (Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode); | ||||||
|         (Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY, |         (Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY, | ||||||
|             this.onHide_.bind(this)); |             this.onHide_.bind(this)); | ||||||
|  |  | ||||||
| @@ -561,10 +562,11 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC | |||||||
|      * Callback for when the drop-down is hidden. |      * Callback for when the drop-down is hidden. | ||||||
|      */ |      */ | ||||||
|     protected onHide_() { |     protected onHide_() { | ||||||
|         Blockly.DropDownDiv.content_.removeAttribute('role'); |         const content = Blockly.DropDownDiv.getContentDiv(); | ||||||
|         Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup'); |         content.removeAttribute('role'); | ||||||
|         Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant'); |         content.removeAttribute('aria-haspopup'); | ||||||
|         Blockly.DropDownDiv.getContentDiv().style.width = ''; |         content.removeAttribute('aria-activedescendant'); | ||||||
|  |         (content as HTMLElement).style.width = ''; | ||||||
|         if (this.isFirst_ && this.box_) { |         if (this.isFirst_ && this.box_) { | ||||||
|             this.box_.setAttribute('fill', this.sourceBlock_.getColour()); |             this.box_.setAttribute('fill', this.sourceBlock_.getColour()); | ||||||
|         } else if (!this.isFirst_ && this.box2_) { |         } else if (!this.isFirst_ && this.box2_) { | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC | |||||||
|         this.width_ = parseInt(options.width) || 380; |         this.width_ = parseInt(options.width) || 380; | ||||||
|  |  | ||||||
|         this.setText = Blockly.FieldDropdown.prototype.setText; |         this.setText = Blockly.FieldDropdown.prototype.setText; | ||||||
|         this.updateWidth = (Blockly.Field as any).prototype.updateWidth; |         this.updateSize_ = (Blockly.Field as any).prototype.updateSize_; | ||||||
|         this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_; |         this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_; | ||||||
|  |  | ||||||
|         if (!pxt.BrowserUtils.isIE() && !soundCache) { |         if (!pxt.BrowserUtils.isIE() && !soundCache) { | ||||||
| @@ -78,14 +78,14 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC | |||||||
|         contentDiv.style.width = (this as any).width_ + 'px'; |         contentDiv.style.width = (this as any).width_ + 'px'; | ||||||
|         contentDiv.style.cssFloat = 'left'; |         contentDiv.style.cssFloat = 'left'; | ||||||
|  |  | ||||||
|         dropdownDiv.style.maxHeight = `410px`; |         (dropdownDiv as HTMLElement).style.maxHeight = `410px`; | ||||||
|         dropdownDiv.appendChild(categoriesDiv); |         dropdownDiv.appendChild(categoriesDiv); | ||||||
|         dropdownDiv.appendChild(contentDiv); |         dropdownDiv.appendChild(contentDiv); | ||||||
|  |  | ||||||
|         Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary()); |         Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary()); | ||||||
|  |  | ||||||
|         // Calculate positioning based on the field position. |         // Calculate positioning based on the field position. | ||||||
|         let scale = this.sourceBlock_.workspace.scale; |         let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale; | ||||||
|         let bBox = { width: this.size_.width, height: this.size_.height }; |         let bBox = { width: this.size_.width, height: this.size_.height }; | ||||||
|         bBox.width *= scale; |         bBox.width *= scale; | ||||||
|         bBox.height *= scale; |         bBox.height *= scale; | ||||||
| @@ -95,7 +95,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC | |||||||
|         let secondaryX = primaryX; |         let secondaryX = primaryX; | ||||||
|         let secondaryY = position.top; |         let secondaryY = position.top; | ||||||
|         // Set bounds to workspace; show the drop-down. |         // Set bounds to workspace; show the drop-down. | ||||||
|         (Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode); |         (Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode); | ||||||
|         (Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY, |         (Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY, | ||||||
|             this.onHide_.bind(this)); |             this.onHide_.bind(this)); | ||||||
|  |  | ||||||
| @@ -236,7 +236,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC | |||||||
|  |  | ||||||
|     protected onHide_() { |     protected onHide_() { | ||||||
|         super.onHide_(); |         super.onHide_(); | ||||||
|         Blockly.DropDownDiv.getContentDiv().style.maxHeight = ''; |         (Blockly.DropDownDiv.getContentDiv() as HTMLElement).style.maxHeight = ''; | ||||||
|         this.stopSounds(); |         this.stopSounds(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ export class FieldPorts extends pxtblockly.FieldImages implements Blockly.FieldC | |||||||
|         this.width_ = parseInt(options.width) || 300; |         this.width_ = parseInt(options.width) || 300; | ||||||
|  |  | ||||||
|         this.setText = Blockly.FieldDropdown.prototype.setText; |         this.setText = Blockly.FieldDropdown.prototype.setText; | ||||||
|         this.updateWidth = (Blockly.Field as any).prototype.updateWidth; |         this.updateSize_ = (Blockly.Field as any).prototype.updateSize_; | ||||||
|         this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_; |         this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,98 +0,0 @@ | |||||||
| /// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts"/> |  | ||||||
| /// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/> |  | ||||||
|  |  | ||||||
| export interface FieldSpeedOptions extends Blockly.FieldCustomOptions { |  | ||||||
|     min?: string; |  | ||||||
|     max?: string; |  | ||||||
|     label?: string; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export class FieldSpeed extends Blockly.FieldSlider implements Blockly.FieldCustom { |  | ||||||
|     public isFieldCustom_ = true; |  | ||||||
|  |  | ||||||
|     private params: any; |  | ||||||
|  |  | ||||||
|     private speedSVG: SVGElement; |  | ||||||
|     private circleBar: SVGCircleElement; |  | ||||||
|     private reporter: SVGTextElement; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Class for a color wheel field. |  | ||||||
|      * @param {number|string} value The initial content of the field. |  | ||||||
|      * @param {Function=} opt_validator An optional function that is called |  | ||||||
|      *     to validate any constraints on what the user entered.  Takes the new |  | ||||||
|      *     text as an argument and returns either the accepted text, a replacement |  | ||||||
|      *     text, or null to abort the change. |  | ||||||
|      * @extends {Blockly.FieldNumber} |  | ||||||
|      * @constructor |  | ||||||
|      */ |  | ||||||
|     constructor(value_: any, params: FieldSpeedOptions, opt_validator?: Function) { |  | ||||||
|         super(String(value_), '-100', '100', null, '10', 'Speed', opt_validator); |  | ||||||
|         this.params = params; |  | ||||||
|         if (this.params['min']) this.min_ = parseFloat(this.params.min); |  | ||||||
|         if (this.params['max']) this.max_ = parseFloat(this.params.max); |  | ||||||
|         if (this.params['label']) this.labelText_ = this.params.label; |  | ||||||
|  |  | ||||||
|         (this as any).sliderColor_ = '#a8aaa8'; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     createLabelDom_(labelText: string) { |  | ||||||
|         var labelContainer = document.createElement('div'); |  | ||||||
|         this.speedSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg") as SVGGElement; |  | ||||||
|         pxsim.svg.hydrate(this.speedSVG, { |  | ||||||
|             viewBox: "0 0 200 100", |  | ||||||
|             width: "170" |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         labelContainer.appendChild(this.speedSVG); |  | ||||||
|  |  | ||||||
|         const outerCircle = pxsim.svg.child(this.speedSVG, "circle", { |  | ||||||
|             'stroke-dasharray': '565.48', 'stroke-dashoffset': '0', |  | ||||||
|             'cx': 100, 'cy': 100, 'r': '90', 'style': `fill:transparent; transition: stroke-dashoffset 0.1s linear;`, |  | ||||||
|             'stroke': '#a8aaa8', 'stroke-width': '1rem' |  | ||||||
|         }) as SVGCircleElement; |  | ||||||
|         this.circleBar = pxsim.svg.child(this.speedSVG, "circle", { |  | ||||||
|             'stroke-dasharray': '565.48', 'stroke-dashoffset': '0', |  | ||||||
|             'cx': 100, 'cy': 100, 'r': '90', 'style': `fill:transparent; transition: stroke-dashoffset 0.1s linear;`, |  | ||||||
|             'stroke': '#f12a21', 'stroke-width': '1rem' |  | ||||||
|         }) as SVGCircleElement; |  | ||||||
|  |  | ||||||
|         this.reporter = pxsim.svg.child(this.speedSVG, "text", { |  | ||||||
|             'x': 100, 'y': 80, |  | ||||||
|             'text-anchor': 'middle', 'dominant-baseline': 'middle', |  | ||||||
|             'style': 'font-size: 50px', |  | ||||||
|             'class': 'sim-text inverted number' |  | ||||||
|         }) as SVGTextElement; |  | ||||||
|  |  | ||||||
|         // labelContainer.setAttribute('class', 'blocklyFieldSliderLabel'); |  | ||||||
|         var readout = document.createElement('span'); |  | ||||||
|         readout.setAttribute('class', 'blocklyFieldSliderReadout'); |  | ||||||
|         // var label = document.createElement('span'); |  | ||||||
|         // label.setAttribute('class', 'blocklyFieldSliderLabelText'); |  | ||||||
|         // label.innerHTML = labelText; |  | ||||||
|         // labelContainer.appendChild(label); |  | ||||||
|         // labelContainer.appendChild(readout); |  | ||||||
|         return [labelContainer, readout]; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     setReadout_(readout: Element, value: string) { |  | ||||||
|         let x = parseFloat(value) || 0; |  | ||||||
|         this.updateSpeed(x); |  | ||||||
|         // Update reporter |  | ||||||
|         this.reporter.textContent = `${x}%`; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private updateSpeed(speed: number) { |  | ||||||
|         let sign = this.sign(speed); |  | ||||||
|         speed = (Math.abs(speed) / 100 * 50) + 50; |  | ||||||
|         if (sign == -1) speed = 50 - speed; |  | ||||||
|         let c = Math.PI * (90 * 2); |  | ||||||
|         let pct = ((100 - speed) / 100) * c; |  | ||||||
|         this.circleBar.setAttribute('stroke-dashoffset', `${pct}`); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // A re-implementation of Math.sign (since IE11 doesn't support it) |  | ||||||
|     private sign(num: number) { |  | ||||||
|         return num ? num < 0 ? -1 : 1 : 0; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,108 +0,0 @@ | |||||||
| /// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts"/> |  | ||||||
| /// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/> |  | ||||||
|  |  | ||||||
| export interface FieldTurnRatioOptions extends Blockly.FieldCustomOptions { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export class FieldTurnRatio extends Blockly.FieldSlider implements Blockly.FieldCustom { |  | ||||||
|     public isFieldCustom_ = true; |  | ||||||
|  |  | ||||||
|     private params: any; |  | ||||||
|  |  | ||||||
|     private path_: SVGPathElement; |  | ||||||
|     private reporter_: SVGTextElement; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Class for a color wheel field. |  | ||||||
|      * @param {number|string} value The initial content of the field. |  | ||||||
|      * @param {Function=} opt_validator An optional function that is called |  | ||||||
|      *     to validate any constraints on what the user entered.  Takes the new |  | ||||||
|      *     text as an argument and returns either the accepted text, a replacement |  | ||||||
|      *     text, or null to abort the change. |  | ||||||
|      * @extends {Blockly.FieldNumber} |  | ||||||
|      * @constructor |  | ||||||
|      */ |  | ||||||
|     constructor(value_: any, params: FieldTurnRatioOptions, opt_validator?: Function) { |  | ||||||
|         super(String(value_), '-200', '200', null, '10', 'TurnRatio', opt_validator); |  | ||||||
|         this.params = params; |  | ||||||
|         (this as any).sliderColor_ = '#a8aaa8'; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static HALF = 80; |  | ||||||
|     static HANDLE_RADIUS = 30; |  | ||||||
|     static RADIUS = FieldTurnRatio.HALF - FieldTurnRatio.HANDLE_RADIUS - 1; |  | ||||||
|  |  | ||||||
|     createLabelDom_(labelText: string) { |  | ||||||
|         let labelContainer = document.createElement('div'); |  | ||||||
|         let svg = Blockly.utils.createSvgElement('svg', { |  | ||||||
|             'xmlns': 'http://www.w3.org/2000/svg', |  | ||||||
|             'xmlns:html': 'http://www.w3.org/1999/xhtml', |  | ||||||
|             'xmlns:xlink': 'http://www.w3.org/1999/xlink', |  | ||||||
|             'version': '1.1', |  | ||||||
|             'height': (FieldTurnRatio.HALF + FieldTurnRatio.HANDLE_RADIUS + 10) + 'px', |  | ||||||
|             'width': (FieldTurnRatio.HALF * 2) + 'px' |  | ||||||
|         }, labelContainer); |  | ||||||
|         let defs = Blockly.utils.createSvgElement('defs', {}, svg); |  | ||||||
|         let marker = Blockly.utils.createSvgElement('marker', { |  | ||||||
|             'id': 'head', |  | ||||||
|             'orient': "auto", |  | ||||||
|             'markerWidth': '2', |  | ||||||
|             'markerHeight': '4', |  | ||||||
|             'refX': '0.1', 'refY': '1.5' |  | ||||||
|         }, defs); |  | ||||||
|         let markerPath = Blockly.utils.createSvgElement('path', { |  | ||||||
|             'd': 'M0,0 V3 L1.5,1.5 Z', |  | ||||||
|             'fill': '#f12a21' |  | ||||||
|         }, marker); |  | ||||||
|         this.reporter_ = pxsim.svg.child(svg, "text", { |  | ||||||
|             'x': FieldTurnRatio.HALF, 'y': 96, |  | ||||||
|             'text-anchor': 'middle', 'dominant-baseline': 'middle', |  | ||||||
|             'style': 'font-size: 50px', |  | ||||||
|             'class': 'sim-text inverted number' |  | ||||||
|         }) as SVGTextElement; |  | ||||||
|         this.path_ = Blockly.utils.createSvgElement('path', { |  | ||||||
|             'x1': FieldTurnRatio.HALF, |  | ||||||
|             'y1': FieldTurnRatio.HALF, |  | ||||||
|             'marker-end': 'url(#head)', |  | ||||||
|             'style': 'fill: none; stroke: #f12a21; stroke-width: 10' |  | ||||||
|         }, svg); |  | ||||||
|         this.updateGraph_(); |  | ||||||
|         let readout = document.createElement('span'); |  | ||||||
|         readout.setAttribute('class', 'blocklyFieldSliderReadout'); |  | ||||||
|         return [labelContainer, readout]; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     updateGraph_() { |  | ||||||
|         if (!this.path_) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         let v = goog.math.clamp(parseFloat(this.getText()), -200, 200); |  | ||||||
|         if (isNaN(v)) { |  | ||||||
|             v = 0; |  | ||||||
|         } |  | ||||||
|         const x = v / 100; |  | ||||||
|         const nx = Math.max(-1, Math.min(1, x)); |  | ||||||
|         const theta = Math.max(nx) * Math.PI / 2; |  | ||||||
|         const r = FieldTurnRatio.RADIUS - 6; |  | ||||||
|         let cx = FieldTurnRatio.HALF; |  | ||||||
|         const cy = FieldTurnRatio.HALF - 22; |  | ||||||
|         if (Math.abs(x) > 1) { |  | ||||||
|             cx -= (x - (x > 0 ? 1 : -1)) * r / 2; // move center of circle |  | ||||||
|         } |  | ||||||
|         const alpha = 0.2 + Math.abs(nx) * 0.5; |  | ||||||
|         const y1 = r * alpha; |  | ||||||
|         const y2 = r * Math.sin(Math.PI / 2 - theta); |  | ||||||
|         const x2 = r * Math.cos(Math.PI / 2 - theta); |  | ||||||
|         const y3 = y2 - r * alpha * Math.cos(2 * theta); |  | ||||||
|         const x3 = x2 - r * alpha * Math.sin(2 * theta); |  | ||||||
|  |  | ||||||
|         const d = `M ${cx} ${cy} C ${cx} ${cy - y1} ${cx + x3} ${cy - y3} ${cx + x2} ${cy - y2}`; |  | ||||||
|         this.path_.setAttribute('d', d); |  | ||||||
|  |  | ||||||
|         this.reporter_.textContent = `${v}`; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     setReadout_(readout: Element, value: string) { |  | ||||||
|         this.updateGraph_(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										9
									
								
								libs/base/enums.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								libs/base/enums.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -22,13 +22,8 @@ | |||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     declare const enum ValType { |     declare const enum PerfCounters { | ||||||
|     Undefined = 0, |     GC = 0, | ||||||
|     Boolean = 1, |  | ||||||
|     Number = 2, |  | ||||||
|     String = 3, |  | ||||||
|     Object = 4, |  | ||||||
|     Function = 5, |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| // Auto-generated. Do not edit. Really. | // Auto-generated. Do not edit. Really. | ||||||
|   | |||||||
							
								
								
									
										76
									
								
								libs/base/shims.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										76
									
								
								libs/base/shims.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4,6 +4,18 @@ | |||||||
|  |  | ||||||
|     //% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte |     //% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte | ||||||
| declare interface Buffer { | declare interface Buffer { | ||||||
|  |     /** | ||||||
|  |      * Reads an unsigned byte at a particular location | ||||||
|  |      */ | ||||||
|  |     //% shim=BufferMethods::getUint8 | ||||||
|  |     getUint8(off: int32): int32; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Writes an unsigned byte at a particular location | ||||||
|  |      */ | ||||||
|  |     //% shim=BufferMethods::setUint8 | ||||||
|  |     setUint8(off: int32, v: int32): void; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Write a number in specified format in the buffer. |      * Write a number in specified format in the buffer. | ||||||
|      */ |      */ | ||||||
| @@ -42,6 +54,12 @@ declare interface Buffer { | |||||||
|     //% start.defl=0 length.defl=-1 shim=BufferMethods::shift |     //% start.defl=0 length.defl=-1 shim=BufferMethods::shift | ||||||
|     shift(offset: int32, start?: int32, length?: int32): void; |     shift(offset: int32, start?: int32, length?: int32): void; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Convert a buffer to string assuming UTF8 encoding | ||||||
|  |      */ | ||||||
|  |     //% shim=BufferMethods::toString | ||||||
|  |     toString(): string; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Convert a buffer to its hexadecimal representation. |      * Convert a buffer to its hexadecimal representation. | ||||||
|      */ |      */ | ||||||
| @@ -72,6 +90,13 @@ declare namespace control { | |||||||
|      */ |      */ | ||||||
|     //% shim=control::createBuffer |     //% shim=control::createBuffer | ||||||
|     function createBuffer(size: int32): Buffer; |     function createBuffer(size: int32): Buffer; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a new buffer with UTF8-encoded string | ||||||
|  |      * @param str the string to put in the buffer | ||||||
|  |      */ | ||||||
|  |     //% shim=control::createBufferFromUTF8 | ||||||
|  |     function createBufferFromUTF8(str: string): Buffer; | ||||||
| } | } | ||||||
| declare namespace loops { | declare namespace loops { | ||||||
|  |  | ||||||
| @@ -101,6 +126,12 @@ declare namespace control { | |||||||
|     //% blockId=control_running_time block="millis (ms)" shim=control::millis |     //% blockId=control_running_time block="millis (ms)" shim=control::millis | ||||||
|     function millis(): int32; |     function millis(): int32; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets current time in microseconds. Overflows every ~18 minutes. | ||||||
|  |      */ | ||||||
|  |     //% shim=control::micros | ||||||
|  |     function micros(): int32; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Used internally |      * Used internally | ||||||
|      */ |      */ | ||||||
| @@ -143,11 +174,54 @@ declare namespace control { | |||||||
|     //% help=control/device-serial-number shim=control::deviceSerialNumber |     //% help=control/device-serial-number shim=control::deviceSerialNumber | ||||||
|     function deviceSerialNumber(): int32; |     function deviceSerialNumber(): int32; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Derive a unique, consistent 64-bit serial number of this device from internal data. | ||||||
|  |      */ | ||||||
|  |     //% blockId="control_device_long_serial_number" block="device long serial number" weight=9 | ||||||
|  |     //% help=control/device-long-serial-number shim=control::deviceLongSerialNumber | ||||||
|  |     function deviceLongSerialNumber(): Buffer; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * |      * | ||||||
|      */ |      */ | ||||||
|     //% shim=control::__log |     //% shim=control::__log | ||||||
|     function __log(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. | // Auto-generated. Do not edit. Really. | ||||||
|   | |||||||
| @@ -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(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										407
									
								
								libs/core/dal.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										407
									
								
								libs/core/dal.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,305 @@ | |||||||
| // Auto-generated. Do not edit. | // Auto-generated. Do not edit. | ||||||
| declare const enum DAL { | 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_INPUTS = 4, | ||||||
|     NUM_OUTPUTS = 4, |     NUM_OUTPUTS = 4, | ||||||
|     LCD_WIDTH = 178, |     LCD_WIDTH = 178, | ||||||
| @@ -46,44 +345,66 @@ declare const enum DAL { | |||||||
|     CONN_OUTPUT_TACHO = 125, |     CONN_OUTPUT_TACHO = 125, | ||||||
|     CONN_NONE = 126, |     CONN_NONE = 126, | ||||||
|     CONN_ERROR = 127, |     CONN_ERROR = 127, | ||||||
|     opProgramStart = 0x03, |     opProgramStart = 3, | ||||||
|     opOutputGetType = 0xA0, |     opOutputGetType = 160, | ||||||
|     opOutputSetType = 0xA1, |     opOutputSetType = 161, | ||||||
|     opOutputReset = 0xA2, |     opOutputReset = 162, | ||||||
|     opOutputStop = 0xA3, |     opOutputStop = 163, | ||||||
|     opOutputPower = 0xA4, |     opOutputPower = 164, | ||||||
|     opOutputSpeed = 0xA5, |     opOutputSpeed = 165, | ||||||
|     opOutputStart = 0xA6, |     opOutputStart = 166, | ||||||
|     opOutputPolarity = 0xA7, |     opOutputPolarity = 167, | ||||||
|     opOutputRead = 0xA8, |     opOutputRead = 168, | ||||||
|     opOutputTest = 0xA9, |     opOutputTest = 169, | ||||||
|     opOutputReady = 0xAA, |     opOutputReady = 170, | ||||||
|     opOutputPosition = 0xAB, |     opOutputPosition = 171, | ||||||
|     opOutputStepPower = 0xAC, |     opOutputStepPower = 172, | ||||||
|     opOutputTimePower = 0xAD, |     opOutputTimePower = 173, | ||||||
|     opOutputStepSpeed = 0xAE, |     opOutputStepSpeed = 174, | ||||||
|     opOutputTimeSpeed = 0xAF, |     opOutputTimeSpeed = 175, | ||||||
|     opOutputStepSync = 0xB0, |     opOutputStepSync = 176, | ||||||
|     opOutputTimeSync = 0xB1, |     opOutputTimeSync = 177, | ||||||
|     opOutputClearCount = 0xB2, |     opOutputClearCount = 178, | ||||||
|     opOutputGetCount = 0xB3, |     opOutputGetCount = 179, | ||||||
|     opOutputProgramStop = 0xB4, |     opOutputProgramStop = 180, | ||||||
|     BUTTON_ID_UP = 0x01, |     BUTTON_ID_UP = 1, | ||||||
|     BUTTON_ID_ENTER = 0x02, |     BUTTON_ID_ENTER = 2, | ||||||
|     BUTTON_ID_DOWN = 0x04, |     BUTTON_ID_DOWN = 4, | ||||||
|     BUTTON_ID_RIGHT = 0x08, |     BUTTON_ID_RIGHT = 8, | ||||||
|     BUTTON_ID_LEFT = 0x10, |     BUTTON_ID_LEFT = 16, | ||||||
|     BUTTON_ID_ESCAPE = 0x20, |     BUTTON_ID_ESCAPE = 32, | ||||||
|     // built/dockermake/pxtapp/pxt.h |     // /pxtapp/platform.h | ||||||
|  |     PXT_GC_THREAD_LIST = 1, | ||||||
|  |     // /pxtapp/pxt.h | ||||||
|     DEVICE_EVT_ANY = 0, |     DEVICE_EVT_ANY = 0, | ||||||
|     DEVICE_ID_NOTIFY = 10000, |     DEVICE_ID_NOTIFY = 10000, | ||||||
|     DEVICE_ID_NOTIFY_ONE = 10001, |     DEVICE_ID_NOTIFY_ONE = 10001, | ||||||
|     // built/dockermake/pxtapp/pxtbase.h |     IMAGE_BITS = 1, | ||||||
|     PXT_REF_TAG_STRING = 1, |     // /pxtapp/pxtbase.h | ||||||
|     PXT_REF_TAG_BUFFER = 2, |     PXT32 = 1, | ||||||
|     PXT_REF_TAG_IMAGE = 3, |     PXT64 = 1, | ||||||
|     PXT_REF_TAG_NUMBER = 32, |     PXT_VTABLE_SHIFT = 2, | ||||||
|     PXT_REF_TAG_ACTION = 33, |     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, |     Int8LE = 1, | ||||||
|     UInt8LE = 2, |     UInt8LE = 2, | ||||||
|     Int16LE = 3, |     Int16LE = 3, | ||||||
| @@ -100,12 +421,10 @@ declare const enum DAL { | |||||||
|     Float64LE = 14, |     Float64LE = 14, | ||||||
|     Float32BE = 15, |     Float32BE = 15, | ||||||
|     Float64BE = 16, |     Float64BE = 16, | ||||||
|     Undefined = 0, |     NUM_TRY_FRAME_REGS = 3, | ||||||
|     Boolean = 1, |     GC = 0, | ||||||
|     Number = 2, |     // /pxtapp/pxtconfig.h | ||||||
|     String = 3, |     PXT_GC = 1, | ||||||
|     Object = 4, |     // /pxtapp/pxtcore.h | ||||||
|     Function = 5, |     PXT_HARD_FLOAT = 1, | ||||||
|     // built/dockermake/pxtapp/pxtconfig.h |  | ||||||
|     // built/dockermake/pxtapp/pxtcore.h |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,589 +0,0 @@ | |||||||
| #include "pxt.h" |  | ||||||
|  |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <sys/time.h> |  | ||||||
| #include <time.h> |  | ||||||
| #include <cstdarg> |  | ||||||
| #include <pthread.h> |  | ||||||
| #include <unistd.h> |  | ||||||
| #include <dirent.h> |  | ||||||
| #include <signal.h> |  | ||||||
| #include <sys/types.h> |  | ||||||
| #include <sys/stat.h> |  | ||||||
| #include <errno.h> |  | ||||||
| #include <fcntl.h> |  | ||||||
| #include <malloc.h> |  | ||||||
| #include <sys/mman.h> |  | ||||||
| #include <sys/ioctl.h> |  | ||||||
| #include "ev3const.h" |  | ||||||
|  |  | ||||||
| #define THREAD_DBG(...) |  | ||||||
|  |  | ||||||
| #define MALLOC_LIMIT (8 * 1024 * 1024) |  | ||||||
| #define MALLOC_CHECK_PERIOD (1024 * 1024) |  | ||||||
|  |  | ||||||
| void *xmalloc(size_t sz) { |  | ||||||
|     static size_t allocBytes = 0; |  | ||||||
|     allocBytes += sz; |  | ||||||
|     if (allocBytes >= MALLOC_CHECK_PERIOD) { |  | ||||||
|         allocBytes = 0; |  | ||||||
|         auto info = mallinfo(); |  | ||||||
|         DMESG("malloc used: %d kb", info.uordblks / 1024); |  | ||||||
|         if (info.uordblks > MALLOC_LIMIT) { |  | ||||||
|             target_panic(904); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     auto r = malloc(sz); |  | ||||||
|     if (r == NULL) |  | ||||||
|         target_panic(905); // shouldn't happen |  | ||||||
|     return r; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void *operator new(size_t size) { |  | ||||||
|     return xmalloc(size); |  | ||||||
| } |  | ||||||
| void *operator new[](size_t size) { |  | ||||||
|     return xmalloc(size); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void operator delete(void *p) { |  | ||||||
|     free(p); |  | ||||||
| } |  | ||||||
| void operator delete[](void *p) { |  | ||||||
|     free(p); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| namespace pxt { |  | ||||||
|  |  | ||||||
| static int startTime; |  | ||||||
| static pthread_mutex_t execMutex; |  | ||||||
| static pthread_mutex_t eventMutex; |  | ||||||
| static pthread_cond_t newEventBroadcast; |  | ||||||
|  |  | ||||||
| struct Thread { |  | ||||||
|     struct Thread *next; |  | ||||||
|     Action act; |  | ||||||
|     TValue arg0; |  | ||||||
|     pthread_t pid; |  | ||||||
|     pthread_cond_t waitCond; |  | ||||||
|     int waitSource; |  | ||||||
|     int waitValue; |  | ||||||
|     TValue data0; |  | ||||||
|     TValue data1; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| static struct Thread *allThreads; |  | ||||||
| static struct Event *eventHead, *eventTail; |  | ||||||
| static int usbFD; |  | ||||||
| static int dmesgPtr; |  | ||||||
| static int dmesgSerialPtr; |  | ||||||
| static char dmesgBuf[4096]; |  | ||||||
|  |  | ||||||
| struct Event { |  | ||||||
|     struct Event *next; |  | ||||||
|     int source; |  | ||||||
|     int value; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| Event lastEvent; |  | ||||||
|  |  | ||||||
| Event *mkEvent(int source, int value) { |  | ||||||
|     auto res = new Event(); |  | ||||||
|     memset(res, 0, sizeof(Event)); |  | ||||||
|     res->source = source; |  | ||||||
|     res->value = value; |  | ||||||
|     return res; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #define USB_MAGIC 0x3d3f |  | ||||||
| #define USB_SERIAL 1 |  | ||||||
| #define USB_RESTART 2 |  | ||||||
| #define USB_DMESG 3 |  | ||||||
|  |  | ||||||
| struct UsbPacket { |  | ||||||
|     uint16_t size; |  | ||||||
|     uint16_t msgcount; |  | ||||||
|     uint16_t magic; |  | ||||||
|     uint16_t code; |  | ||||||
|     char buf[1024 - 8]; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| void *usbThread(void *) { |  | ||||||
|     UsbPacket pkt; |  | ||||||
|     UsbPacket resp; |  | ||||||
|     while (true) { |  | ||||||
|         int len = read(usbFD, &pkt, sizeof(pkt)); |  | ||||||
|         if (len <= 4) { |  | ||||||
|             sleep_core_us(20000); |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
|         resp.msgcount = pkt.msgcount; |  | ||||||
|         if (pkt.magic == USB_MAGIC) { |  | ||||||
|             if (pkt.code == USB_RESTART) { |  | ||||||
|                 target_reset(); |  | ||||||
|             } else if (pkt.code == USB_DMESG) { |  | ||||||
|                 dumpDmesg(); |  | ||||||
|             } |  | ||||||
|             /* |  | ||||||
|             resp.magic = pkt.magic; |  | ||||||
|             resp.code = pkt.code; |  | ||||||
|             resp.size = 8; |  | ||||||
|             write(usbFD, &resp, sizeof(resp)); |  | ||||||
|             */ |  | ||||||
|         } else { |  | ||||||
|             resp.magic = 0xffff; |  | ||||||
|             resp.size = 4; |  | ||||||
|             write(usbFD, &resp, sizeof(resp)); |  | ||||||
|         } |  | ||||||
|         sleep_core_us(1000); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void startUsb() { |  | ||||||
|     usbFD = open("/dev/lms_usbdev", O_RDWR, 0666); |  | ||||||
|     pthread_t pid; |  | ||||||
|     pthread_create(&pid, NULL, usbThread, NULL); |  | ||||||
|     pthread_detach(pid); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void *exitThread(void *) { |  | ||||||
|     int fd = open("/dev/lms_ui", O_RDWR, 0666); |  | ||||||
|     if (fd < 0) |  | ||||||
|         return 0; |  | ||||||
|     uint8_t *data = |  | ||||||
|         (uint8_t *)mmap(NULL, NUM_BUTTONS, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |  | ||||||
|     if (data == MAP_FAILED) { |  | ||||||
|         close(fd); |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
|     for (;;) { |  | ||||||
|         if (data[5]) |  | ||||||
|             target_reset(); |  | ||||||
|         sleep_core_us(50000); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void startExitThread() { |  | ||||||
|     pthread_t pid; |  | ||||||
|     pthread_create(&pid, NULL, exitThread, NULL); |  | ||||||
|     pthread_detach(pid); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void sendUsb(uint16_t code, const char *data, int len) { |  | ||||||
|     while (len > 0) { |  | ||||||
|         int sz = len; |  | ||||||
|         if (sz > 1000) |  | ||||||
|             sz = 1000; |  | ||||||
|         UsbPacket pkt = {(uint16_t)(6 + sz), 0, USB_MAGIC, code, {}}; |  | ||||||
|         memcpy(pkt.buf, data, sz); |  | ||||||
|         write(usbFD, &pkt, sizeof(pkt)); |  | ||||||
|         len -= sz; |  | ||||||
|         data += sz; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void sendSerial(const char *data, int len) { |  | ||||||
|     sendUsb(USB_SERIAL, data, len); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| volatile bool paniced; |  | ||||||
| extern "C" void drawPanic(int code); |  | ||||||
|  |  | ||||||
| extern "C" void target_panic(int error_code) { |  | ||||||
|     char buf[50]; |  | ||||||
|     paniced = true; |  | ||||||
|     pthread_mutex_trylock(&execMutex); |  | ||||||
|  |  | ||||||
|     snprintf(buf, sizeof(buf), "\nPANIC %d\n", error_code); |  | ||||||
|  |  | ||||||
|     drawPanic(error_code); |  | ||||||
|     DMESG("PANIC %d", error_code); |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < 10; ++i) { |  | ||||||
|         sendSerial(buf, strlen(buf)); |  | ||||||
|         sleep_core_us(500 * 1000); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     target_reset(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void startUser() { |  | ||||||
|     pthread_mutex_lock(&execMutex); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void stopUser() { |  | ||||||
|     pthread_mutex_unlock(&execMutex); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void sleep_core_us(uint64_t us) { |  | ||||||
|     struct timespec ts; |  | ||||||
|     ts.tv_sec = us / 1000000; |  | ||||||
|     ts.tv_nsec = (us % 1000000) * 1000; |  | ||||||
|     while (nanosleep(&ts, &ts)) |  | ||||||
|         ; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void sleep_ms(uint32_t ms) { |  | ||||||
|     stopUser(); |  | ||||||
|     sleep_core_us(ms * 1000); |  | ||||||
|     startUser(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void sleep_us(uint64_t us) { |  | ||||||
|     if (us > 50000) { |  | ||||||
|         sleep_ms(us / 1000); |  | ||||||
|     } |  | ||||||
|     sleep_core_us(us); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| uint64_t currTime() { |  | ||||||
|     struct timeval tv; |  | ||||||
|     gettimeofday(&tv, NULL); |  | ||||||
|     return tv.tv_sec * 1000 + tv.tv_usec / 1000; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int current_time_ms() { |  | ||||||
|     return currTime() - startTime; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void disposeThread(Thread *t) { |  | ||||||
|     if (allThreads == t) { |  | ||||||
|         allThreads = t->next; |  | ||||||
|     } else { |  | ||||||
|         for (auto tt = allThreads; tt; tt = tt->next) { |  | ||||||
|             if (tt->next == t) { |  | ||||||
|                 tt->next = t->next; |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     decr(t->act); |  | ||||||
|     decr(t->arg0); |  | ||||||
|     decr(t->data0); |  | ||||||
|     decr(t->data1); |  | ||||||
|     pthread_cond_destroy(&t->waitCond); |  | ||||||
|     delete t; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void runAct(Thread *thr) { |  | ||||||
|     startUser(); |  | ||||||
|     pxt::runAction1(thr->act, thr->arg0); |  | ||||||
|     stopUser(); |  | ||||||
|     disposeThread(thr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void mainThread(Thread *) {} |  | ||||||
|  |  | ||||||
| void setupThread(Action a, TValue arg = 0, void (*runner)(Thread *) = NULL, TValue d0 = 0, |  | ||||||
|                  TValue d1 = 0) { |  | ||||||
|     if (runner == NULL) |  | ||||||
|         runner = runAct; |  | ||||||
|     auto thr = new Thread(); |  | ||||||
|     memset(thr, 0, sizeof(Thread)); |  | ||||||
|     thr->next = allThreads; |  | ||||||
|     allThreads = thr; |  | ||||||
|     thr->act = incr(a); |  | ||||||
|     thr->arg0 = incr(arg); |  | ||||||
|     thr->data0 = incr(d0); |  | ||||||
|     thr->data1 = incr(d1); |  | ||||||
|     pthread_cond_init(&thr->waitCond, NULL); |  | ||||||
|     if (runner == mainThread) { |  | ||||||
|         thr->pid = pthread_self(); |  | ||||||
|     } else { |  | ||||||
|         pthread_create(&thr->pid, NULL, (void *(*)(void *))runner, thr); |  | ||||||
|         THREAD_DBG("setup thread: %p (pid %p)", thr, thr->pid); |  | ||||||
|         pthread_detach(thr->pid); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void releaseFiber() { |  | ||||||
|     stopUser(); |  | ||||||
|     pthread_exit(NULL); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void runInParallel(Action a) { |  | ||||||
|     setupThread(a); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void runFor(Thread *t) { |  | ||||||
|     startUser(); |  | ||||||
|     while (true) { |  | ||||||
|         pxt::runAction0(t->act); |  | ||||||
|         sleep_ms(20); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void runForever(Action a) { |  | ||||||
|     setupThread(a, 0, runFor); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void waitForEvent(int source, int value) { |  | ||||||
|     THREAD_DBG("waitForEv: %d %d", source, value); |  | ||||||
|     auto self = pthread_self(); |  | ||||||
|     for (auto t = allThreads; t; t = t->next) { |  | ||||||
|         THREAD_DBG("t: %p", t); |  | ||||||
|         if (t->pid == self) { |  | ||||||
|             pthread_mutex_lock(&eventMutex); |  | ||||||
|             t->waitSource = source; |  | ||||||
|             t->waitValue = value; |  | ||||||
|             stopUser(); |  | ||||||
|             // spourious wake ups may occur they say |  | ||||||
|             while (t->waitSource) { |  | ||||||
|                 pthread_cond_wait(&t->waitCond, &eventMutex); |  | ||||||
|             } |  | ||||||
|             pthread_mutex_unlock(&eventMutex); |  | ||||||
|             startUser(); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     DMESG("current thread not registered!"); |  | ||||||
|     target_panic(901); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void dispatchEvent(Event &e) { |  | ||||||
|     lastEvent = e; |  | ||||||
|  |  | ||||||
|     auto curr = findBinding(e.source, e.value); |  | ||||||
|     if (curr) |  | ||||||
|         setupThread(curr->action, fromInt(e.value)); |  | ||||||
|  |  | ||||||
|     curr = findBinding(e.source, DEVICE_EVT_ANY); |  | ||||||
|     if (curr) |  | ||||||
|         setupThread(curr->action, fromInt(e.value)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void *evtDispatcher(void *dummy) { |  | ||||||
|     pthread_mutex_lock(&eventMutex); |  | ||||||
|     while (true) { |  | ||||||
|         pthread_cond_wait(&newEventBroadcast, &eventMutex); |  | ||||||
|         while (eventHead != NULL) { |  | ||||||
|             if (paniced) |  | ||||||
|                 return 0; |  | ||||||
|             Event *ev = eventHead; |  | ||||||
|             eventHead = ev->next; |  | ||||||
|             if (eventHead == NULL) |  | ||||||
|                 eventTail = NULL; |  | ||||||
|  |  | ||||||
|             for (auto thr = allThreads; thr; thr = thr->next) { |  | ||||||
|                 if (paniced) |  | ||||||
|                     return 0; |  | ||||||
|                 if (thr->waitSource == 0) |  | ||||||
|                     continue; |  | ||||||
|                 if (thr->waitValue != ev->value && thr->waitValue != DEVICE_EVT_ANY) |  | ||||||
|                     continue; |  | ||||||
|                 if (thr->waitSource == ev->source) { |  | ||||||
|                     thr->waitSource = 0; // once! |  | ||||||
|                     pthread_cond_broadcast(&thr->waitCond); |  | ||||||
|                 } else if (thr->waitSource == DEVICE_ID_NOTIFY && |  | ||||||
|                            ev->source == DEVICE_ID_NOTIFY_ONE) { |  | ||||||
|                     thr->waitSource = 0; // once! |  | ||||||
|                     pthread_cond_broadcast(&thr->waitCond); |  | ||||||
|                     break; // do not wake up any other threads |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             dispatchEvent(*ev); |  | ||||||
|             delete ev; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int allocateNotifyEvent() { |  | ||||||
|     static volatile int notifyId; |  | ||||||
|     pthread_mutex_lock(&eventMutex); |  | ||||||
|     int res = ++notifyId; |  | ||||||
|     pthread_mutex_unlock(&eventMutex); |  | ||||||
|     return res; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void raiseEvent(int id, int event) { |  | ||||||
|     auto e = mkEvent(id, event); |  | ||||||
|     pthread_mutex_lock(&eventMutex); |  | ||||||
|     if (eventTail == NULL) { |  | ||||||
|         if (eventHead != NULL) |  | ||||||
|             target_panic(902); |  | ||||||
|         eventHead = eventTail = e; |  | ||||||
|     } else { |  | ||||||
|         eventTail->next = e; |  | ||||||
|         eventTail = e; |  | ||||||
|     } |  | ||||||
|     pthread_cond_broadcast(&newEventBroadcast); |  | ||||||
|     pthread_mutex_unlock(&eventMutex); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void registerWithDal(int id, int event, Action a, int flags) { |  | ||||||
|     // TODO support flags |  | ||||||
|     setBinding(id, event, a); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void runPoller(Thread *thr) { |  | ||||||
|     Action query = thr->data0; |  | ||||||
|     auto us = (uint64_t)toInt(thr->data1) * 1000; |  | ||||||
|  |  | ||||||
|     // note that this is run without the user mutex held - it should not modify any state! |  | ||||||
|     TValue prev = pxt::runAction0(query); |  | ||||||
|  |  | ||||||
|     startUser(); |  | ||||||
|     pxt::runAction2(thr->act, prev, prev); |  | ||||||
|     stopUser(); |  | ||||||
|  |  | ||||||
|     while (true) { |  | ||||||
|         sleep_core_us(us); |  | ||||||
|         if (paniced) |  | ||||||
|             break; |  | ||||||
|         TValue curr = pxt::runAction0(query); |  | ||||||
|         if (curr != prev) { |  | ||||||
|             startUser(); |  | ||||||
|             pxt::runAction2(thr->act, prev, curr); |  | ||||||
|             stopUser(); |  | ||||||
|             if (paniced) |  | ||||||
|                 break; |  | ||||||
|             decr(prev); |  | ||||||
|             prev = curr; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     //    disposeThread(thr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| uint32_t afterProgramPage() { |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| void dumpDmesg() { |  | ||||||
|     auto len = dmesgPtr - dmesgSerialPtr; |  | ||||||
|     if (len == 0) |  | ||||||
|         return; |  | ||||||
|     sendSerial(dmesgBuf + dmesgSerialPtr, len); |  | ||||||
|     dmesgSerialPtr = dmesgPtr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int lmsPid; |  | ||||||
| void stopLMS() { |  | ||||||
|     struct dirent *ent; |  | ||||||
|     DIR *dir; |  | ||||||
|  |  | ||||||
|     dir = opendir("/proc"); |  | ||||||
|     if (dir == NULL) |  | ||||||
|         return; |  | ||||||
|  |  | ||||||
|     while ((ent = readdir(dir)) != NULL) { |  | ||||||
|         int pid = atoi(ent->d_name); |  | ||||||
|         if (!pid) |  | ||||||
|             continue; |  | ||||||
|         char namebuf[100]; |  | ||||||
|         snprintf(namebuf, 1000, "/proc/%d/cmdline", pid); |  | ||||||
|         FILE *f = fopen(namebuf, "r"); |  | ||||||
|         if (f) { |  | ||||||
|             fread(namebuf, 1, 99, f); |  | ||||||
|             if (strcmp(namebuf, "./lms2012") == 0) { |  | ||||||
|                 lmsPid = pid; |  | ||||||
|             } |  | ||||||
|             fclose(f); |  | ||||||
|             if (lmsPid) |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     closedir(dir); |  | ||||||
|  |  | ||||||
|     lmsPid = 0; // disable SIGSTOP for now - rethink if problems with I2C (runs on a thread) |  | ||||||
|  |  | ||||||
|     if (lmsPid) { |  | ||||||
|         DMESG("SIGSTOP to lmsPID=%d", lmsPid); |  | ||||||
|         if (kill(lmsPid, SIGSTOP)) |  | ||||||
|             DMESG("SIGSTOP failed"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void runLMS() { |  | ||||||
|     DMESG("re-starting LMS2012"); |  | ||||||
|     kill(lmsPid, SIGCONT); |  | ||||||
|     sleep_core_us(200000); |  | ||||||
|     exit(0); |  | ||||||
|     /* |  | ||||||
|     chdir("/home/root/lms2012/sys"); |  | ||||||
|     for (int fd = 3; fd < 9999; ++fd) |  | ||||||
|         close(fd); |  | ||||||
|     execl("lms2012", "./lms2012"); |  | ||||||
|     exit(100); // should not be reached |  | ||||||
|     */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void stopMotors() { |  | ||||||
|     uint8_t cmd[3] = {opOutputStop, 0x0F, 0}; |  | ||||||
|     int fd = open("/dev/lms_pwm", O_RDWR); |  | ||||||
|     write(fd, cmd, 3); |  | ||||||
|     close(fd); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void stopProgram() { |  | ||||||
|     uint8_t cmd[1] = {opOutputProgramStop}; |  | ||||||
|     int fd = open("/dev/lms_pwm", O_RDWR); |  | ||||||
|     write(fd, cmd, 1); |  | ||||||
|     close(fd); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| extern "C" void target_reset() { |  | ||||||
|     pthread_mutex_trylock(&execMutex); |  | ||||||
|     stopMotors(); |  | ||||||
|     stopProgram(); |  | ||||||
|     if (lmsPid) |  | ||||||
|         runLMS(); |  | ||||||
|     else |  | ||||||
|         exit(0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void screen_init(); |  | ||||||
| void initRuntime() { |  | ||||||
|     // daemon(1, 1); |  | ||||||
|     startTime = currTime(); |  | ||||||
|     DMESG("runtime starting..."); |  | ||||||
|     stopLMS(); |  | ||||||
|     startUsb(); |  | ||||||
|     startExitThread(); |  | ||||||
|     pthread_t disp; |  | ||||||
|     pthread_create(&disp, NULL, evtDispatcher, NULL); |  | ||||||
|     pthread_detach(disp); |  | ||||||
|     setupThread(0, 0, mainThread); |  | ||||||
|     target_init(); |  | ||||||
|     screen_init(); |  | ||||||
|     startUser(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static FILE *dmesgFile; |  | ||||||
|  |  | ||||||
| void dmesgRaw(const char *buf, uint32_t len) { |  | ||||||
|     if (!dmesgFile) { |  | ||||||
|         dmesgFile = fopen("/tmp/dmesg.txt", "w"); |  | ||||||
|         if (!dmesgFile) |  | ||||||
|             dmesgFile = stderr; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (len > sizeof(dmesgBuf) / 2) |  | ||||||
|         return; |  | ||||||
|     if (dmesgPtr + len > sizeof(dmesgBuf)) { |  | ||||||
|         dmesgPtr = 0; |  | ||||||
|         dmesgSerialPtr = 0; |  | ||||||
|     } |  | ||||||
|     memcpy(dmesgBuf + dmesgPtr, buf, len); |  | ||||||
|     dmesgPtr += len; |  | ||||||
|     fwrite(buf, 1, len, dmesgFile); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void dmesg(const char *format, ...) { |  | ||||||
|     char buf[500]; |  | ||||||
|  |  | ||||||
|     snprintf(buf, sizeof(buf), "[%8d] ", current_time_ms()); |  | ||||||
|     dmesgRaw(buf, strlen(buf)); |  | ||||||
|  |  | ||||||
|     va_list arg; |  | ||||||
|     va_start(arg, format); |  | ||||||
|     vsnprintf(buf, sizeof(buf), format, arg); |  | ||||||
|     va_end(arg); |  | ||||||
|     dmesgRaw(buf, strlen(buf)); |  | ||||||
|     dmesgRaw("\n", 1); |  | ||||||
|  |  | ||||||
|     fflush(dmesgFile); |  | ||||||
|     fdatasync(fileno(dmesgFile)); |  | ||||||
| } |  | ||||||
| } // namespace pxt |  | ||||||
| @@ -25,13 +25,20 @@ PXT_VTABLE_CTOR(MMap) { | |||||||
| } | } | ||||||
|  |  | ||||||
| void MMap::print() { | 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() { | void MMap::destroy() { | ||||||
|     munmap(data, length); |     munmap(data, length); | ||||||
|     close(fd); |     close(fd); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void MMap::scan(MMap *) {} | ||||||
|  |  | ||||||
|  | unsigned MMap::gcsize(MMap *) { | ||||||
|  |     return TOWORDS(sizeof(MMap)); | ||||||
|  | } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| namespace control { | namespace control { | ||||||
| @@ -39,8 +46,8 @@ namespace control { | |||||||
| /** Create new file mapping in memory */ | /** Create new file mapping in memory */ | ||||||
| //% | //% | ||||||
| MMap *mmap(String filename, int size, int offset) { | MMap *mmap(String filename, int size, int offset) { | ||||||
|     DMESG("mmap %s len=%d off=%d", filename->data, size, offset); |     DMESG("mmap %s len=%d off=%d", filename->getUTF8Data(), size, offset); | ||||||
|     int fd = open(filename->data, O_RDWR, 0); |     int fd = open(filename->getUTF8Data(), O_RDWR, 0); | ||||||
|     if (fd < 0) |     if (fd < 0) | ||||||
|         return 0; |         return 0; | ||||||
|      |      | ||||||
|   | |||||||
| @@ -918,9 +918,3 @@ namespace motors { | |||||||
|         writePWM(b) |         writePWM(b) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| interface Buffer { |  | ||||||
|     [index: number]: number; |  | ||||||
|     // rest defined in buffer.cpp |  | ||||||
| } |  | ||||||
							
								
								
									
										199
									
								
								libs/core/platform.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								libs/core/platform.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | |||||||
|  | #include "pxt.h" | ||||||
|  |  | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <sys/mman.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  | #include <sys/stat.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <sys/ioctl.h> | ||||||
|  | #include <pthread.h> | ||||||
|  | #include <signal.h> | ||||||
|  | #include <dirent.h> | ||||||
|  | #include "ev3const.h" | ||||||
|  |  | ||||||
|  | namespace pxt { | ||||||
|  |  | ||||||
|  |     static int usbFD; | ||||||
|  |  | ||||||
|  | #define USB_MAGIC 0x3d3f | ||||||
|  | #define USB_SERIAL 1 | ||||||
|  | #define USB_RESTART 2 | ||||||
|  | #define USB_DMESG 3 | ||||||
|  |  | ||||||
|  | struct UsbPacket { | ||||||
|  |     uint16_t size; | ||||||
|  |     uint16_t msgcount; | ||||||
|  |     uint16_t magic; | ||||||
|  |     uint16_t code; | ||||||
|  |     char buf[1024 - 8]; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | void *usbThread(void *) { | ||||||
|  |     UsbPacket pkt; | ||||||
|  |     UsbPacket resp; | ||||||
|  |     while (true) { | ||||||
|  |         int len = read(usbFD, &pkt, sizeof(pkt)); | ||||||
|  |         if (len <= 4) { | ||||||
|  |             sleep_core_us(20000); | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         resp.msgcount = pkt.msgcount; | ||||||
|  |         if (pkt.magic == USB_MAGIC) { | ||||||
|  |             if (pkt.code == USB_RESTART) { | ||||||
|  |                 target_reset(); | ||||||
|  |             } else if (pkt.code == USB_DMESG) { | ||||||
|  |                 dumpDmesg(); | ||||||
|  |             } | ||||||
|  |             /* | ||||||
|  |             resp.magic = pkt.magic; | ||||||
|  |             resp.code = pkt.code; | ||||||
|  |             resp.size = 8; | ||||||
|  |             write(usbFD, &resp, sizeof(resp)); | ||||||
|  |             */ | ||||||
|  |         } else { | ||||||
|  |             resp.magic = 0xffff; | ||||||
|  |             resp.size = 4; | ||||||
|  |             write(usbFD, &resp, sizeof(resp)); | ||||||
|  |         } | ||||||
|  |         sleep_core_us(1000); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void startUsb() { | ||||||
|  |     usbFD = open("/dev/lms_usbdev", O_RDWR, 0666); | ||||||
|  |     pthread_t pid; | ||||||
|  |     pthread_create(&pid, NULL, usbThread, NULL); | ||||||
|  |     pthread_detach(pid); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void *exitThread(void *) { | ||||||
|  |     int fd = open("/dev/lms_ui", O_RDWR, 0666); | ||||||
|  |     if (fd < 0) | ||||||
|  |         return 0; | ||||||
|  |     uint8_t *data = | ||||||
|  |         (uint8_t *)mmap(NULL, NUM_BUTTONS, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | ||||||
|  |     if (data == MAP_FAILED) { | ||||||
|  |         close(fd); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     for (;;) { | ||||||
|  |         if (data[5]) | ||||||
|  |             target_reset(); | ||||||
|  |         sleep_core_us(50000); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void startExitThread() { | ||||||
|  |     pthread_t pid; | ||||||
|  |     pthread_create(&pid, NULL, exitThread, NULL); | ||||||
|  |     pthread_detach(pid); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void sendUsb(uint16_t code, const char *data, int len) { | ||||||
|  |     while (len > 0) { | ||||||
|  |         int sz = len; | ||||||
|  |         if (sz > 1000) | ||||||
|  |             sz = 1000; | ||||||
|  |         UsbPacket pkt = {(uint16_t)(6 + sz), 0, USB_MAGIC, code, {}}; | ||||||
|  |         memcpy(pkt.buf, data, sz); | ||||||
|  |         write(usbFD, &pkt, sizeof(pkt)); | ||||||
|  |         len -= sz; | ||||||
|  |         data += sz; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void sendSerial(const char *data, int len) { | ||||||
|  |     sendUsb(USB_SERIAL, data, len); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lmsPid; | ||||||
|  | void stopLMS() { | ||||||
|  |     struct dirent *ent; | ||||||
|  |     DIR *dir; | ||||||
|  |  | ||||||
|  |     dir = opendir("/proc"); | ||||||
|  |     if (dir == NULL) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     while ((ent = readdir(dir)) != NULL) { | ||||||
|  |         int pid = atoi(ent->d_name); | ||||||
|  |         if (!pid) | ||||||
|  |             continue; | ||||||
|  |         char namebuf[100]; | ||||||
|  |         snprintf(namebuf, 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() {} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -1 +1,3 @@ | |||||||
| // leave empty | #define PXT_GC_THREAD_LIST 1 | ||||||
|  |  | ||||||
|  | #define PXT_IN_ISR() false | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ int allocateNotifyEvent(); | |||||||
| void sleep_core_us(uint64_t us); | void sleep_core_us(uint64_t us); | ||||||
| void startUser(); | void startUser(); | ||||||
| void stopUser(); | void stopUser(); | ||||||
|  | int tryLockUser(); | ||||||
|  |  | ||||||
| class Button; | class Button; | ||||||
| typedef Button *Button_; | typedef Button *Button_; | ||||||
| @@ -27,9 +28,13 @@ class MMap : public RefObject { | |||||||
|     MMap(); |     MMap(); | ||||||
|     void destroy(); |     void destroy(); | ||||||
|     void print(); |     void print(); | ||||||
|  |  | ||||||
|  |     static void scan(MMap *); | ||||||
|  |     static unsigned gcsize(MMap *); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| extern volatile bool paniced; | extern volatile bool paniced; | ||||||
|  | void target_exit(); | ||||||
|  |  | ||||||
| // Buffer, Sound, and Image share representation. | // Buffer, Sound, and Image share representation. | ||||||
| typedef Buffer Sound; | typedef Buffer Sound; | ||||||
|   | |||||||
| @@ -26,11 +26,19 @@ | |||||||
|         "icons.jres", |         "icons.jres", | ||||||
|         "ns.ts", |         "ns.ts", | ||||||
|         "platform.h", |         "platform.h", | ||||||
|  |         "platform.cpp", | ||||||
|  |         "dmesg.cpp", | ||||||
|         "integrator.ts" |         "integrator.ts" | ||||||
|     ], |     ], | ||||||
|     "testFiles": [ |     "testFiles": [ | ||||||
|         "test.ts" |         "test.ts" | ||||||
|     ], |     ], | ||||||
|  |     "dalDTS": { | ||||||
|  |         "includeDirs": [ | ||||||
|  |             "pxtapp" | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     "additionalFilePath": "../../node_modules/pxt-common-packages/libs/core---linux", | ||||||
|     "npmDependencies": {}, |     "npmDependencies": {}, | ||||||
|     "public": true, |     "public": true, | ||||||
|     "dependencies": { |     "dependencies": { | ||||||
|   | |||||||
| @@ -1,16 +0,0 @@ | |||||||
| #ifndef __PXTCORE_H |  | ||||||
| #define __PXTCORE_H |  | ||||||
|  |  | ||||||
| #include <stdio.h> |  | ||||||
|  |  | ||||||
| namespace pxt { |  | ||||||
| void dmesg(const char *fmt, ...); |  | ||||||
| #define DMESG pxt::dmesg |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline void itoa(int v, char *dst) { |  | ||||||
|  |  | ||||||
|     snprintf(dst, 30, "%d", v); |  | ||||||
|  |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| @@ -85,10 +85,9 @@ void updateScreen(Image_ img) { | |||||||
|         lastImg = 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) |         if (lastImg->bpp() != 1 || lastImg->width() != LCD_WIDTH || lastImg->height() != LCD_HEIGHT) | ||||||
|             target_panic(906); |             target_panic(906); | ||||||
|         lastImg->clearDirty(); |  | ||||||
|         bitBufferToFrameBufferSwap(lastImg->pix(), mappedFrameBuffer); |         bitBufferToFrameBufferSwap(lastImg->pix(), mappedFrameBuffer); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -25,8 +25,8 @@ struct hci_dev_list_req { | |||||||
|     hci_dev_req dev_req[2]; |     hci_dev_req dev_req[2]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static uint32_t bt_addr() { | static uint64_t bt_addr() { | ||||||
|     uint32_t res = -1; |     uint64_t res = -1; | ||||||
|  |  | ||||||
|     int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); |     int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); | ||||||
|     if (fd < 0) { |     if (fd < 0) { | ||||||
| @@ -50,11 +50,8 @@ static uint32_t bt_addr() { | |||||||
|         goto done; |         goto done; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     memcpy(&res, di.bdaddr, 4); |     res = 0; | ||||||
|     res *= 0x1000193; |     memcpy(&res, di.bdaddr, 6); | ||||||
|     res += di.bdaddr[4]; |  | ||||||
|     res *= 0x1000193; |  | ||||||
|     res += di.bdaddr[5]; |  | ||||||
|  |  | ||||||
| done: | done: | ||||||
|     close(fd); |     close(fd); | ||||||
| @@ -63,14 +60,10 @@ done: | |||||||
|  |  | ||||||
| namespace pxt { | namespace pxt { | ||||||
|  |  | ||||||
| int getSerialNumber() { | uint64_t getLongSerialNumber() { | ||||||
|     static int serial; |     static uint64_t serial; | ||||||
|  |     if (serial == 0) | ||||||
|     if (serial != 0) |         serial = bt_addr(); | ||||||
|         return serial; |  | ||||||
|  |  | ||||||
|     serial = bt_addr() & 0x7fffffff; |  | ||||||
|  |  | ||||||
|     return serial; |     return serial; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								libs/core/shims.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								libs/core/shims.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -68,6 +68,12 @@ declare namespace control { | |||||||
|     /** Write data to DMESG debugging buffer. */ |     /** Write data to DMESG debugging buffer. */ | ||||||
|     //% shim=control::dmesg |     //% shim=control::dmesg | ||||||
|     function dmesg(s: string): void; |     function dmesg(s: string): void; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Determines if the USB has been enumerated. | ||||||
|  |      */ | ||||||
|  |     //% shim=control::isUSBInitialized | ||||||
|  |     function isUSBInitialized(): boolean; | ||||||
| } | } | ||||||
| declare namespace serial { | declare namespace serial { | ||||||
|  |  | ||||||
|   | |||||||
| @@ -44,7 +44,7 @@ namespace console._screen { | |||||||
|         printLog(); |         printLog(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function log(msg: string): void {     |     function log(priority: ConsolePriority, msg: string): void { | ||||||
|         lines.push(msg); |         lines.push(msg); | ||||||
|         if (lines.length + 5 > maxLines) { |         if (lines.length + 5 > maxLines) { | ||||||
|             lines.splice(0, maxLines - lines.length); |             lines.splice(0, maxLines - lines.length); | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| // This is the last thing executed before user code | // 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)) |     control.dmesg(msg.substr(0, msg.length - 1)) | ||||||
| }) | }) | ||||||
| // pulse green, play startup sound, turn off light | // pulse green, play startup sound, turn off light | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								libs/screen/screenimage.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								libs/screen/screenimage.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  |  | ||||||
|  | namespace image { | ||||||
|  |     /** | ||||||
|  |     * Get the screen image | ||||||
|  |     */ | ||||||
|  |     //% | ||||||
|  |     export function screenImage(): Image { | ||||||
|  |         return screen; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								libs/screen/shims.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								libs/screen/shims.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -15,7 +15,7 @@ declare interface Image { | |||||||
|     height: int32; |     height: int32; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * True iff the image is monochromatic (black and white) |      * True if the image is monochromatic (black and white) | ||||||
|      */ |      */ | ||||||
|     //% property shim=ImageMethods::isMono |     //% property shim=ImageMethods::isMono | ||||||
|     isMono: boolean; |     isMono: boolean; | ||||||
| @@ -45,6 +45,18 @@ declare interface Image { | |||||||
|     //% shim=ImageMethods::fill |     //% shim=ImageMethods::fill | ||||||
|     fill(c: int32): void; |     fill(c: int32): void; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Copy row(s) of pixel from image to buffer (8 bit per pixel). | ||||||
|  |      */ | ||||||
|  |     //% shim=ImageMethods::getRows | ||||||
|  |     getRows(x: int32, dst: Buffer): void; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Copy row(s) of pixel from buffer to image. | ||||||
|  |      */ | ||||||
|  |     //% shim=ImageMethods::setRows | ||||||
|  |     setRows(x: int32, src: Buffer): void; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Return a copy of the current image |      * Return a copy of the current image | ||||||
|      */ |      */ | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,12 +1,13 @@ | |||||||
| { | { | ||||||
|   "name": "pxt-ev3", |   "name": "pxt-ev3", | ||||||
|   "version": "1.2.23", |   "version": "1.4.0", | ||||||
|   "description": "LEGO MINDSTORMS EV3 for Microsoft MakeCode", |   "description": "LEGO MINDSTORMS EV3 for Microsoft MakeCode", | ||||||
|   "private": false, |   "private": false, | ||||||
|   "keywords": [ |   "keywords": [ | ||||||
|     "JavaScript", |     "JavaScript", | ||||||
|     "education", |     "education", | ||||||
|     "lego", |     "LEGO", | ||||||
|  |     "EV3", | ||||||
|     "pxt", |     "pxt", | ||||||
|     "MakeCode", |     "MakeCode", | ||||||
|     "Microsoft" |     "Microsoft" | ||||||
| @@ -32,15 +33,20 @@ | |||||||
|   ], |   ], | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "typescript": "2.6.1", |     "typescript": "2.6.1", | ||||||
|  |     "react": "16.8.3", | ||||||
|     "semantic-ui-less": "2.2.14", |     "semantic-ui-less": "2.2.14", | ||||||
|     "@types/bluebird": "2.0.33", |     "@types/bluebird": "2.0.33", | ||||||
|     "@types/marked": "0.3.0", |     "@types/marked": "0.3.0", | ||||||
|     "@types/node": "8.0.53", |     "@types/node": "8.0.53", | ||||||
|     "webfonts-generator": "^0.4.0" |     "webfonts-generator": "^0.4.0", | ||||||
|  |     "@types/jquery": "3.2.16", | ||||||
|  |     "@types/react": "16.0.25", | ||||||
|  |     "@types/react-dom": "16.0.3", | ||||||
|  |     "@types/web-bluetooth": "0.0.4" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "pxt-common-packages": "0.23.61", |     "pxt-common-packages": "6.16.7", | ||||||
|     "pxt-core": "4.0.11" |     "pxt-core": "5.25.6" | ||||||
|   }, |   }, | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "test": "node node_modules/pxt-core/built/pxt.js travis" |     "test": "node node_modules/pxt-core/built/pxt.js travis" | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ | |||||||
|     ], |     ], | ||||||
|     "simulator": { |     "simulator": { | ||||||
|         "autoRun": true, |         "autoRun": true, | ||||||
|         "streams": true, |         "autoRunLight": false, | ||||||
|         "aspectRatio": 0.5, |         "aspectRatio": 0.5, | ||||||
|         "parts": false, |         "parts": false, | ||||||
|         "enableTrace": true, |         "enableTrace": true, | ||||||
| @@ -50,7 +50,8 @@ | |||||||
|         "flashCodeAlign": 256, |         "flashCodeAlign": 256, | ||||||
|         "floatingPoint": true, |         "floatingPoint": true, | ||||||
|         "taggedInts": true, |         "taggedInts": true, | ||||||
|         "stackAlign": 2 |         "stackAlign": 2, | ||||||
|  |         "gc": true | ||||||
|     }, |     }, | ||||||
|     "serial": { |     "serial": { | ||||||
|         "vendorId": "0x0694", |         "vendorId": "0x0694", | ||||||
| @@ -72,7 +73,10 @@ | |||||||
|         "onStartColor": "#58AB41", |         "onStartColor": "#58AB41", | ||||||
|         "pauseUntilBlock": { |         "pauseUntilBlock": { | ||||||
|             "category": "loops" |             "category": "loops" | ||||||
|         } |         }, | ||||||
|  |         "bannedCategories": [ | ||||||
|  |             "image" | ||||||
|  |         ] | ||||||
|     }, |     }, | ||||||
|     "compileService": { |     "compileService": { | ||||||
|         "buildEngine": "dockermake", |         "buildEngine": "dockermake", | ||||||
| @@ -151,6 +155,12 @@ | |||||||
|         "usbHelp": [], |         "usbHelp": [], | ||||||
|         "extendEditor": true, |         "extendEditor": true, | ||||||
|         "extendFieldEditors": true, |         "extendFieldEditors": true, | ||||||
|  |         "scriptManager": true, | ||||||
|  |         "importExtensionFiles": true, | ||||||
|  |         "experiments": [ | ||||||
|  |             "python", | ||||||
|  |             "alwaysGithubItemBlocks" | ||||||
|  |         ], | ||||||
|         "disableBlockIcons": true, |         "disableBlockIcons": true, | ||||||
|         "blocklyOptions": { |         "blocklyOptions": { | ||||||
|             "grid": { |             "grid": { | ||||||
| @@ -186,6 +196,10 @@ | |||||||
|             "editor.background": "#f9f9f9" |             "editor.background": "#f9f9f9" | ||||||
|         }, |         }, | ||||||
|         "fileNameExclusiveFilter": "[^a-zA-Z0-9]", |         "fileNameExclusiveFilter": "[^a-zA-Z0-9]", | ||||||
|  |         "qrCode": true, | ||||||
|  |         "shareFinishedTutorials": true, | ||||||
|  |         "nameProjectFirst": true, | ||||||
|  |         "alwaysGithubItem": true, | ||||||
|         "enableTrace": true |         "enableTrace": true | ||||||
|     }, |     }, | ||||||
|     "ignoreDocsErrors": true |     "ignoreDocsErrors": true | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| namespace pxsim { | namespace pxsim { | ||||||
|  |  | ||||||
|     export class EV3Board extends CoreBoard { |     export class EV3Board extends CoreBoard { | ||||||
|  |         viewHost: visuals.BoardHost; | ||||||
|         view: SVGSVGElement; |         view: SVGSVGElement; | ||||||
|  |  | ||||||
|         outputState: EV3OutputState; |         outputState: EV3OutputState; | ||||||
| @@ -83,7 +84,8 @@ namespace pxsim { | |||||||
|                 highContrast: msg.highContrast, |                 highContrast: msg.highContrast, | ||||||
|                 light: msg.light |                 light: msg.light | ||||||
|             }; |             }; | ||||||
|             const viewHost = new visuals.BoardHost(pxsim.visuals.mkBoardView({ |             this.viewHost = new visuals.BoardHost(pxsim.visuals.mkBoardView({ | ||||||
|  |                 boardDef, | ||||||
|                 visual: boardDef.visual, |                 visual: boardDef.visual, | ||||||
|                 highContrast: msg.highContrast, |                 highContrast: msg.highContrast, | ||||||
|                 light: msg.light |                 light: msg.light | ||||||
| @@ -91,7 +93,7 @@ namespace pxsim { | |||||||
|  |  | ||||||
|             document.body.innerHTML = ""; // clear children |             document.body.innerHTML = ""; // clear children | ||||||
|             document.body.className = msg.light ? "light" : ""; |             document.body.className = msg.light ? "light" : ""; | ||||||
|             document.body.appendChild(this.view = viewHost.getView() as SVGSVGElement); |             document.body.appendChild(this.view = this.viewHost.getView() as SVGSVGElement); | ||||||
|  |  | ||||||
|             this.inputNodes = []; |             this.inputNodes = []; | ||||||
|             this.outputNodes = []; |             this.outputNodes = []; | ||||||
| @@ -102,8 +104,8 @@ namespace pxsim { | |||||||
|             return Promise.resolve(); |             return Promise.resolve(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         screenshot(): string { |         screenshotAsync(width?: number): Promise<ImageData> { | ||||||
|             return svg.toDataUri(new XMLSerializer().serializeToString(this.view)); |             return this.viewHost.screenshotAsync(width); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         getBrickNode() { |         getBrickNode() { | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
|  |  | ||||||
| namespace pxsim.music { | namespace pxsim.music { | ||||||
|     export function fromWAV(buf: RefBuffer) { |     export function fromWAV(buf: RefBuffer) { | ||||||
|         return incr(buf) |         return buf | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     export function stopAllSounds() { |     export function stopAllSounds() { | ||||||
| @@ -13,7 +13,7 @@ namespace pxsim.SoundMethods { | |||||||
|     let audio: HTMLAudioElement; |     let audio: HTMLAudioElement; | ||||||
|  |  | ||||||
|     export function buffer(buf: RefBuffer) { |     export function buffer(buf: RefBuffer) { | ||||||
|         return incr(buf) |         return buf | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     export function play(buf: RefBuffer) { |     export function play(buf: RefBuffer) { | ||||||
|   | |||||||
| @@ -176,7 +176,7 @@ namespace pxsim.visuals { | |||||||
|             const dalBoard = board(); |             const dalBoard = board(); | ||||||
|             dalBoard.updateSubscribers.push(() => this.updateState()); |             dalBoard.updateSubscribers.push(() => this.updateState()); | ||||||
|             if (props && props.wireframe) |             if (props && props.wireframe) | ||||||
|                 svg.addClass(this.element, "sim-wireframe"); |                 U.addClass(this.element, "sim-wireframe"); | ||||||
|  |  | ||||||
|             if (props && props.theme) |             if (props && props.theme) | ||||||
|                 this.updateTheme(); |                 this.updateTheme(); | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ namespace pxsim.visuals { | |||||||
|         protected buildDomCore() { |         protected buildDomCore() { | ||||||
|             // Setup buttons |             // Setup buttons | ||||||
|             this.buttons = this.btnids.map(n => this.content.getElementById(this.normalizeId(n)) as SVGElement); |             this.buttons = this.btnids.map(n => this.content.getElementById(this.normalizeId(n)) as SVGElement); | ||||||
|             this.buttons.forEach(b => 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; |             this.light = this.content.getElementById(this.normalizeId(BrickView.EV3_LIGHT_ID)) as SVGElement; | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ | |||||||
|         "Design Engineering": "design-engineering", |         "Design Engineering": "design-engineering", | ||||||
|         "Coding": "coding", |         "Coding": "coding", | ||||||
|         "Maker": "maker", |         "Maker": "maker", | ||||||
|         "Videos": "videos" |         "Tutorial Videos": "videos" | ||||||
|     }, |     }, | ||||||
|     "electronManifest": { |     "electronManifest": { | ||||||
|         "latest": "v1.2.22" |         "latest": "v1.2.22" | ||||||
|   | |||||||
| @@ -16,6 +16,10 @@ | |||||||
| /******************************* | /******************************* | ||||||
|     Add your custom CSS here |     Add your custom CSS here | ||||||
| *******************************/ | *******************************/ | ||||||
|  | .simframe.ui.embed { | ||||||
|  |     background: transparent; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Open Sans font */ | /* Open Sans font */ | ||||||
| @font-face  { | @font-face  { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user