web serial cleanup (#928)
* updated ticks * fix enable and compile * add debug mode * don't try to change UI while downloading * cleanup * don't double open * use cu * add delay before reconnecting * support for 200 ragne in field turn ratio * updated docs * fix docs
This commit is contained in:
		@@ -61,6 +61,12 @@ motors.largeBC.steer(0, 50, 1, MoveUnit.Rotations);
 | 
				
			|||||||
motors.largeBC.stop();
 | 
					motors.largeBC.stop();
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### ~ hint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The **turn ratio range is -200, 200** unlike LabView who used -100,100.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### ~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Tank
 | 
					## Tank
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The **tank** blocks control the speed of two motors. These are commonly used for a differential drive robot. The blocks can also specify the duration, angle, or number of rotations.
 | 
					The **tank** blocks control the speed of two motors. These are commonly used for a differential drive robot. The blocks can also specify the duration, angle, or number of rotations.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ If you decide to use a **value** of rotation distance, you need to choose a type
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Parameters
 | 
					## Parameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* **turnRatio**: a [number](/types/number) that is the percentage of speed of the drive motor. The follower motor runs at this speed. A negative number steers to the left and a positive number steers to the right. This is a number between `-100` and `100`.
 | 
					* **turnRatio**: a [number](/types/number) that is the percentage of speed of the drive motor. The follower motor runs at this speed. A negative number steers to the left and a positive number steers to the right. This is a number between `-200` and `200`.
 | 
				
			||||||
* **speed**: a [number](/types/number) that is the percentage of full speed. A negative value runs the motors in the reverse direction. This is the speed that the drive motor runs at.
 | 
					* **speed**: a [number](/types/number) that is the percentage of full speed. A negative value runs the motors in the reverse direction. This is the speed that the drive motor runs at.
 | 
				
			||||||
* **value**: the [number](/types/number) of movement units to rotate for. A value of `0` means run the motor continuously.
 | 
					* **value**: the [number](/types/number) of movement units to rotate for. A value of `0` means run the motor continuously.
 | 
				
			||||||
* **unit**: the movement unit of rotation. This can be `milliseconds`, `seconds`, `degrees`, or `rotations`. If the number for **value** is `0`, this parameter isn't used.
 | 
					* **unit**: the movement unit of rotation. This can be `milliseconds`, `seconds`, `degrees`, or `rotations`. If the number for **value** is `0`, this parameter isn't used.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,7 +64,6 @@ class WebSerialPackageIO implements pxt.HF2.PacketIO {
 | 
				
			|||||||
    private _writer: any;
 | 
					    private _writer: any;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(private port: SerialPort, private options: SerialOptions) {
 | 
					    constructor(private port: SerialPort, private options: SerialOptions) {
 | 
				
			||||||
        this.openAsync();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async readSerialAsync() {
 | 
					    async readSerialAsync() {
 | 
				
			||||||
@@ -173,7 +172,7 @@ export function initAsync(): Promise<void> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (WebSerialPackageIO.isSupported())
 | 
					    if (WebSerialPackageIO.isSupported())
 | 
				
			||||||
        pxt.tickEvent("bluetooth.supported");
 | 
					        pxt.tickEvent("webserial.supported");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Promise.resolve();
 | 
					    return Promise.resolve();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -274,7 +273,7 @@ export function deployCoreAsync(resp: pxtc.CompileResult) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (!useHID) return saveUF2Async()
 | 
					    if (!useHID) return saveUF2Async()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pxt.tickEvent("bluetooth.flash");
 | 
					    pxt.tickEvent("webserial.flash");
 | 
				
			||||||
    let w: Ev3Wrapper;
 | 
					    let w: Ev3Wrapper;
 | 
				
			||||||
    return initHidAsync()
 | 
					    return initHidAsync()
 | 
				
			||||||
        .then(w_ => {
 | 
					        .then(w_ => {
 | 
				
			||||||
@@ -291,12 +290,14 @@ export function deployCoreAsync(resp: pxtc.CompileResult) {
 | 
				
			|||||||
                                `<ul>
 | 
					                                `<ul>
 | 
				
			||||||
<li>${lf("Make sure to stop your program or exit portview on the EV3.")}</li>
 | 
					<li>${lf("Make sure to stop your program or exit portview on the EV3.")}</li>
 | 
				
			||||||
<li>${lf("Check your battery level.")}</li>
 | 
					<li>${lf("Check your battery level.")}</li>
 | 
				
			||||||
 | 
					<li>${lf("Close EV3 LabView or other MakeCode editor tabs.")}
 | 
				
			||||||
</ul>`,
 | 
					</ul>`,
 | 
				
			||||||
                            hasCloseIcon: true,
 | 
					                            hasCloseIcon: true,
 | 
				
			||||||
                            hideCancel: true,
 | 
					                            hideCancel: true,
 | 
				
			||||||
                            hideAgree: false,
 | 
					                            hideAgree: false,
 | 
				
			||||||
                            agreeLbl: lf("Try again"),
 | 
					                            agreeLbl: lf("Try again"),
 | 
				
			||||||
                        }).then(() => w.disconnectAsync())
 | 
					                        }).then(() => w.disconnectAsync())
 | 
				
			||||||
 | 
					                            .then(() => Promise.delay(1000))
 | 
				
			||||||
                            .then(() => w.reconnectAsync());
 | 
					                            .then(() => w.reconnectAsync());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // nothing we can do
 | 
					                    // nothing we can do
 | 
				
			||||||
@@ -309,11 +310,11 @@ export function deployCoreAsync(resp: pxtc.CompileResult) {
 | 
				
			|||||||
        .then(() => w.flashAsync(rbfPath, rbfBIN))
 | 
					        .then(() => w.flashAsync(rbfPath, rbfBIN))
 | 
				
			||||||
        .then(() => w.runAsync(rbfPath))
 | 
					        .then(() => w.runAsync(rbfPath))
 | 
				
			||||||
        .then(() => {
 | 
					        .then(() => {
 | 
				
			||||||
            pxt.tickEvent("bluetooth.success");
 | 
					            pxt.tickEvent("webserial.success");
 | 
				
			||||||
            return w.disconnectAsync()
 | 
					            return w.disconnectAsync()
 | 
				
			||||||
            //return Promise.delay(1000).then(() => w.dmesgAsync())
 | 
					            //return Promise.delay(1000).then(() => w.dmesgAsync())
 | 
				
			||||||
        }).catch(e => {
 | 
					        }).catch(e => {
 | 
				
			||||||
            pxt.tickEvent("bluetooth.fail");
 | 
					            pxt.tickEvent("webserial.fail");
 | 
				
			||||||
            useHID = false;
 | 
					            useHID = false;
 | 
				
			||||||
            useWebSerial = false;
 | 
					            useWebSerial = false;
 | 
				
			||||||
            // if we failed to initalize, tell the user to retry
 | 
					            // if we failed to initalize, tell the user to retry
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,13 @@ 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;
 | 
					    const projectView = opts.projectView;
 | 
				
			||||||
    pxt.debug('loading pxt-ev3 target extensions...')
 | 
					    pxt.debug('loading pxt-ev3 target extensions...')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function enableWebSerialAndCompileAsync() {
 | 
				
			||||||
 | 
					        return enableWebSerialAsync()
 | 
				
			||||||
 | 
					        .then(() => Promise.delay(500))
 | 
				
			||||||
 | 
					        .then(() => projectView.compile());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const res: pxt.editor.ExtensionResult = {
 | 
					    const res: pxt.editor.ExtensionResult = {
 | 
				
			||||||
        deployCoreAsync,
 | 
					        deployCoreAsync,
 | 
				
			||||||
        showUploadInstructionsAsync: (fn: string, url: string, confirmAsync: (options: any) => Promise<number>) => {
 | 
					        showUploadInstructionsAsync: (fn: string, url: string, confirmAsync: (options: any) => Promise<number>) => {
 | 
				
			||||||
@@ -84,7 +91,7 @@ pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): P
 | 
				
			|||||||
                    onclick: () => {
 | 
					                    onclick: () => {
 | 
				
			||||||
                        pxt.tickEvent("bluetooth.enable");
 | 
					                        pxt.tickEvent("bluetooth.enable");
 | 
				
			||||||
                        if (bluetoothDialogShown) {
 | 
					                        if (bluetoothDialogShown) {
 | 
				
			||||||
                            enableWebSerialAsync().done();
 | 
					                            enableWebSerialAndCompileAsync().done();
 | 
				
			||||||
                        } else {
 | 
					                        } else {
 | 
				
			||||||
                            bluetoothDialogShown = true;
 | 
					                            bluetoothDialogShown = true;
 | 
				
			||||||
                            confirmAsync({
 | 
					                            confirmAsync({
 | 
				
			||||||
@@ -99,13 +106,13 @@ pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): P
 | 
				
			|||||||
                                }],
 | 
					                                }],
 | 
				
			||||||
                                htmlBody: `<p>
 | 
					                                htmlBody: `<p>
 | 
				
			||||||
${lf("You will be prompted to select a serial port.")}
 | 
					${lf("You will be prompted to select a serial port.")}
 | 
				
			||||||
${pxt.BrowserUtils.isWindows() ? lf("Look for 'Standard Serial over Bluetooth link'.") : lf("Loop for 'tty.EV3-SerialPort' or 'cu.EV3-SerialPort'")}
 | 
					${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.")}
 | 
					${lf("If you have paired multiple EV3, you might have to try out multiple ports until you find the correct one.")}
 | 
				
			||||||
</p>
 | 
					</p>
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
                            }).then(() => enableWebSerialAsync())
 | 
					                            }).then(() => enableWebSerialAndCompileAsync())
 | 
				
			||||||
                                .then(() => Promise.delay(500))
 | 
					 | 
				
			||||||
                                .then(() => projectView.compile())
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                } : undefined, downloadAgain ? {
 | 
					                } : undefined, downloadAgain ? {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,12 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * See https://www.lego.com/cdn/cs/set/assets/blt6879b00ae6951482/LEGO_MINDSTORMS_EV3_Communication_Developer_Kit.pdf
 | 
				
			||||||
 | 
					 * https://github.com/mindboards/ev3sources/blob/master/lms2012/lms2012/source/bytecodes.h#L146
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
import HF2 = pxt.HF2
 | 
					import HF2 = pxt.HF2
 | 
				
			||||||
import U = pxt.U
 | 
					import U = pxt.U
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function log(msg: string) {
 | 
					function log(msg: string) {
 | 
				
			||||||
    pxt.debug("EWRAP: " + msg)
 | 
					    pxt.log("serial: " + msg)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface DirEntry {
 | 
					export interface DirEntry {
 | 
				
			||||||
@@ -19,7 +23,7 @@ export class Ev3Wrapper {
 | 
				
			|||||||
    private cmdSeq = U.randomUint32() & 0xffff;
 | 
					    private cmdSeq = U.randomUint32() & 0xffff;
 | 
				
			||||||
    private lock = new U.PromiseQueue();
 | 
					    private lock = new U.PromiseQueue();
 | 
				
			||||||
    isStreaming = false;
 | 
					    isStreaming = false;
 | 
				
			||||||
    dataDump = false;
 | 
					    dataDump = /talkdbg=1/.test(window.location.href);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(public io: pxt.HF2.PacketIO) {
 | 
					    constructor(public io: pxt.HF2.PacketIO) {
 | 
				
			||||||
        io.onData = buf => {
 | 
					        io.onData = buf => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@ export class FieldTurnRatio extends Blockly.FieldSlider implements Blockly.Field
 | 
				
			|||||||
     * @constructor
 | 
					     * @constructor
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    constructor(value_: any, params: FieldTurnRatioOptions, opt_validator?: Function) {
 | 
					    constructor(value_: any, params: FieldTurnRatioOptions, opt_validator?: Function) {
 | 
				
			||||||
        super(String(value_), '-100', '100', null, '10', 'TurnRatio', opt_validator);
 | 
					        super(String(value_), '-200', '200', null, '10', 'TurnRatio', opt_validator);
 | 
				
			||||||
        this.params = params;
 | 
					        this.params = params;
 | 
				
			||||||
        (this as any).sliderColor_ = '#a8aaa8';
 | 
					        (this as any).sliderColor_ = '#a8aaa8';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -76,26 +76,26 @@ export class FieldTurnRatio extends Blockly.FieldSlider implements Blockly.Field
 | 
				
			|||||||
        if (!this.path_) {
 | 
					        if (!this.path_) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let v = goog.math.clamp(parseFloat(this.getText()), -100, 100);
 | 
					        let v = goog.math.clamp(parseFloat(this.getText()), -200, 200);
 | 
				
			||||||
        if (isNaN(v)) {
 | 
					        if (isNaN(v)) {
 | 
				
			||||||
            v = 0;
 | 
					            v = 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        const x = v / 100;
 | 
				
			||||||
        const x = goog.math.clamp(parseFloat(this.getText()), -100, 100) / 100;
 | 
					        const nx = Math.max(-1, Math.min(1, x));
 | 
				
			||||||
        const theta = x * Math.PI / 2;
 | 
					        const theta = Math.max(nx) * Math.PI / 2;
 | 
				
			||||||
        const cx = FieldTurnRatio.HALF;
 | 
					        const r = FieldTurnRatio.RADIUS - 6;
 | 
				
			||||||
        const cy = FieldTurnRatio.HALF - 14;
 | 
					        let cx = FieldTurnRatio.HALF;
 | 
				
			||||||
        const gamma = Math.PI - 2 * theta;
 | 
					        const cy = FieldTurnRatio.HALF - 22;
 | 
				
			||||||
        const r = FieldTurnRatio.RADIUS;
 | 
					        if (Math.abs(x) > 1) {
 | 
				
			||||||
        const alpha = 0.2 + Math.abs(x) * 0.5;
 | 
					            cx -= (x - (x > 0 ? 1 : -1)) * r / 2; // move center of circle
 | 
				
			||||||
        const x1 = 0;
 | 
					        }
 | 
				
			||||||
 | 
					        const alpha = 0.2 + Math.abs(nx) * 0.5;
 | 
				
			||||||
        const y1 = r * alpha;
 | 
					        const y1 = r * alpha;
 | 
				
			||||||
        const y2 = r * Math.sin(Math.PI / 2 - theta);
 | 
					        const y2 = r * Math.sin(Math.PI / 2 - theta);
 | 
				
			||||||
        const x2 = r * Math.cos(Math.PI / 2 - theta);
 | 
					        const x2 = r * Math.cos(Math.PI / 2 - theta);
 | 
				
			||||||
        const y3 = y2 - r * alpha * Math.cos(2 * theta);
 | 
					        const y3 = y2 - r * alpha * Math.cos(2 * theta);
 | 
				
			||||||
        const x3 = x2 - r * alpha * Math.sin(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}`;
 | 
					        const d = `M ${cx} ${cy} C ${cx} ${cy - y1} ${cx + x3} ${cy - y3} ${cx + x2} ${cy - y2}`;
 | 
				
			||||||
        this.path_.setAttribute('d', d);
 | 
					        this.path_.setAttribute('d', d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user