chapter 3: ScratchX

Graphical Laguage for Arduino

http://blog.ardublock.com/2012/06/11/setup-ardublock-development-in-eclipse/

*Redbot controller for scratchx https://github.com/MrYsLab/rb4s

nodejs +scratch x

https://www.npmjs.com/package/http-server

nodejs
1.npm install http-server -g 2.http-server ./public

IE11 – OK example-firmata- standard firmata - upload IE —close - plugin에서 시리얼 신호를 보내서 오류가 남

Arduino Uno +ScratchX =>OK Arduino Mega=ScratchX ==> OK

<<original>>

http://scratchx.org/?url=http://khanning.github.io/scratch-arduino-extension/arduino_extension.js=ko#scratch

IE11 — OK D:SEANLAB2ScratchXrealworld_gitnode-scratchx

node app.js node scratchx.js

http://localhost:8080/?url=http://localhost:8080/scratch_extensions/arduino_extension.js=ko#scratch

scratch_microbit extension OK

scratch-microbit-extension/firmware/ makecode-microbit-scratch-extension.hex install

D:SEANLAB2ScratchXgit_downscratch-microbit-extension node index.js 실행후 ==> Green light

http://scratchx.org/?url=https://jaafreitas.github.io/scratch-microbit-extension/scratch_microbit.js&lang=en#scratch

http://localhost:8080/?url=http://localhost:8080/scratch_extensions/scratch_microbit.js=en#scratch

http://localhost:8080/?url=http://localhost:8080/scratch_extensions/makecode-microbit-scratch-extension.js=en&url=http://localhost:8080/scratch_extensions/examples/Compass.sbx#scratch

http://localhost:8080/?url=http://localhost:8080/scratch_extensions/makecode-microbit-scratch-extension.js=en&url=http://localhost:8080/scratch_extensions/examples/Button.sbx#scratch http://localhost:8080/?url=http://localhost:8080/scratch_extensions/makecode-microbit-scratch-extension.js=en&url=http://localhost:8080/scratch_extensions/examples/Display.sbx#scratch http://localhost:8080/?url=http://localhost:8080/scratch_extensions/makecode-microbit-scratch-extension.js=en&url=http://localhost:8080/scratch_extensions/examples/Tilt.sbx#scratch

minecraft scratch

http://scratchx.org/?url=https://mojang.github.io/cc-scratch.js#scratch http://localhost:8080/?url=http://localhost:8080/scratch_extensions/cc-scratch.js=ko#scratch

