TurboWarp / scratch-vm

Scratch VM with a JIT compiler and more features
https://turbowarp.org/
Mozilla Public License 2.0
75 stars 72 forks source link

Fix WeDo2.send sends empty message #192

Closed tpsnt closed 8 months ago

tpsnt commented 8 months ago

WeDo2.send invokes Base64Util.uint8ArrayToBase64(message). However message.arrayLength === undefined. This causes Base64Util.uint8ArrayToBase64 always returning empty string ''.

Resolves

WeDo2.send invokes Base64Util.uint8ArrayToBase64(message). However message.arrayLength === undefined. This causes Base64Util.uint8ArrayToBase64 always returning empty string ''. This causes motors not functioning, and other devices not functioning.

Proposed Changes

replace Base64Util.uint8ArrayToBase64(message) with Base64Util.uint8ArrayToBase64(new Uint8Array(message))

Reason for Changes

WeDo2.send invokes Base64Util.uint8ArrayToBase64(message). However message.arrayLength === undefined. This causes Base64Util.uint8ArrayToBase64 always returning empty string ''. This causes motors not functioning, and other devices not functioning.

Test Coverage

Wedo 2.0 Block: turn motor on for 1 seconds.

tpsnt commented 8 months ago

This problem is caused by commit dc9b3f6 https://github.com/TurboWarp/scratch-vm/commit/dc9b3f60558de9626761ae698083b14ee9a8ef2c#diff-bc3782b0d9f67b943072d728f3741dc881117ad48184a09266d7fb125c3939cd

GarboMuffin commented 8 months ago

do you know if that affects the other scratch link extensions too?

tpsnt commented 8 months ago

do you know if that affects the other scratch link extensions too?

no, i only have wedo2. If i get plenty time i will probably review other scratch link extensions codes. But I don't have hardware other than wedo2.

tpsnt commented 8 months ago

do you know if that affects the other scratch link extensions too?

I just reviewed ev3 entension code. https://github.com/TurboWarp/scratch-vm/blob/develop/src/extensions/scratch3_ev3/index.js Line 659

/**
 * Send a message to the peripheral BT socket.
 * @param {Uint8Array} message - the message to send.
 * @param {boolean} [useLimiter=true] - if true, use the rate limiter
 * @return {Promise} - a promise result of the send operation.
 */
send (message, useLimiter = true) {
    if (!this.isConnected()) return Promise.resolve();

    if (useLimiter) {
        if (!this._rateLimiter.okayToSend()) return Promise.resolve();
    }

    return this._bt.sendMessage({
        message: Base64Util.uint8ArrayToBase64(message),
        encoding: 'base64'
    });
}

Line 678

    /**
     * Genrates direct commands that are sent to the EV3 as a single or compounded byte arrays.
     * See 'EV3 Communication Developer Kit', section 4, page 24 at
     * https://education.lego.com/en-us/support/mindstorms-ev3/developer-kits.
     *
     * Direct commands are one of two types:
     * DIRECT_COMMAND_NO_REPLY = a direct command where no reply is expected
     * DIRECT_COMMAND_REPLY = a direct command where a reply is expected, and the
     * number and length of returned values needs to be specified.
     *
     * The direct command byte array sent takes the following format:
     * Byte 0 - 1: Command size, Little Endian. Command size not including these 2 bytes
     * Byte 2 - 3: Message counter, Little Endian. Forth running counter
     * Byte 4:     Command type. Either DIRECT_COMMAND_REPLY or DIRECT_COMMAND_NO_REPLY
     * Byte 5 - 6: Reservation (allocation) of global and local variables using a compressed format
     *             (globals reserved in byte 5 and the 2 lsb of byte 6, locals reserved in the upper
     *             6 bits of byte 6) – see documentation for more details.
     * Byte 7 - n: Byte codes as a single command or compound commands (I.e. more commands composed
     *             as a small program)
     *
     * @param {number} type - the direct command type.
     * @param {string} byteCommands - a compound array of EV3 Opcode + arguments.
     * @param {number} allocation - the allocation of global and local vars needed for replies.
     * @return {array} - generated complete command byte array, with header and compounded commands.
     */
    generateCommand (type, byteCommands, allocation = 0) {

        // Header (Bytes 0 - 6)
        let command = [];
        command[2] = 0; // Message counter unused for now
        command[3] = 0; // Message counter unused for now
        command[4] = type;
        command[5] = allocation & 0xFF;
        command[6] = allocation >> 8 && 0xFF;

        // Bytecodes (Bytes 7 - n)
        command = command.concat(byteCommands);

        // Calculate command length minus first two header bytes
        const len = command.length - 2;
        command[0] = len & 0xFF;
        command[1] = len >> 8 && 0xFF;

        return command;
    }

generateCommand returns array, not Uint8Array, so it is the same with wedo2, message sent will always be empty. If i have time, i will perhaps review other extensions.

GarboMuffin commented 8 months ago

This is supposed to be fixed on the live https://turbowarp.org/editor -- have you been able to test it with real hardware?