(function(ext) {
    var poller = null;
    var device = null;
    var status = false;
    var _selectors = {};
    var _buffer = [];
    var _isParseStartIndex = 0;
    var _isParseStart = false;
    var ports = {
        Port1: 1,
        Port2: 2,
        Port3: 3,
        Port4: 4,
        M1:9,
        M2:10,
        'on board':7,
        'light sensor on board':8
    };
    var slots = {
        Slot1:1,
        Slot2:2
    };
    var switchStatus = {
        On:1,
        Off:0
    };
    var buttonStatus = {
        pressed:0,
        released:1
    }
    var shutterStatus = {
        Press:0,
        Release:1,
        'Focus On':2,
        'Focus Off':3,
    };
    var axis = {
        'X-Axis':1,
        'Y-Axis':2,
        'Z-Axis':3
    };
    var ircodes = { "A":69,
        "B":70,
        "C":71,
        "D":68,
        "E":67,
        "F":13,
        "↑":64,
        "↓":25,
        "←":7,
        "→":9,
        "R0":22,
        "R1":12,
        "R2":24,
        "R3":94,
        "R4":8,
        "R5":28,
        "R6":90,
        "R7":66,
        "R8":82,
        "R9":74};
    var __irCodes = [];
    for(var key in ircodes){
        __irCodes.push(ircodes[key]);
    }
    var tones = {"B0":31,"C1":33,"D1":37,"E1":41,"F1":44,"G1":49,"A1":55,"B1":62,
            "C2":65,"D2":73,"E2":82,"F2":87,"G2":98,"A2":110,"B2":123,
            "C3":131,"D3":147,"E3":165,"F3":175,"G3":196,"A3":220,"B3":247,
            "C4":262,"D4":294,"E4":330,"F4":349,"G4":392,"A4":440,"B4":494,
            "C5":523,"D5":587,"E5":659,"F5":698,"G5":784,"A5":880,"B5":988,
            "C6":1047,"D6":1175,"E6":1319,"F6":1397,"G6":1568,"A6":1760,"B6":1976,
            "C7":2093,"D7":2349,"E7":2637,"F7":2794,"G7":3136,"A7":3520,"B7":3951,
    "C8":4186,"D8":4699};
    var beats = {"Half":500,"Quater":250,"Eighth":125,"Whole":1000,"Double":2000,"Zero":0};

    function onParse(byte){
        position = 0
        value = 0
        _buffer.push(byte);
        var len = _buffer.length;
        if(len>= 2){
            if (_buffer[len-1]==0x55 && _buffer[len-2]==0xff){
                _isParseStartIndex = len-2
                _isParseStart = true;
            }
            if (_buffer[len-1]==0xa && _buffer[len-2]==0xd && _isParseStart == true){
                _isParseStart = false;

                var position = _isParseStartIndex+2;
                var extId = _buffer[position];
                position+=1;
                var type = _buffer[position];
                position+=1;
                var value = 0;
                // 1 byte 2 float 3 short 4 len+string 5 double

                if (type == 1){
                    value = _buffer[position];
                }
                if (type == 2){
                    value = readFloat(position);
                    if(value<-255 || value>1023){
                        value = 0;
                    }
                }
                if (type == 3){
                    value = readShort(position);
                }
                if (type == 4){
                    value = readString(position);
                }
                if (type == 5){
                    value = readDouble(position);
                }
                if(type<=5){
                    if(value!=null){
                        _selectors["value_"+extId] = value;
                    }
                    _selectors["callback_"+extId](value);
                }
                _buffer = []
            }
        }
    }
    function readFloat(position){
        var buf = new ArrayBuffer(4);
        var intView = new Uint8Array(buf);
        var floatView = new Float32Array(buf);
        for(var i=0;i<4;i++){
            intView[i] = _buffer[position+i];
        }
        return floatView[0];
    }
    function readShort(position){
        var buf = new ArrayBuffer(2);
        var intView = new Uint8Array(buf);
        var shortView = new Int16Array(buf);
        for(var i=0;i<2;i++){
            intView[i] = _buffer[position+i];
        }
        return shortView[0];
    }
    function readString(position){
        var l = _buffer[position]
        position+=1
        s = ""
        for(var i=0;i<l;i++){
            s += self.buffer[position+i].charAt(0)
        }
        return s
    }
    function readDouble(position){
        var buf = new ArrayBuffer(8);
        var intView = new Uint8Array(buf);
        var doubleView = new Float64Array(buf);
        for(var i=0;i<8;i++){
            intView[i] = _buffer[position+i];
        }
        return doubleView[0];
    }
    function short2array(v){
        var buf = new ArrayBuffer(2);
        var intView = new Uint8Array(buf);
        var shortView = new Int16Array(buf);
        shortView[0] = v;
        return [intView[0],intView[1]];
    }
    function float2array(v){
        var buf = new ArrayBuffer(4);
        var intView = new Uint8Array(buf);
        var floatView = new Float32Array(buf);
        floatView[0] = v;
        return [intView[0],intView[1],intView[2],intView[3]];
    }
    function string2array(v){
        var arr = v.split("");
        for(var i=0;i<arr.length;i++){
            arr[i] = arr[i].charCodeAt(0);
        }
        console.log(arr);
        return arr;
    }
    function deviceOpened(dev) {
        // if device fails to open, forget about it
        if (dev == null) device = null;

        // otherwise start polling
        poller = setInterval(function() {
            if(device!=null){
                function callback(buffer){
                    var buf = new Uint8Array(buffer);
                    var len = buf[0];
                    if(buf[0]>0){
                        for(var i=0;i<len;i++){
                            onParse(buf[i+1]);
                        }
                    }
                }
                device.read(callback,30);
            }
        }, 20);
    };
    var lastWritten = 0;
    var _buffers = [];
    var _isWaiting = false;
    function addPackage(buffer,callback){
        _buffers.push(buffer);
        var extId = buffer[4];
        setTimeout(function(){
            callback(_selectors["value_"+extId]);
        },100);
        writePackage();
    }
    function writePackage(){
        if(_buffers.length>0&&_isWaiting==false){
            _isWaiting = true;
            var buffer = _buffers[0];
            _buffers.shift();
            device.write(buffer,function(){
                setTimeout(function(){
                    _isWaiting = false;
                    writePackage();
                },20);
            });
        }
    }
    ext._getStatus = function() {
        return status?{status: 2, msg: 'Ready'}:{status: 1, msg: 'Not Ready'};
    };
    ext._deviceConnected = function(dev) {
        if(device) return;
        console.log("_deviceConnected");
        device = dev;
        device.open(deviceOpened);
        status = true;
    };
    ext._deviceRemoved = function(dev) {
        if(device != dev) return;
        if(poller) poller = clearInterval(poller);
        device = null;
        status = false;
    };
    ext._shutdown = function() {
        if(poller) poller = clearInterval(poller);
        if(device) device.close();
        device = null;
        status = false;
    }
    var arrayBufferFromArray = function(data){
        var result = new Int8Array(data.length);
        for(var i=0;i<data.length;i++){
            result[i] = data[i];
        }
        return result;
    }

    //************* mBot Blocks ***************//
    function genNextID(port, slot){
        var nextID = port * 4 + slot;
        return nextID;
    }
    ext.resetAll = function(){
        var data = [0x5,0xff, 0x55, 0x02, 0x0, 0x04];
        addPackage(arrayBufferFromArray(data), function(){
        })
    };
    ext.runBot = function(lSpeed,rSpeed){
        var deviceId = 5;
        var extId = 0;
        var data = [extId, 0x02, deviceId].concat(short2array(-lSpeed)).concat(short2array(rSpeed));
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        addPackage(arrayBufferFromArray(data), function(){
        });
    }
    ext.runMotor = function(port,speed){
        if(typeof port=="string"){
            port = ports[port];
        }
        var deviceId = 10;
        var extId = 0;
        var data = [extId, 0x02, deviceId, port].concat(short2array(speed));
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        addPackage(arrayBufferFromArray(data), function(){
        });
    }
    ext.runServo = function(port,slot,angle){
        if(typeof port=="string"){
            port = ports[port];
        }
        if(typeof slot=="string"){
            slot = slots[slot];
        }
        var deviceId = 11;
        var extId = 0;
        var data = [extId, 0x02, deviceId, port, slot, angle];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        addPackage(arrayBufferFromArray(data), function(){
        });
    }
    ext.runLedOnBoard = function(index,red,green,blue){
        if(index == "all"){
            index = 0;
        }
        runLed(7,2,index,red,green,blue)
    }
    ext.runLed = function(port,slot,index,red,green,blue){
        if(typeof port == "string"){
            port = ports[port];
        }
        if(typeof slot == "string"){
            slot = slots[slot];
        }
        if(port==ports["on board"]){
            slot = 2;
        }
        if(index == "all"){
            index = 0;
        }
        var deviceId = 8;
        var extId = 0;
        var data = [extId, 0x02, deviceId, port, slot, index, red*1, green*1, blue*1];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        addPackage(arrayBufferFromArray(data), function(){
        });
    }
    ext.runBuzzer = function(tone,beat){
        if(typeof tone=="string"){
            tone = tones[tone];
        }
        if(typeof beat=="string"){
            beat = beats[beat];
        }
        var deviceId = 34;
        var extId = 0;
        var data = [extId, 0x02, deviceId].concat(short2array(tone)).concat(short2array(beat));
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        addPackage(arrayBufferFromArray(data), function(){
        });
    };
    ext.stopBuzzer = function(){
        runBuzzer(0,0);
    };
    ext.showCharacters = function(port,x,y,msg){
        if(typeof port == "string"){
            port = ports[port];
        }
        var deviceId = 41;
        var extId = 0;
        var brightness = 6;
        var data = [extId, 0x02, deviceId, port,1,brightness,3].concat(short2array(x)).concat(short2array(7+y)).concat([msg.length].concat(string2array(msg)));
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        addPackage(arrayBufferFromArray(data), function(){
        });
    }
    ext.showTime = function(port,hour,dot,min){
        if(typeof port == "string"){
            port = ports[port];
        }
        var deviceId = 41;
        var extId = 0;
        var brightness = 6;
        var data = [extId, 0x02, deviceId, port,3,brightness,dot==":"?1:0].concat(short2array(hour)).concat(short2array(min));
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        addPackage(arrayBufferFromArray(data), function(){
        });
    }
    ext.runSevseg = function(port,num){
        if(typeof port == "string"){
            port = ports[port];
        }
        var deviceId = 9;
        var extId = 0;
        var data = [extId, 0x02, deviceId, port].concat(float2array(num));
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        addPackage(arrayBufferFromArray(data), function(){
        });
    }
    ext.runLightSensor = function(port,status){
        if(typeof port == "string"){
            port = ports[port];
        }
        if(typeof status == "string"){
            status = switchStatus[status];
        }
        var deviceId = 3;
        var extId = 0;
        var data = [extId, 0x02, deviceId, port,status];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        addPackage(arrayBufferFromArray(data), function(){
        });
    }
    ext.runShutter = function(port,shutter){
        if(typeof port == "string"){
            port = ports[port];
        }
        if(typeof shutter == "string"){
            shutter = shutterStatus[shutter];
        }
        var deviceId = 20;
        var extId = 0;
        var data = [extId, 0x02, deviceId, port,shutter];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        addPackage(arrayBufferFromArray(data), function(){
        });
    }
    ext.getButtonOnBoard = function(status,callback){
        if(typeof status=="string"){
            status = buttonStatus[status];
        }
        var deviceId = 31;
        var port = 7;
        var extId = genNextID(port,0);
        var data = [extId, 0x01, deviceId, port];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        _selectors["callback_"+extId] = function(v){
            callback(status==1?v>500:v<500);
        }
        addPackage(arrayBufferFromArray(data), _selectors["callback_"+extId]);
    }
    var _lastTime = 0;
    var _lastButtonStatus = [false,false];
    ext.whenButtonPressed = function(status,callback){
        if(typeof status == "string"){
            status = buttonStatus[status];
        }
        if(new Date().getTime()-_lastTime>150){
            _lastTime = new Date().getTime();
            var deviceId = 31;
            var port = 7;
            var extId = genNextID(port,status);
            var data = [extId, 0x01, deviceId, port];
            data = [data.length+3, 0xff, 0x55, data.length].concat(data);
            _selectors["callback_"+extId] = function(v){
                _lastButtonStatus[0] = status==1?v>500:v<500;
                _lastButtonStatus[1] = !_lastButtonStatus[status];
            }
            addPackage(arrayBufferFromArray(data), _selectors["callback_"+extId]);
        }
        return _lastButtonStatus[status];

    }
    ext.getLightSensor = function(port,callback){
        if(typeof port=="string"){
            port = ports[port];
        }
        var deviceId = 3;
        var extId = genNextID(port,0);
        var data = [extId, 0x01, deviceId, port];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        _selectors["callback_"+extId] = callback;
        addPackage(arrayBufferFromArray(data), _selectors["callback_"+extId]);
    }
    ext.getUltrasonic = function(port,callback){
        if(typeof port=="string"){
            port = ports[port];
        }
        var deviceId = 1;
        var extId = genNextID(port,0);
        var data = [extId, 0x01, deviceId, port];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        _selectors["callback_"+extId] = function(v){
            callback(Math.floor(v*100.0)/100.0);
        }
        addPackage(arrayBufferFromArray(data), _selectors["callback_"+extId]);
    }
    ext.getLinefollower = function(port,callback){
        if(typeof port=="string"){
            port = ports[port];
        }
        var deviceId = 17;
        var extId = genNextID(port,0);
        var data = [extId, 0x01, deviceId, port];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        _selectors["callback_"+extId] = callback;
        addPackage(arrayBufferFromArray(data), _selectors["callback_"+extId]);
    }
    ext.getJoystick = function(port,ax,callback){
        if(typeof port=="string"){
            port = ports[port];
        }
        if(typeof ax=="string"){
            ax = axis[ax];
        }
        var deviceId = 5;
        var extId = genNextID(port,ax);
        var data = [extId, 0x01, deviceId, port, ax];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        _selectors["callback_"+extId] = callback;
        addPackage(arrayBufferFromArray(data), _selectors["callback_"+extId]);
    }
    ext.getPotentiometer = function(port,callback){
        if(typeof port=="string"){
            port = ports[port];
        }
        var deviceId = 4;
        var extId = genNextID(port,0);
        var data = [extId, 0x01, deviceId, port];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        _selectors["callback_"+extId] = callback;
        addPackage(arrayBufferFromArray(data), _selectors["callback_"+extId]);
    }
    ext.getSoundSensor = function(port,callback){
        if(typeof port=="string"){
            port = ports[port];
        }
        var deviceId = 7;
        var extId = genNextID(port,0);
        var data = [extId, 0x01, deviceId, port];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        _selectors["callback_"+extId] = callback;
        addPackage(arrayBufferFromArray(data), _selectors["callback_"+extId]);
    }
    ext.getLimitswitch = function(port,slot,callback){
        if(typeof port=="string"){
            port = ports[port];
        }
        if(typeof slot=="string"){
            slot = slots[slot];
        }
        var deviceId = 21;
        var extId = genNextID(port,slot);
        var data = [extId, 0x01, deviceId, port, slot];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        _selectors["callback_"+extId] = callback;
        addPackage(arrayBufferFromArray(data), _selectors["callback_"+extId]);
    }
    ext.getTemperature = function(port,callback){
        if(typeof port=="string"){
            port = ports[port];
        }
        var deviceId = 2;
        var extId = genNextID(port,0);
        var data = [extId, 0x01, deviceId, port];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        _selectors["callback_"+extId] = function(v){
            callback(Math.floor(v*100)/100);
        }
        addPackage(arrayBufferFromArray(data), _selectors["callback_"+extId]);
    }
    ext.getPirmotion = function(port,callback){
        if(typeof port=="string"){
            port = ports[port];
        }
        var deviceId = 6;
        var extId = genNextID(port,0);
        var data = [extId, 0x01, deviceId, port];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        _selectors["callback_"+extId] = callback;
        addPackage(arrayBufferFromArray(data), _selectors["callback_"+extId]);
    }
    ext.getIrRemote = function(code,callback){
        var deviceId = 14;
        if(typeof code=="string"){
            code = ircodes[code];
        }
        var port = 11;
        var slot = __irCodes.indexOf(code);
        var halfSize = __irCodes.length >> 1;
        if(slot >= halfSize){
            ++port;
            slot -= halfSize;
        }
        var extId = genNextID(port,slot);
        var data = [extId, 0x01, deviceId, 0, code];
        data = [data.length+3, 0xff, 0x55, data.length].concat(data);
        _selectors["callback_"+extId] = callback;
        addPackage(arrayBufferFromArray(data), _selectors["callback_"+extId]);
    }
    var descriptor = {
        blocks: [
            [" ", "move left %d.motorvalue right %d.motorvalue","runBot", 100, 100],
            [" ", "set motor%d.motorPort speed %d.motorvalue","runMotor", "M1", 0],
            [" ", "set servo %d.port %d.slot angle %d.servovalue","runServo", "Port1","Slot1", 90],
            [" ", "set led %d.lport %d.slot %d.index red%d.value green%d.value blue%d.value","runLed","on board","Slot1","all",0,0,0],
            [" ", "play tone on note %d.note beat %d.beats","runBuzzer", "C4", "Half"],
            [" ", "show face %d.port x:%n y:%n characters:%s","showCharacters", "Port1", 0,0,"Hello"],
            [" ", "show time %d.port hour:%n %m.points min:%n","showTime", "Port1", 10,":",20],
            [" ", "show drawing %d.port x:%n y:%n draw:%m.drawFace","showDraw", "Port1", 0,0,"        "],
            ["-"],
            [" ", "set 7-segments display%d.port number %n","runSevseg", "Port1", 100],
            [" ", "set light sensor %d.aport led as %d.switchStatus","runLightSensor", "Port3", "On"],
            [" ", "set camera shutter %d.port as %d.shutter","runShutter","Port1", "Press"],
            ["-"],
            ["h", "when button %m.buttonStatus","whenButtonPressed","pressed"],
            ["R", "button %m.buttonStatus","getButtonOnBoard","pressed"],
            ["R", "light sensor %d.laport","getLightSensor","light sensor on board"],
            ["-"],
            ["R", "ultrasonic sensor %d.port distance","getUltrasonic","Port1"],
            ["R", "line follower %d.port","getLinefollower","Port1"],
            ["R", "joystick %d.aport %d.Axis","getJoystick","Port3","X-Axis"],
            ["R", "potentiometer %d.aport","getPotentiometer","Port3"],
            ["R", "sound sensor %d.aport","getSoundSensor","Port3"],
            ["R", "limit switch %d.port %d.slot","getLimitswitch","Port1","Slot1"],
            ["R", "temperature %d.port %d.slot °C","getTemperature","Port3","Slot1"],
            ["R", "pir motion sensor %d.port","getPirmotion","Port2"],
            ["-"],
            ["R","ir remote %m.ircode pressed","getIrRemote","A"],
            ["-"],
            [" ", "send mBot's message %s","runIR", "hello"],
            ["R", "mBot's message received","getIR"],
            ["-"],
            ["R", "timer","getTimer", "0"],
            [" ", "reset timer","resetTimer", "0"]
            ],
        menus: {
            motorPort:["M1","M2"],
            slot:["Slot1","Slot2"],
            index:["all",1,2],
            Axis:["X-Axis","Y-Axis"],
            port:["Port1","Port2","Port3","Port4"],
            aport:["Port3","Port4"],
            lport:["led on board","Port1","Port2","Port3","Port4"],
            laport:["light sensor on board","Port3","Port4"],
            direction:["run forward","run backward","turn right","turn left"],
            points:[":"," "],
            note:["C2","D2","E2","F2","G2","A2","B2","C3","D3","E3","F3","G3","A3","B3","C4","D4","E4","F4","G4","A4","B4","C5","D5","E5","F5","G5","A5","B5","C6","D6","E6","F6","G6","A6","B6","C7","D7","E7","F7","G7","A7","B7","C8","D8"],
            beats:["Half","Quater","Eighth","Whole","Double","Zero"],
            servovalue:[0,45,90,135,180],
            motorvalue:[-255,-100,-50,0,50,100,255],
            value:[0,20,60,150,255],
            buttonStatus:["pressed","released"],
            shutter:["Press","Release","Focus On","Focus Off"],
            switchStatus:["Off","On"],
            ircode:["A","B","C","D","E","F","↑","↓","←","→","Setting","R0","R1","R2","R3","R4","R5","R6","R7","R8","R9"],
        }
    };
    var hid_info = {type: 'hid', vendor: 0x0416, product: 0xffff};
    ScratchExtensions.register('Makeblock mBot', descriptor, ext, hid_info);
})({});