var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; /// var pxsim; (function (pxsim) { var DalBoard = (function (_super) { __extends(DalBoard, _super); function DalBoard() { _super.call(this); // components this.fileSystem = new pxsim.FileSystemState(); this.builtinParts["ledmatrix"] = this.ledMatrixState = new pxsim.LedMatrixState(pxsim.runtime); this.builtinParts["buttonpair"] = this.buttonPairState = new pxsim.ButtonPairState({ ID_BUTTON_A: 1 /* MICROBIT_ID_BUTTON_A */, ID_BUTTON_B: 2 /* MICROBIT_ID_BUTTON_B */, ID_BUTTON_AB: 26 /* MICROBIT_ID_BUTTON_AB */, BUTTON_EVT_UP: 2 /* MICROBIT_BUTTON_EVT_UP */, BUTTON_EVT_CLICK: 3 /* MICROBIT_BUTTON_EVT_CLICK */ }); this.builtinParts["edgeconnector"] = this.edgeConnectorState = new pxsim.EdgeConnectorState({ pins: [ 7 /* MICROBIT_ID_IO_P0 */, 8 /* MICROBIT_ID_IO_P1 */, 9 /* MICROBIT_ID_IO_P2 */, 10 /* MICROBIT_ID_IO_P3 */, 11 /* MICROBIT_ID_IO_P4 */, 12 /* MICROBIT_ID_IO_P5 */, 13 /* MICROBIT_ID_IO_P6 */, 14 /* MICROBIT_ID_IO_P7 */, 15 /* MICROBIT_ID_IO_P8 */, 16 /* MICROBIT_ID_IO_P9 */, 17 /* MICROBIT_ID_IO_P10 */, 18 /* MICROBIT_ID_IO_P11 */, 19 /* MICROBIT_ID_IO_P12 */, 20 /* MICROBIT_ID_IO_P13 */, 21 /* MICROBIT_ID_IO_P14 */, 22 /* MICROBIT_ID_IO_P15 */, 23 /* MICROBIT_ID_IO_P16 */, 0, 0, 24 /* MICROBIT_ID_IO_P19 */, 25 /* MICROBIT_ID_IO_P20 */, 50 /* MICROBIT_ID_IO_P21 */ ], servos: { "P0": 19 /* MICROBIT_ID_IO_P12 */, "P1": 7 /* MICROBIT_ID_IO_P0 */, "P2": 8 /* MICROBIT_ID_IO_P1 */, "P3": 23 /* MICROBIT_ID_IO_P16 */ } }); this.builtinParts["radio"] = this.radioState = new pxsim.RadioState(pxsim.runtime); this.builtinParts["accelerometer"] = this.accelerometerState = new pxsim.AccelerometerState(pxsim.runtime); this.builtinParts["serial"] = this.serialState = new pxsim.SerialState(); this.builtinParts["thermometer"] = this.thermometerState = new pxsim.ThermometerState(); this.builtinParts["lightsensor"] = this.lightSensorState = new pxsim.LightSensorState(); this.builtinParts["compass"] = this.compassState = new pxsim.CompassState(); this.builtinParts["neopixel"] = this.neopixelState = new pxsim.NeoPixelState(); this.builtinParts["speaker"] = this.speakerState = new pxsim.SpeakerState(); this.builtinParts["microservo"] = this.edgeConnectorState; this.builtinVisuals["buttonpair"] = function () { return new pxsim.visuals.ButtonPairView(); }; this.builtinVisuals["ledmatrix"] = function () { return new pxsim.visuals.LedMatrixView(); }; this.builtinVisuals["neopixel"] = function () { return new pxsim.visuals.NeoPixelView(); }; this.builtinVisuals["microservo"] = function () { return new pxsim.visuals.MicroServoView(); }; this.builtinPartVisuals["buttonpair"] = function (xy) { return pxsim.visuals.mkBtnSvg(xy); }; this.builtinPartVisuals["ledmatrix"] = function (xy) { return pxsim.visuals.mkLedMatrixSvg(xy, 8, 8); }; this.builtinPartVisuals["neopixel"] = function (xy) { return pxsim.visuals.mkNeoPixelPart(xy); }; this.builtinPartVisuals["microservo"] = function (xy) { return pxsim.visuals.mkMicroServoPart(xy); }; } DalBoard.prototype.receiveMessage = function (msg) { if (!pxsim.runtime || pxsim.runtime.dead) return; switch (msg.type || "") { case "eventbus": var ev = msg; this.bus.queue(ev.id, ev.eventid, ev.value); break; case "serial": var data = msg.data || ""; this.serialState.recieveData(data); break; case "radiopacket": var packet = msg; this.radioState.recievePacket(packet); break; } }; DalBoard.prototype.initAsync = function (msg) { _super.prototype.initAsync.call(this, msg); var options = (msg.options || {}); var boardDef = msg.boardDefinition; var cmpsList = msg.parts; var cmpDefs = msg.partDefinitions || {}; var fnArgs = msg.fnArgs; var opts = { state: this, boardDef: boardDef, partsList: cmpsList, partDefs: cmpDefs, fnArgs: fnArgs, maxWidth: "100%", maxHeight: "100%", }; var viewHost = new pxsim.visuals.BoardHost(pxsim.visuals.mkBoardView({ visual: boardDef.visual }), opts); document.body.innerHTML = ""; // clear children document.body.appendChild(viewHost.getView()); return Promise.resolve(); }; return DalBoard; }(pxsim.CoreBoard)); pxsim.DalBoard = DalBoard; function initRuntimeWithDalBoard() { pxsim.U.assert(!pxsim.runtime.board); var b = new DalBoard(); pxsim.runtime.board = b; pxsim.runtime.postError = function (e) { pxsim.led.setBrightness(255); var img = board().ledMatrixState.image; img.clear(); img.set(0, 4, 255); img.set(1, 3, 255); img.set(2, 3, 255); img.set(3, 3, 255); img.set(4, 4, 255); img.set(0, 0, 255); img.set(1, 0, 255); img.set(0, 1, 255); img.set(1, 1, 255); img.set(3, 0, 255); img.set(4, 0, 255); img.set(3, 1, 255); img.set(4, 1, 255); pxsim.runtime.updateDisplay(); }; } pxsim.initRuntimeWithDalBoard = initRuntimeWithDalBoard; if (!pxsim.initCurrentRuntime) { pxsim.initCurrentRuntime = initRuntimeWithDalBoard; } function board() { return pxsim.runtime.board; } pxsim.board = board; })(pxsim || (pxsim = {})); /// /// /// //HACK: allows instructions.html to access pxtblocks without requiring simulator.html to import blocks as well if (!window.pxt) window.pxt = {}; var pxtrunner = pxt.runner; var pxtdocs = pxt.docs; var pxsim; (function (pxsim) { var instructions; (function (instructions) { function drawInstructions() { pxsim.visuals.mkBoardView = function (opts) { return new pxsim.visuals.MicrobitBoardSvg({ runtime: pxsim.runtime, theme: pxsim.visuals.randomTheme(), disableTilt: false, wireframe: opts.wireframe, }); }; var getQsVal = pxsim.parseQueryString(); //project name var name = getQsVal("name") || "Untitled"; // board def var boardDef = JSON.parse(getQsVal("board")); //parts list var parts = (getQsVal("parts") || "").split(" "); parts.sort(); // parts definitions var partDefinitions = JSON.parse(getQsVal("partdefs") || "{}"); //fn args var fnArgs = JSON.parse((getQsVal("fnArgs") || "{}")); //project code var tsCode = getQsVal("code"); var tsPackage = getQsVal("package") || ""; var codeSpinnerDiv = document.getElementById("proj-code-spinner"); var codeContainerDiv = document.getElementById("proj-code-container"); if (tsCode) { //we use the docs renderer to decompile the code to blocks and render it //TODO: render the blocks code directly var md = "```blocks\n" + tsCode + "\n```\n```package\n" + tsPackage + "\n```\n"; pxtdocs.requireMarked = function () { return window.marked; }; pxtrunner.renderMarkdownAsync(codeContainerDiv, md) .done(function () { var codeSvg = $("#proj-code-container svg"); if (codeSvg.length > 0) { //code rendered successfully as blocks codeSvg.css("width", "inherit"); codeSvg.css("height", "inherit"); //takes the svg out of the wrapper markdown codeContainerDiv.innerHTML = ""; codeContainerDiv.appendChild(codeSvg[0]); } else { //code failed to convert to blocks, display as typescript instead codeContainerDiv.innerText = tsCode; } $(codeContainerDiv).show(); $(codeSpinnerDiv).hide(); }); } if (name) $("#proj-title").text(name); //init runtime if (!pxsim.initCurrentRuntime) pxsim.initCurrentRuntime = pxsim.initRuntimeWithDalBoard; instructions.renderParts({ name: name, boardDef: boardDef, parts: parts, partDefinitions: partDefinitions, fnArgs: fnArgs }); } instructions.drawInstructions = drawInstructions; })(instructions = pxsim.instructions || (pxsim.instructions = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var input; (function (input) { function onGesture(gesture, handler) { var b = pxsim.board().accelerometerState; b.accelerometer.activate(); if (gesture == 11 && !b.useShake) { b.useShake = true; pxsim.runtime.queueDisplayUpdate(); } pxsim.pxtcore.registerWithDal(27 /* MICROBIT_ID_GESTURE */, gesture, handler); } input.onGesture = onGesture; function acceleration(dimension) { var b = pxsim.board().accelerometerState; var acc = b.accelerometer; acc.activate(); switch (dimension) { case 0: return acc.getX(); case 1: return acc.getY(); case 2: return acc.getZ(); default: return Math.floor(Math.sqrt(acc.instantaneousAccelerationSquared())); } } input.acceleration = acceleration; function rotation(kind) { var b = pxsim.board().accelerometerState; var acc = b.accelerometer; acc.activate(); var x = acc.getX(pxsim.MicroBitCoordinateSystem.NORTH_EAST_DOWN); var y = acc.getX(pxsim.MicroBitCoordinateSystem.NORTH_EAST_DOWN); var z = acc.getX(pxsim.MicroBitCoordinateSystem.NORTH_EAST_DOWN); var roll = Math.atan2(y, z); var pitch = Math.atan(-x / (y * Math.sin(roll) + z * Math.cos(roll))); var r = 0; switch (kind) { case 0: r = pitch; break; case 1: r = roll; break; } return Math.floor(r / Math.PI * 180); } input.rotation = rotation; function setAccelerometerRange(range) { var b = pxsim.board().accelerometerState; b.accelerometer.setSampleRange(range); } input.setAccelerometerRange = setAccelerometerRange; })(input = pxsim.input || (pxsim.input = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { /** * Co-ordinate systems that can be used. * RAW: Unaltered data. Data will be returned directly from the accelerometer. * * SIMPLE_CARTESIAN: Data will be returned based on an easy to understand alignment, consistent with the cartesian system taught in schools. * When held upright, facing the user: * * / * +--------------------+ z * | | * | ..... | * | * ..... * | * ^ | ..... | * | | | * y +--------------------+ x--> * * * NORTH_EAST_DOWN: Data will be returned based on the industry convention of the North East Down (NED) system. * When held upright, facing the user: * * z * +--------------------+ / * | | * | ..... | * | * ..... * | * ^ | ..... | * | | | * x +--------------------+ y--> * */ (function (MicroBitCoordinateSystem) { MicroBitCoordinateSystem[MicroBitCoordinateSystem["RAW"] = 0] = "RAW"; MicroBitCoordinateSystem[MicroBitCoordinateSystem["SIMPLE_CARTESIAN"] = 1] = "SIMPLE_CARTESIAN"; MicroBitCoordinateSystem[MicroBitCoordinateSystem["NORTH_EAST_DOWN"] = 2] = "NORTH_EAST_DOWN"; })(pxsim.MicroBitCoordinateSystem || (pxsim.MicroBitCoordinateSystem = {})); var MicroBitCoordinateSystem = pxsim.MicroBitCoordinateSystem; var Accelerometer = (function () { function Accelerometer(runtime) { this.runtime = runtime; this.sigma = 0; // the number of ticks that the instantaneous gesture has been stable. this.lastGesture = 0; // the last, stable gesture recorded. this.currentGesture = 0; // the instantaneous, unfiltered gesture detected. this.sample = { x: 0, y: 0, z: -1023 }; this.shake = { x: false, y: false, z: false, count: 0, shaken: 0, timer: 0 }; // State information needed to detect shake events. this.isActive = false; this.sampleRange = 2; this.id = 4 /* MICROBIT_ID_ACCELEROMETER */; } Accelerometer.prototype.setSampleRange = function (range) { this.activate(); this.sampleRange = Math.max(1, Math.min(8, range)); }; Accelerometer.prototype.activate = function () { if (!this.isActive) { this.isActive = true; this.runtime.queueDisplayUpdate(); } }; /** * Reads the acceleration data from the accelerometer, and stores it in our buffer. * This is called by the tick() member function, if the interrupt is set! */ Accelerometer.prototype.update = function (x, y, z) { // read MSB values... this.sample.x = Math.floor(x); this.sample.y = Math.floor(y); this.sample.z = Math.floor(z); // Update gesture tracking this.updateGesture(); // Indicate that a new sample is available pxsim.board().bus.queue(this.id, 1 /* MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE */); }; Accelerometer.prototype.instantaneousAccelerationSquared = function () { // Use pythagoras theorem to determine the combined force acting on the device. return this.sample.x * this.sample.x + this.sample.y * this.sample.y + this.sample.z * this.sample.z; }; /** * Service function. Determines the best guess posture of the device based on instantaneous data. * This makes no use of historic data (except for shake), and forms this input to the filter implemented in updateGesture(). * * @return A best guess of the current posture of the device, based on instantaneous data. */ Accelerometer.prototype.instantaneousPosture = function () { var force = this.instantaneousAccelerationSquared(); var shakeDetected = false; // Test for shake events. // We detect a shake by measuring zero crossings in each axis. In other words, if we see a strong acceleration to the left followed by // a string acceleration to the right, then we can infer a shake. Similarly, we can do this for each acxis (left/right, up/down, in/out). // // If we see enough zero crossings in succession (MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD), then we decide that the device // has been shaken. if ((this.getX() < -400 /* MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE */ && this.shake.x) || (this.getX() > 400 /* MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE */ && !this.shake.x)) { shakeDetected = true; this.shake.x = !this.shake.x; } if ((this.getY() < -400 /* MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE */ && this.shake.y) || (this.getY() > 400 /* MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE */ && !this.shake.y)) { shakeDetected = true; this.shake.y = !this.shake.y; } if ((this.getZ() < -400 /* MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE */ && this.shake.z) || (this.getZ() > 400 /* MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE */ && !this.shake.z)) { shakeDetected = true; this.shake.z = !this.shake.z; } if (shakeDetected && this.shake.count < 4 /* MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD */ && ++this.shake.count == 4 /* MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD */) this.shake.shaken = 1; if (++this.shake.timer >= 10 /* MICROBIT_ACCELEROMETER_SHAKE_DAMPING */) { this.shake.timer = 0; if (this.shake.count > 0) { if (--this.shake.count == 0) this.shake.shaken = 0; } } if (this.shake.shaken) return 12 /* MICROBIT_ACCELEROMETER_EVT_SHAKE */; var sq = function (n) { return n * n; }; if (force < sq(400 /* MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE */)) return 7 /* MICROBIT_ACCELEROMETER_EVT_FREEFALL */; // TODO: fix this //if (force > sq(DAL.MICROBIT_ACCELEROMETER_3G_TOLERANCE)) // return DAL.MICROBIT_ACCELEROMETER_EVT_3G; if (force > sq(6144 /* MICROBIT_ACCELEROMETER_6G_TOLERANCE */)) return 10 /* MICROBIT_ACCELEROMETER_EVT_6G */; if (force > sq(8192 /* MICROBIT_ACCELEROMETER_8G_TOLERANCE */)) return 11 /* MICROBIT_ACCELEROMETER_EVT_8G */; // Determine our posture. if (this.getX() < (-1000 + 200 /* MICROBIT_ACCELEROMETER_TILT_TOLERANCE */)) return 3 /* MICROBIT_ACCELEROMETER_EVT_TILT_LEFT */; if (this.getX() > (1000 - 200 /* MICROBIT_ACCELEROMETER_TILT_TOLERANCE */)) return 4 /* MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT */; if (this.getY() < (-1000 + 200 /* MICROBIT_ACCELEROMETER_TILT_TOLERANCE */)) return 2 /* MICROBIT_ACCELEROMETER_EVT_TILT_DOWN */; if (this.getY() > (1000 - 200 /* MICROBIT_ACCELEROMETER_TILT_TOLERANCE */)) return 1 /* MICROBIT_ACCELEROMETER_EVT_TILT_UP */; if (this.getZ() < (-1000 + 200 /* MICROBIT_ACCELEROMETER_TILT_TOLERANCE */)) return 6 /* MICROBIT_ACCELEROMETER_EVT_FACE_DOWN */; if (this.getZ() > (1000 - 200 /* MICROBIT_ACCELEROMETER_TILT_TOLERANCE */)) return 5 /* MICROBIT_ACCELEROMETER_EVT_FACE_UP */; return 0; }; Accelerometer.prototype.updateGesture = function () { // Determine what it looks like we're doing based on the latest sample... var g = this.instantaneousPosture(); // Perform some low pass filtering to reduce jitter from any detected effects if (g == this.currentGesture) { if (this.sigma < 5 /* MICROBIT_ACCELEROMETER_GESTURE_DAMPING */) this.sigma++; } else { this.currentGesture = g; this.sigma = 0; } // If we've reached threshold, update our record and raise the relevant event... if (this.currentGesture != this.lastGesture && this.sigma >= 5 /* MICROBIT_ACCELEROMETER_GESTURE_DAMPING */) { this.lastGesture = this.currentGesture; pxsim.board().bus.queue(27 /* MICROBIT_ID_GESTURE */, this.lastGesture); } }; /** * Reads the X axis value of the latest update from the accelerometer. * @param system The coordinate system to use. By default, a simple cartesian system is provided. * @return The force measured in the X axis, in milli-g. * * Example: * @code * uBit.accelerometer.getX(); * uBit.accelerometer.getX(RAW); * @endcode */ Accelerometer.prototype.getX = function (system) { if (system === void 0) { system = MicroBitCoordinateSystem.SIMPLE_CARTESIAN; } this.activate(); switch (system) { case MicroBitCoordinateSystem.SIMPLE_CARTESIAN: return -this.sample.x; case MicroBitCoordinateSystem.NORTH_EAST_DOWN: return this.sample.y; //case MicroBitCoordinateSystem.SIMPLE_CARTESIAN.RAW: default: return this.sample.x; } }; /** * Reads the Y axis value of the latest update from the accelerometer. * @param system The coordinate system to use. By default, a simple cartesian system is provided. * @return The force measured in the Y axis, in milli-g. * * Example: * @code * uBit.accelerometer.getY(); * uBit.accelerometer.getY(RAW); * @endcode */ Accelerometer.prototype.getY = function (system) { if (system === void 0) { system = MicroBitCoordinateSystem.SIMPLE_CARTESIAN; } this.activate(); switch (system) { case MicroBitCoordinateSystem.SIMPLE_CARTESIAN: return -this.sample.y; case MicroBitCoordinateSystem.NORTH_EAST_DOWN: return -this.sample.x; //case RAW: default: return this.sample.y; } }; /** * Reads the Z axis value of the latest update from the accelerometer. * @param system The coordinate system to use. By default, a simple cartesian system is provided. * @return The force measured in the Z axis, in milli-g. * * Example: * @code * uBit.accelerometer.getZ(); * uBit.accelerometer.getZ(RAW); * @endcode */ Accelerometer.prototype.getZ = function (system) { if (system === void 0) { system = MicroBitCoordinateSystem.SIMPLE_CARTESIAN; } this.activate(); switch (system) { case MicroBitCoordinateSystem.NORTH_EAST_DOWN: return -this.sample.z; //case MicroBitCoordinateSystem.SIMPLE_CARTESIAN: //case MicroBitCoordinateSystem.RAW: default: return this.sample.z; } }; /** * Provides a rotation compensated pitch of the device, based on the latest update from the accelerometer. * @return The pitch of the device, in degrees. * * Example: * @code * uBit.accelerometer.getPitch(); * @endcode */ Accelerometer.prototype.getPitch = function () { this.activate(); return Math.floor((360 * this.getPitchRadians()) / (2 * Math.PI)); }; Accelerometer.prototype.getPitchRadians = function () { this.recalculatePitchRoll(); return this.pitch; }; /** * Provides a rotation compensated roll of the device, based on the latest update from the accelerometer. * @return The roll of the device, in degrees. * * Example: * @code * uBit.accelerometer.getRoll(); * @endcode */ Accelerometer.prototype.getRoll = function () { this.activate(); return Math.floor((360 * this.getRollRadians()) / (2 * Math.PI)); }; Accelerometer.prototype.getRollRadians = function () { this.recalculatePitchRoll(); return this.roll; }; /** * Recalculate roll and pitch values for the current sample. * We only do this at most once per sample, as the necessary trigonemteric functions are rather * heavyweight for a CPU without a floating point unit... */ Accelerometer.prototype.recalculatePitchRoll = function () { var x = this.getX(MicroBitCoordinateSystem.NORTH_EAST_DOWN); var y = this.getY(MicroBitCoordinateSystem.NORTH_EAST_DOWN); var z = this.getZ(MicroBitCoordinateSystem.NORTH_EAST_DOWN); this.roll = Math.atan2(y, z); this.pitch = Math.atan(-x / (y * Math.sin(this.roll) + z * Math.cos(this.roll))); }; return Accelerometer; }()); pxsim.Accelerometer = Accelerometer; var AccelerometerState = (function () { function AccelerometerState(runtime) { this.useShake = false; this.accelerometer = new Accelerometer(runtime); } return AccelerometerState; }()); pxsim.AccelerometerState = AccelerometerState; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var input; (function (input) { function onButtonPressed(button, handler) { var b = pxsim.board().buttonPairState; if (button == b.props.ID_BUTTON_AB && !b.usesButtonAB) { b.usesButtonAB = true; pxsim.runtime.queueDisplayUpdate(); } pxsim.pxtcore.registerWithDal(button, 3 /* MICROBIT_BUTTON_EVT_CLICK */, handler); } input.onButtonPressed = onButtonPressed; function buttonIsPressed(button) { var b = pxsim.board().buttonPairState; if (button == b.abBtn.id && !b.usesButtonAB) { b.usesButtonAB = true; pxsim.runtime.queueDisplayUpdate(); } if (button == b.aBtn.id) return b.aBtn.pressed; if (button == b.bBtn.id) return b.bBtn.pressed; return b.abBtn.pressed || (b.aBtn.pressed && b.bBtn.pressed); } input.buttonIsPressed = buttonIsPressed; })(input = pxsim.input || (pxsim.input = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var input; (function (input) { function compassHeading() { var b = pxsim.board().compassState; if (!b.usesHeading) { b.usesHeading = true; pxsim.runtime.queueDisplayUpdate(); } return b.heading; } input.compassHeading = compassHeading; function magneticForce() { // TODO return 0; } input.magneticForce = magneticForce; })(input = pxsim.input || (pxsim.input = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var input; (function (input) { function onPinPressed(pinId, handler) { var pin = pxsim.getPin(pinId); if (!pin) return; pin.isTouched(); pxsim.pxtcore.registerWithDal(pin.id, 3 /* MICROBIT_BUTTON_EVT_CLICK */, handler); } input.onPinPressed = onPinPressed; function onPinReleased(pinId, handler) { var pin = pxsim.getPin(pinId); if (!pin) return; pin.isTouched(); pxsim.pxtcore.registerWithDal(pin.id, 2 /* MICROBIT_BUTTON_EVT_UP */, handler); } input.onPinReleased = onPinReleased; function pinIsPressed(pinId) { var pin = pxsim.getPin(pinId); if (!pin) return false; return pin.isTouched(); } input.pinIsPressed = pinIsPressed; })(input = pxsim.input || (pxsim.input = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { function getPin(id) { return pxsim.board().edgeConnectorState.getPin(id); } pxsim.getPin = getPin; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var pins; (function (pins_1) { function digitalReadPin(pinId) { var pin = pxsim.getPin(pinId); if (!pin) return; pin.mode = pxsim.PinFlags.Digital | pxsim.PinFlags.Input; return pin.value > 100 ? 1 : 0; } pins_1.digitalReadPin = digitalReadPin; function digitalWritePin(pinId, value) { var pin = pxsim.getPin(pinId); if (!pin) return; pin.mode = pxsim.PinFlags.Digital | pxsim.PinFlags.Output; pin.value = value > 0 ? 1023 : 0; pxsim.runtime.queueDisplayUpdate(); } pins_1.digitalWritePin = digitalWritePin; function setPull(pinId, pull) { var pin = pxsim.getPin(pinId); if (!pin) return; pin.pull = pull; } pins_1.setPull = setPull; function analogReadPin(pinId) { var pin = pxsim.getPin(pinId); if (!pin) return; pin.mode = pxsim.PinFlags.Analog | pxsim.PinFlags.Input; return pin.value || 0; } pins_1.analogReadPin = analogReadPin; function analogWritePin(pinId, value) { var pin = pxsim.getPin(pinId); if (!pin) return; pin.mode = pxsim.PinFlags.Analog | pxsim.PinFlags.Output; pin.value = value ? 1 : 0; pxsim.runtime.queueDisplayUpdate(); } pins_1.analogWritePin = analogWritePin; function analogSetPeriod(pinId, micros) { var pin = pxsim.getPin(pinId); if (!pin) return; pin.mode = pxsim.PinFlags.Analog | pxsim.PinFlags.Output; pin.period = micros; pxsim.runtime.queueDisplayUpdate(); } pins_1.analogSetPeriod = analogSetPeriod; function servoWritePin(pinId, value) { var pin = pxsim.getPin(pinId); if (!pin) return; analogSetPeriod(pinId, 20000); pin.servoAngle = Math.max(0, Math.min(180, value)); } pins_1.servoWritePin = servoWritePin; function servoSetPulse(pinId, micros) { var pin = pxsim.getPin(pinId); if (!pin) return; // TODO } pins_1.servoSetPulse = servoSetPulse; function analogSetPitchPin(pinId) { var pin = pxsim.getPin(pinId); if (!pin) return; pxsim.board().edgeConnectorState.pins.filter(function (p) { return !!p; }).forEach(function (p) { return p.pitch = false; }); pin.pitch = true; } pins_1.analogSetPitchPin = analogSetPitchPin; function analogPitch(frequency, ms) { // update analog output var pins = pxsim.board().edgeConnectorState.pins; var pin = pins.filter(function (pin) { return !!pin && pin.pitch; })[0] || pins[0]; pin.mode = pxsim.PinFlags.Analog | pxsim.PinFlags.Output; if (frequency <= 0) { pin.value = 0; pin.period = 0; } else { pin.value = 512; pin.period = 1000000 / frequency; } pxsim.runtime.queueDisplayUpdate(); var cb = pxsim.getResume(); pxsim.AudioContextManager.tone(frequency, 1); if (ms <= 0) cb(); else { setTimeout(function () { pxsim.AudioContextManager.stop(); pin.value = 0; pin.period = 0; pin.mode = pxsim.PinFlags.Unused; pxsim.runtime.queueDisplayUpdate(); cb(); }, ms); } } pins_1.analogPitch = analogPitch; })(pins = pxsim.pins || (pxsim.pins = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var files; (function (files) { function appendLine(filename, text) { var b = pxsim.board(); b.fileSystem.append(filename, text + "\r\n"); } files.appendLine = appendLine; function appendString(filename, text) { var b = pxsim.board(); b.fileSystem.append(filename, text); } files.appendString = appendString; function appendNumber(filename, value) { var b = pxsim.board(); b.fileSystem.append(filename, value.toString()); } files.appendNumber = appendNumber; function remove(filename) { var b = pxsim.board(); b.fileSystem.remove(filename); } files.remove = remove; })(files = pxsim.files || (pxsim.files = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { (function (DisplayMode) { DisplayMode[DisplayMode["bw"] = 0] = "bw"; DisplayMode[DisplayMode["greyscale"] = 1] = "greyscale"; })(pxsim.DisplayMode || (pxsim.DisplayMode = {})); var DisplayMode = pxsim.DisplayMode; var LedMatrixState = (function () { function LedMatrixState(runtime) { this.image = createInternalImage(5); this.brigthness = 255; this.displayMode = DisplayMode.bw; this.font = createFont(); this.animationQ = new pxsim.AnimationQueue(runtime); } return LedMatrixState; }()); pxsim.LedMatrixState = LedMatrixState; var Image = (function (_super) { __extends(Image, _super); function Image(width, data) { _super.call(this); this.width = width; this.data = data; } Image.prototype.print = function () { console.log("Image id:" + this.id + " refs:" + this.refcnt + " size:" + this.width + "x" + Image.height); }; Image.prototype.get = function (x, y) { if (x < 0 || x >= this.width || y < 0 || y >= 5) return 0; return this.data[y * this.width + x]; }; Image.prototype.set = function (x, y, v) { if (x < 0 || x >= this.width || y < 0 || y >= 5) return; this.data[y * this.width + x] = Math.max(0, Math.min(255, v)); }; Image.prototype.copyTo = function (xSrcIndex, length, target, xTargetIndex) { for (var x = 0; x < length; x++) { for (var y = 0; y < 5; y++) { var value = this.get(xSrcIndex + x, y); target.set(xTargetIndex + x, y, value); } } }; Image.prototype.shiftLeft = function (cols) { for (var x = 0; x < this.width; ++x) for (var y = 0; y < 5; ++y) this.set(x, y, x < this.width - cols ? this.get(x + cols, y) : 0); }; Image.prototype.shiftRight = function (cols) { for (var x = this.width - 1; x >= 0; --x) for (var y = 0; y < 5; ++y) this.set(x, y, x >= cols ? this.get(x - cols, y) : 0); }; Image.prototype.clear = function () { for (var i = 0; i < this.data.length; ++i) this.data[i] = 0; }; Image.height = 5; return Image; }(pxsim.RefObject)); pxsim.Image = Image; function createInternalImage(width) { var img = createImage(width); pxsim.noLeakTracking(img); return img; } pxsim.createInternalImage = createInternalImage; function createImage(width) { return new Image(width, new Array(width * 5)); } pxsim.createImage = createImage; function createImageFromBuffer(data) { return new Image(data.length / 5, data); } pxsim.createImageFromBuffer = createImageFromBuffer; function createImageFromString(text) { var font = pxsim.board().ledMatrixState.font; var w = font.width; var sprite = createInternalImage(6 * text.length - 1); var k = 0; for (var i = 0; i < text.length; i++) { var charCode = text.charCodeAt(i); var charStart = (charCode - 32) * 5; if (charStart < 0 || charStart + 5 > w) { charCode = " ".charCodeAt(0); charStart = (charCode - 32) * 5; } font.copyTo(charStart, 5, sprite, k); k = k + 5; if (i < text.length - 1) { k = k + 1; } } return sprite; } pxsim.createImageFromString = createImageFromString; function createFont() { var data = [0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x0, 0x8, 0xa, 0x4a, 0x40, 0x0, 0x0, 0xa, 0x5f, 0xea, 0x5f, 0xea, 0xe, 0xd9, 0x2e, 0xd3, 0x6e, 0x19, 0x32, 0x44, 0x89, 0x33, 0xc, 0x92, 0x4c, 0x92, 0x4d, 0x8, 0x8, 0x0, 0x0, 0x0, 0x4, 0x88, 0x8, 0x8, 0x4, 0x8, 0x4, 0x84, 0x84, 0x88, 0x0, 0xa, 0x44, 0x8a, 0x40, 0x0, 0x4, 0x8e, 0xc4, 0x80, 0x0, 0x0, 0x0, 0x4, 0x88, 0x0, 0x0, 0xe, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, 0x22, 0x44, 0x88, 0x10, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x4, 0x8c, 0x84, 0x84, 0x8e, 0x1c, 0x82, 0x4c, 0x90, 0x1e, 0x1e, 0xc2, 0x44, 0x92, 0x4c, 0x6, 0xca, 0x52, 0x5f, 0xe2, 0x1f, 0xf0, 0x1e, 0xc1, 0x3e, 0x2, 0x44, 0x8e, 0xd1, 0x2e, 0x1f, 0xe2, 0x44, 0x88, 0x10, 0xe, 0xd1, 0x2e, 0xd1, 0x2e, 0xe, 0xd1, 0x2e, 0xc4, 0x88, 0x0, 0x8, 0x0, 0x8, 0x0, 0x0, 0x4, 0x80, 0x4, 0x88, 0x2, 0x44, 0x88, 0x4, 0x82, 0x0, 0xe, 0xc0, 0xe, 0xc0, 0x8, 0x4, 0x82, 0x44, 0x88, 0xe, 0xd1, 0x26, 0xc0, 0x4, 0xe, 0xd1, 0x35, 0xb3, 0x6c, 0xc, 0x92, 0x5e, 0xd2, 0x52, 0x1c, 0x92, 0x5c, 0x92, 0x5c, 0xe, 0xd0, 0x10, 0x10, 0xe, 0x1c, 0x92, 0x52, 0x52, 0x5c, 0x1e, 0xd0, 0x1c, 0x90, 0x1e, 0x1e, 0xd0, 0x1c, 0x90, 0x10, 0xe, 0xd0, 0x13, 0x71, 0x2e, 0x12, 0x52, 0x5e, 0xd2, 0x52, 0x1c, 0x88, 0x8, 0x8, 0x1c, 0x1f, 0xe2, 0x42, 0x52, 0x4c, 0x12, 0x54, 0x98, 0x14, 0x92, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x11, 0x3b, 0x75, 0xb1, 0x31, 0x11, 0x39, 0x35, 0xb3, 0x71, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x1c, 0x92, 0x5c, 0x90, 0x10, 0xc, 0x92, 0x52, 0x4c, 0x86, 0x1c, 0x92, 0x5c, 0x92, 0x51, 0xe, 0xd0, 0xc, 0x82, 0x5c, 0x1f, 0xe4, 0x84, 0x84, 0x84, 0x12, 0x52, 0x52, 0x52, 0x4c, 0x11, 0x31, 0x31, 0x2a, 0x44, 0x11, 0x31, 0x35, 0xbb, 0x71, 0x12, 0x52, 0x4c, 0x92, 0x52, 0x11, 0x2a, 0x44, 0x84, 0x84, 0x1e, 0xc4, 0x88, 0x10, 0x1e, 0xe, 0xc8, 0x8, 0x8, 0xe, 0x10, 0x8, 0x4, 0x82, 0x41, 0xe, 0xc2, 0x42, 0x42, 0x4e, 0x4, 0x8a, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x8, 0x4, 0x80, 0x0, 0x0, 0x0, 0xe, 0xd2, 0x52, 0x4f, 0x10, 0x10, 0x1c, 0x92, 0x5c, 0x0, 0xe, 0xd0, 0x10, 0xe, 0x2, 0x42, 0x4e, 0xd2, 0x4e, 0xc, 0x92, 0x5c, 0x90, 0xe, 0x6, 0xc8, 0x1c, 0x88, 0x8, 0xe, 0xd2, 0x4e, 0xc2, 0x4c, 0x10, 0x10, 0x1c, 0x92, 0x52, 0x8, 0x0, 0x8, 0x8, 0x8, 0x2, 0x40, 0x2, 0x42, 0x4c, 0x10, 0x14, 0x98, 0x14, 0x92, 0x8, 0x8, 0x8, 0x8, 0x6, 0x0, 0x1b, 0x75, 0xb1, 0x31, 0x0, 0x1c, 0x92, 0x52, 0x52, 0x0, 0xc, 0x92, 0x52, 0x4c, 0x0, 0x1c, 0x92, 0x5c, 0x90, 0x0, 0xe, 0xd2, 0x4e, 0xc2, 0x0, 0xe, 0xd0, 0x10, 0x10, 0x0, 0x6, 0xc8, 0x4, 0x98, 0x8, 0x8, 0xe, 0xc8, 0x7, 0x0, 0x12, 0x52, 0x52, 0x4f, 0x0, 0x11, 0x31, 0x2a, 0x44, 0x0, 0x11, 0x31, 0x35, 0xbb, 0x0, 0x12, 0x4c, 0x8c, 0x92, 0x0, 0x11, 0x2a, 0x44, 0x98, 0x0, 0x1e, 0xc4, 0x88, 0x1e, 0x6, 0xc4, 0x8c, 0x84, 0x86, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0xc, 0x88, 0x18, 0x0, 0x0, 0xc, 0x83, 0x60]; var nb = data.length; var n = nb / 5; var font = createInternalImage(nb); for (var c = 0; c < n; c++) { for (var row = 0; row < 5; row++) { var char = data[c * 5 + row]; for (var col = 0; col < 5; col++) { if ((char & (1 << col)) != 0) font.set((c * 5 + 4) - col, row, 255); } } } return font; } pxsim.createFont = createFont; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var images; (function (images) { function createImage(img) { return img; } images.createImage = createImage; function createBigImage(img) { return img; } images.createBigImage = createBigImage; })(images = pxsim.images || (pxsim.images = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var ImageMethods; (function (ImageMethods) { function showImage(leds, offset, interval) { pxsim.pxtrt.nullCheck(leds); leds.copyTo(offset, 5, pxsim.board().ledMatrixState.image, 0); pxsim.runtime.queueDisplayUpdate(); pxsim.basic.pause(interval); } ImageMethods.showImage = showImage; function plotImage(leds, offset) { pxsim.pxtrt.nullCheck(leds); leds.copyTo(offset, 5, pxsim.board().ledMatrixState.image, 0); pxsim.runtime.queueDisplayUpdate(); } ImageMethods.plotImage = plotImage; function height(leds) { pxsim.pxtrt.nullCheck(leds); return pxsim.Image.height; } ImageMethods.height = height; function width(leds) { pxsim.pxtrt.nullCheck(leds); return leds.width; } ImageMethods.width = width; function plotFrame(leds, frame) { ImageMethods.plotImage(leds, frame * pxsim.Image.height); } ImageMethods.plotFrame = plotFrame; function showFrame(leds, frame, interval) { ImageMethods.showImage(leds, frame * pxsim.Image.height, interval); } ImageMethods.showFrame = showFrame; function pixel(leds, x, y) { pxsim.pxtrt.nullCheck(leds); return leds.get(x, y); } ImageMethods.pixel = pixel; function setPixel(leds, x, y, v) { pxsim.pxtrt.nullCheck(leds); leds.set(x, y, v); } ImageMethods.setPixel = setPixel; function clear(leds) { pxsim.pxtrt.nullCheck(leds); leds.clear(); } ImageMethods.clear = clear; function setPixelBrightness(i, x, y, b) { pxsim.pxtrt.nullCheck(i); i.set(x, y, b); } ImageMethods.setPixelBrightness = setPixelBrightness; function pixelBrightness(i, x, y) { pxsim.pxtrt.nullCheck(i); return i.get(x, y); } ImageMethods.pixelBrightness = pixelBrightness; function scrollImage(leds, stride, interval) { pxsim.pxtrt.nullCheck(leds); if (stride == 0) stride = 1; var cb = pxsim.getResume(); var off = stride > 0 ? 0 : leds.width - 1; var display = pxsim.board().ledMatrixState.image; pxsim.board().ledMatrixState.animationQ.enqueue({ interval: interval, frame: function () { if (off >= leds.width || off < 0) return false; if (stride > 0) { display.shiftLeft(stride); var c = Math.min(stride, leds.width - off); leds.copyTo(off, c, display, 5 - stride); } else { display.shiftRight(-stride); var c = Math.min(-stride, leds.width - off); leds.copyTo(off, c, display, 0); } off += stride; return true; }, whenDone: cb }); } ImageMethods.scrollImage = scrollImage; })(ImageMethods = pxsim.ImageMethods || (pxsim.ImageMethods = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var basic; (function (basic) { function showNumber(x, interval) { if (interval < 0) return; var leds = pxsim.createImageFromString(x.toString()); if (x < 0 || x >= 10) pxsim.ImageMethods.scrollImage(leds, 1, interval); else showLeds(leds, interval * 5); } basic.showNumber = showNumber; function showString(s, interval) { if (interval < 0) return; if (s.length == 0) { clearScreen(); basic.pause(interval * 5); } else { if (s.length == 1) showLeds(pxsim.createImageFromString(s), 0); else pxsim.ImageMethods.scrollImage(pxsim.createImageFromString(s + " "), 1, interval); } } basic.showString = showString; function showLeds(leds, delay) { showAnimation(leds, delay); } basic.showLeds = showLeds; function clearScreen() { pxsim.board().ledMatrixState.image.clear(); pxsim.runtime.queueDisplayUpdate(); } basic.clearScreen = clearScreen; function showAnimation(leds, interval) { pxsim.ImageMethods.scrollImage(leds, 5, interval); } basic.showAnimation = showAnimation; function plotLeds(leds) { pxsim.ImageMethods.plotImage(leds, 0); } basic.plotLeds = plotLeds; })(basic = pxsim.basic || (pxsim.basic = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var led; (function (led) { function plot(x, y) { pxsim.board().ledMatrixState.image.set(x, y, 255); pxsim.runtime.queueDisplayUpdate(); } led.plot = plot; function unplot(x, y) { pxsim.board().ledMatrixState.image.set(x, y, 0); pxsim.runtime.queueDisplayUpdate(); } led.unplot = unplot; function point(x, y) { return !!pxsim.board().ledMatrixState.image.get(x, y); } led.point = point; function brightness() { return pxsim.board().ledMatrixState.brigthness; } led.brightness = brightness; function setBrightness(value) { pxsim.board().ledMatrixState.brigthness = value; pxsim.runtime.queueDisplayUpdate(); } led.setBrightness = setBrightness; function stopAnimation() { pxsim.board().ledMatrixState.animationQ.cancelAll(); pxsim.board().ledMatrixState.image.clear(); } led.stopAnimation = stopAnimation; function setDisplayMode(mode) { pxsim.board().ledMatrixState.displayMode = mode; pxsim.runtime.queueDisplayUpdate(); } led.setDisplayMode = setDisplayMode; function screenshot() { var img = pxsim.createImage(5); pxsim.board().ledMatrixState.image.copyTo(0, 5, img, 0); return img; } led.screenshot = screenshot; function enable(on) { pxsim.board().ledMatrixState.disabled = !on; pxsim.runtime.queueDisplayUpdate(); } led.enable = enable; })(led = pxsim.led || (pxsim.led = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var input; (function (input) { function lightLevel() { var b = pxsim.board().lightSensorState; if (!b.usesLightLevel) { b.usesLightLevel = true; pxsim.runtime.queueDisplayUpdate(); } return b.lightLevel; } input.lightLevel = lightLevel; })(input = pxsim.input || (pxsim.input = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { /** * Error codes used in the micro:bit runtime. */ (function (PanicCode) { // PANIC Codes. These are not return codes, but are terminal conditions. // These induce a panic operation, where all code stops executing, and a panic state is // entered where the panic code is diplayed. // Out out memory error. Heap storage was requested, but is not available. PanicCode[PanicCode["MICROBIT_OOM"] = 20] = "MICROBIT_OOM"; // Corruption detected in the micro:bit heap space PanicCode[PanicCode["MICROBIT_HEAP_ERROR"] = 30] = "MICROBIT_HEAP_ERROR"; // Dereference of a NULL pointer through the ManagedType class, PanicCode[PanicCode["MICROBIT_NULL_DEREFERENCE"] = 40] = "MICROBIT_NULL_DEREFERENCE"; })(pxsim.PanicCode || (pxsim.PanicCode = {})); var PanicCode = pxsim.PanicCode; ; function panic(code) { console.log("PANIC:", code); throw new Error("PANIC " + code); } pxsim.panic = panic; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var basic; (function (basic) { basic.pause = pxsim.thread.pause; basic.forever = pxsim.thread.forever; })(basic = pxsim.basic || (pxsim.basic = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var control; (function (control) { control.inBackground = pxsim.thread.runInBackground; function reset() { pxsim.U.userError("reset not implemented in simulator yet"); } control.reset = reset; function waitMicros(micros) { // TODO } control.waitMicros = waitMicros; function deviceName() { var b = pxsim.board(); return b && b.id ? b.id.slice(0, 4) : "abcd"; } control.deviceName = deviceName; function deviceSerialNumber() { var b = pxsim.board(); return parseInt(b && b.id ? b.id.slice(1) : "42"); } control.deviceSerialNumber = deviceSerialNumber; function onEvent(id, evid, handler) { pxsim.pxtcore.registerWithDal(id, evid, handler); } control.onEvent = onEvent; function raiseEvent(id, evid, mode) { // TODO mode? pxsim.board().bus.queue(id, evid); } control.raiseEvent = raiseEvent; })(control = pxsim.control || (pxsim.control = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var pxtcore; (function (pxtcore) { function registerWithDal(id, evid, handler) { pxsim.board().bus.listen(id, evid, handler); } pxtcore.registerWithDal = registerWithDal; })(pxtcore = pxsim.pxtcore || (pxsim.pxtcore = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var input; (function (input) { function runningTime() { return pxsim.runtime.runningTime(); } input.runningTime = runningTime; function calibrate() { } input.calibrate = calibrate; })(input = pxsim.input || (pxsim.input = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var pins; (function (pins) { function onPulsed(name, pulse, body) { } pins.onPulsed = onPulsed; function pulseDuration() { return 0; } pins.pulseDuration = pulseDuration; function createBuffer(sz) { return pxsim.BufferMethods.createBuffer(sz); } pins.createBuffer = createBuffer; function pulseIn(name, value, maxDuration) { var pin = pxsim.getPin(name); if (!pin) return 0; return 5000; } pins.pulseIn = pulseIn; function spiWrite(value) { // TODO return 0; } pins.spiWrite = spiWrite; function i2cReadBuffer(address, size, repeat) { // fake reading zeros return createBuffer(size); } pins.i2cReadBuffer = i2cReadBuffer; function i2cWriteBuffer(address, buf, repeat) { // fake - noop } pins.i2cWriteBuffer = i2cWriteBuffer; // this likely shouldn't be called function getPinAddress(name) { return pxsim.getPin(name); } pins.getPinAddress = getPinAddress; function setEvents(name, event) { } pins.setEvents = setEvents; })(pins = pxsim.pins || (pxsim.pins = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var devices; (function (devices) { function tellCameraTo(action) { // TODO } devices.tellCameraTo = tellCameraTo; function tellRemoteControlTo(action) { // TODO } devices.tellRemoteControlTo = tellRemoteControlTo; function raiseAlertTo(action) { // TODO } devices.raiseAlertTo = raiseAlertTo; function onSignalStrengthChanged(action) { // TODO } devices.onSignalStrengthChanged = onSignalStrengthChanged; function signalStrength() { // TODO return 0; } devices.signalStrength = signalStrength; function onGamepadButton(button, body) { // TODO } devices.onGamepadButton = onGamepadButton; })(devices = pxsim.devices || (pxsim.devices = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var bluetooth; (function (bluetooth) { function startIOPinService() { // TODO } bluetooth.startIOPinService = startIOPinService; function startLEDService() { // TODO } bluetooth.startLEDService = startLEDService; function startTemperatureService() { // TODO } bluetooth.startTemperatureService = startTemperatureService; function startMagnetometerService() { // TODO } bluetooth.startMagnetometerService = startMagnetometerService; function startAccelerometerService() { // TODO } bluetooth.startAccelerometerService = startAccelerometerService; function startButtonService() { // TODO } bluetooth.startButtonService = startButtonService; function startUartService() { // TODO } bluetooth.startUartService = startUartService; function uartWrite(s) { // TODO } bluetooth.uartWrite = uartWrite; function uartReadUntil(del) { // TODO return ""; } bluetooth.uartReadUntil = uartReadUntil; function onBluetoothConnected(a) { // TODO } bluetooth.onBluetoothConnected = onBluetoothConnected; function onBluetoothDisconnected(a) { // TODO } bluetooth.onBluetoothDisconnected = onBluetoothDisconnected; })(bluetooth = pxsim.bluetooth || (pxsim.bluetooth = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var SpeakerState = (function () { function SpeakerState() { } return SpeakerState; }()); pxsim.SpeakerState = SpeakerState; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var music; (function (music) { function playTone(frequency, ms) { var b = pxsim.board(); b.speakerState.frequency = frequency; b.speakerState.ms = ms; pxsim.runtime.queueDisplayUpdate(); var cb = pxsim.getResume(); pxsim.AudioContextManager.tone(frequency, 1); if (ms <= 0) cb(); else { setTimeout(function () { pxsim.AudioContextManager.stop(); b.speakerState.frequency = 0; b.speakerState.ms = 0; pxsim.runtime.queueDisplayUpdate(); cb(); }, ms); } } music.playTone = playTone; })(music = pxsim.music || (pxsim.music = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { function sendBufferAsm(buffer, pin) { var b = pxsim.board(); if (b) { var np = b.neopixelState; if (np) { var buf = buffer.data; np.updateBuffer(buf, pin); pxsim.runtime.queueDisplayUpdate(); } } } pxsim.sendBufferAsm = sendBufferAsm; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var RadioDatagram = (function () { function RadioDatagram(runtime) { this.runtime = runtime; this.datagram = []; this.lastReceived = RadioDatagram.defaultPacket(); } RadioDatagram.prototype.queue = function (packet) { if (this.datagram.length < 4) { this.datagram.push(packet); } pxsim.runtime.board.bus.queue(29 /* MICROBIT_ID_RADIO */, 1 /* MICROBIT_RADIO_EVT_DATAGRAM */); }; RadioDatagram.prototype.send = function (payload) { pxsim.Runtime.postMessage({ type: "radiopacket", rssi: 0, serial: pxsim.board().radioState.bus.transmitSerialNumber ? pxsim.board().radioState.bus.serial : 0, time: 0, payload: payload }); }; RadioDatagram.prototype.recv = function () { var r = this.datagram.shift(); if (!r) r = RadioDatagram.defaultPacket(); return this.lastReceived = r; }; RadioDatagram.defaultPacket = function () { return { rssi: -1, serial: 0, time: 0, payload: { type: -1 } }; }; return RadioDatagram; }()); pxsim.RadioDatagram = RadioDatagram; var RadioBus = (function () { function RadioBus(runtime) { this.runtime = runtime; // uint8_t radioDefaultGroup = MICROBIT_RADIO_DEFAULT_GROUP; this.groupId = 0; // todo this.power = 0; this.serial = 0; this.transmitSerialNumber = false; this.datagram = new RadioDatagram(runtime); this.serial = Math.floor(Math.random() * Math.pow(2, 32)) - Math.pow(2, 31); // 32 bit signed integer } RadioBus.prototype.setGroup = function (id) { this.groupId = id & 0xff; // byte only }; RadioBus.prototype.setTransmitPower = function (power) { this.power = Math.max(0, Math.min(7, power)); }; RadioBus.prototype.setTransmitSerialNumber = function (sn) { this.transmitSerialNumber = !!sn; }; RadioBus.prototype.broadcast = function (msg) { pxsim.Runtime.postMessage({ type: "eventbus", id: 2000 /* MES_BROADCAST_GENERAL_ID */, eventid: msg, power: this.power, group: this.groupId }); }; return RadioBus; }()); pxsim.RadioBus = RadioBus; var RadioState = (function () { function RadioState(runtime) { this.bus = new RadioBus(runtime); } RadioState.prototype.recievePacket = function (packet) { this.bus.datagram.queue(packet); }; return RadioState; }()); pxsim.RadioState = RadioState; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var radio; (function (radio) { var PacketPayloadType; (function (PacketPayloadType) { PacketPayloadType[PacketPayloadType["NUMBER"] = 0] = "NUMBER"; PacketPayloadType[PacketPayloadType["VALUE"] = 1] = "VALUE"; PacketPayloadType[PacketPayloadType["STRING"] = 2] = "STRING"; })(PacketPayloadType || (PacketPayloadType = {})); function broadcastMessage(msg) { pxsim.board().radioState.bus.broadcast(msg); } radio.broadcastMessage = broadcastMessage; function onBroadcastMessageReceived(msg, handler) { pxsim.pxtcore.registerWithDal(2000 /* MES_BROADCAST_GENERAL_ID */, msg, handler); } radio.onBroadcastMessageReceived = onBroadcastMessageReceived; function setGroup(id) { pxsim.board().radioState.bus.setGroup(id); } radio.setGroup = setGroup; function setTransmitPower(power) { pxsim.board().radioState.bus.setTransmitPower(power); } radio.setTransmitPower = setTransmitPower; function setTransmitSerialNumber(transmit) { pxsim.board().radioState.bus.setTransmitSerialNumber(transmit); } radio.setTransmitSerialNumber = setTransmitSerialNumber; function sendNumber(value) { pxsim.board().radioState.bus.datagram.send({ type: PacketPayloadType.NUMBER, numberData: value }); } radio.sendNumber = sendNumber; function sendString(msg) { msg = msg.substr(0, 19); pxsim.board().radioState.bus.datagram.send({ type: PacketPayloadType.STRING, stringData: msg }); } radio.sendString = sendString; function writeValueToSerial() { var b = pxsim.board(); writePacketToSerial(b, b.radioState.bus.datagram.recv()); } radio.writeValueToSerial = writeValueToSerial; function writeReceivedPacketToSerial() { var b = pxsim.board(); writePacketToSerial(b, b.radioState.bus.datagram.lastReceived); } radio.writeReceivedPacketToSerial = writeReceivedPacketToSerial; function sendValue(name, value) { name = name.substr(0, 12); var msg = []; msg.push(); pxsim.board().radioState.bus.datagram.send({ type: PacketPayloadType.VALUE, stringData: name, numberData: value }); } radio.sendValue = sendValue; function receiveNumber() { var packet = pxsim.board().radioState.bus.datagram.recv(); return receivedNumber(); } radio.receiveNumber = receiveNumber; function receiveString() { var packet = pxsim.board().radioState.bus.datagram.recv(); return receivedString(); } radio.receiveString = receiveString; function receivedSignalStrength() { return pxsim.board().radioState.bus.datagram.lastReceived.rssi; } radio.receivedSignalStrength = receivedSignalStrength; function onDataReceived(handler) { pxsim.pxtcore.registerWithDal(29 /* MICROBIT_ID_RADIO */, 1 /* MICROBIT_RADIO_EVT_DATAGRAM */, handler); radio.receiveNumber(); } radio.onDataReceived = onDataReceived; function receivedNumber() { return pxsim.board().radioState.bus.datagram.lastReceived.payload.numberData || 0; } radio.receivedNumber = receivedNumber; function receivedSerial() { return pxsim.board().radioState.bus.datagram.lastReceived.serial; } radio.receivedSerial = receivedSerial; function receivedString() { return pxsim.board().radioState.bus.datagram.lastReceived.payload.stringData || ""; } radio.receivedString = receivedString; function receivedTime() { return pxsim.board().radioState.bus.datagram.lastReceived.time; } radio.receivedTime = receivedTime; function writePacketToSerial(b, p) { switch (p.payload.type) { case PacketPayloadType.NUMBER: b.writeSerial("{\"t\":" + p.time + ",\"s\":" + p.serial + ",\"v\":" + p.payload.numberData + "}\r\n"); break; case PacketPayloadType.VALUE: b.writeSerial("{\"t\":" + p.time + ",\"s\":" + p.serial + ",\"n\":\"" + p.payload.stringData + "\",\"v\":" + p.payload.numberData + "}\r\n"); break; case PacketPayloadType.STRING: b.writeSerial("{\"t\":" + p.time + ",\"s\":" + p.serial + ",\"n\":\"" + p.payload.stringData + "\"}\r\n"); break; default: } } })(radio = pxsim.radio || (pxsim.radio = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var basic; (function (basic) { function setLedColor(c) { pxsim.board().rgbLedState = c; pxsim.runtime.queueDisplayUpdate(); } basic.setLedColor = setLedColor; })(basic = pxsim.basic || (pxsim.basic = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var SerialState = (function () { function SerialState() { this.serialIn = []; this.serialOutBuffer = ""; } SerialState.prototype.recieveData = function (data) { this.serialIn.push(); }; SerialState.prototype.readSerial = function () { var v = this.serialIn.shift() || ""; return v; }; SerialState.prototype.writeSerial = function (s) { for (var i = 0; i < s.length; ++i) { var c = s[i]; this.serialOutBuffer += c; if (c == "\n") { pxsim.Runtime.postMessage({ type: "serial", data: this.serialOutBuffer, id: pxsim.runtime.id }); this.serialOutBuffer = ""; break; } } }; return SerialState; }()); pxsim.SerialState = SerialState; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var serial; (function (serial) { function writeString(s) { pxsim.board().writeSerial(s); } serial.writeString = writeString; function readUntil(del) { return readString(); } serial.readUntil = readUntil; function readString() { return pxsim.board().serialState.readSerial(); } serial.readString = readString; function onDataReceived(delimiters, handler) { var b = pxsim.board(); b.bus.listen(32 /* MICROBIT_ID_SERIAL */, 1 /* MICROBIT_SERIAL_EVT_DELIM_MATCH */, handler); } serial.onDataReceived = onDataReceived; function redirect(tx, rx, rate) { // TODO? } serial.redirect = redirect; })(serial = pxsim.serial || (pxsim.serial = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var motors; (function (motors) { function motorPower(power) { // TODO } motors.motorPower = motorPower; function motorCommand(command) { } motors.motorCommand = motorCommand; function dualMotorPower(motor, percent) { } motors.dualMotorPower = dualMotorPower; })(motors = pxsim.motors || (pxsim.motors = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var ThermometerState = (function () { function ThermometerState() { this.usesTemperature = false; this.temperature = 21; } return ThermometerState; }()); pxsim.ThermometerState = ThermometerState; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var input; (function (input) { function temperature() { var b = pxsim.board(); if (!b.thermometerState.usesTemperature) { b.thermometerState.usesTemperature = true; pxsim.runtime.queueDisplayUpdate(); } return b.thermometerState.temperature; } input.temperature = temperature; })(input = pxsim.input || (pxsim.input = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var visuals; (function (visuals) { visuals.mkBoardView = function (opts) { return new visuals.MicrobitBoardSvg({ runtime: pxsim.runtime, theme: visuals.randomTheme(), disableTilt: false, wireframe: opts.wireframe, }); }; })(visuals = pxsim.visuals || (pxsim.visuals = {})); })(pxsim || (pxsim = {})); /// /// var pxsim; (function (pxsim) { var visuals; (function (visuals) { function mkLedMatrixSvg(xy, rows, cols) { var result = { el: null, y: 0, x: 0, w: 0, h: 0, leds: [], ledsOuter: [], background: null }; result.el = pxsim.svg.elt("g"); var width = cols * visuals.PIN_DIST; var height = rows * visuals.PIN_DIST; var ledRad = Math.round(visuals.PIN_DIST * .35); var spacing = visuals.PIN_DIST; var padding = (spacing - 2 * ledRad) / 2.0; var x = xy[0], y = xy[1]; var left = x - (ledRad + padding); var top = y - (ledRad + padding); result.x = left; result.y = top; result.w = width; result.h = height; result.background = pxsim.svg.child(result.el, "rect", { class: "sim-display", x: left, y: top, width: width, height: height }); // ledsOuter result.leds = []; result.ledsOuter = []; var hoverRad = ledRad * 1.2; for (var i = 0; i < rows; ++i) { var y_1 = top + ledRad + i * spacing + padding; for (var j = 0; j < cols; ++j) { var x_1 = left + ledRad + j * spacing + padding; result.ledsOuter.push(pxsim.svg.child(result.el, "circle", { class: "sim-led-back", cx: x_1, cy: y_1, r: ledRad })); result.leds.push(pxsim.svg.child(result.el, "circle", { class: "sim-led", cx: x_1, cy: y_1, r: hoverRad, title: "(" + j + "," + i + ")" })); } } //default theme pxsim.svg.fill(result.background, visuals.defaultLedMatrixTheme.background); pxsim.svg.fills(result.leds, visuals.defaultLedMatrixTheme.ledOn); pxsim.svg.fills(result.ledsOuter, visuals.defaultLedMatrixTheme.ledOff); //turn off LEDs result.leds.forEach(function (l) { return l.style.opacity = 0 + ""; }); return result; } visuals.mkLedMatrixSvg = mkLedMatrixSvg; visuals.defaultLedMatrixTheme = { background: "#000", ledOn: "#ff5f5f", ledOff: "#DDD", }; visuals.LED_MATRIX_STYLE = "\n .sim-led-back:hover {\n stroke:#a0a0a0;\n stroke-width:3px;\n }\n .sim-led:hover {\n stroke:#ff7f7f;\n stroke-width:3px;\n }\n "; var LedMatrixView = (function () { function LedMatrixView() { this.DRAW_SIZE = 8; this.ACTIVE_SIZE = 5; this.style = visuals.LED_MATRIX_STYLE; } LedMatrixView.prototype.init = function (bus, state) { this.bus = bus; this.state = state; this.theme = visuals.defaultLedMatrixTheme; this.defs = []; this.element = this.buildDom(); }; LedMatrixView.prototype.moveToCoord = function (xy) { visuals.translateEl(this.element, xy); }; LedMatrixView.prototype.updateTheme = function () { pxsim.svg.fill(this.background, this.theme.background); pxsim.svg.fills(this.leds, this.theme.ledOn); pxsim.svg.fills(this.ledsOuter, this.theme.ledOff); }; LedMatrixView.prototype.updateState = function () { var _this = this; if (this.state.disabled) { this.leds.forEach(function (led, i) { var sel = led; sel.style.opacity = 0 + ""; }); return; } var bw = this.state.displayMode == pxsim.DisplayMode.bw; var img = this.state.image; this.leds.forEach(function (led, i) { var sel = led; var dx = i % _this.DRAW_SIZE; var dy = (i - dx) / _this.DRAW_SIZE; if (dx < _this.ACTIVE_SIZE && dy < _this.ACTIVE_SIZE) { var j = dx + dy * _this.ACTIVE_SIZE; sel.style.opacity = ((bw ? img.data[j] > 0 ? 255 : 0 : img.data[j]) / 255.0) + ""; } else { sel.style.opacity = 0 + ""; } }); }; LedMatrixView.prototype.buildDom = function () { var res = mkLedMatrixSvg([0, 0], this.DRAW_SIZE, this.DRAW_SIZE); var display = res.el; this.background = res.background; this.leds = res.leds; this.ledsOuter = res.ledsOuter; return display; }; return LedMatrixView; }()); visuals.LedMatrixView = LedMatrixView; })(visuals = pxsim.visuals || (pxsim.visuals = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var visuals; (function (visuals) { var MB_STYLE = "\n svg.sim {\n margin-bottom:1em;\n }\n svg.sim.grayscale {\n -moz-filter: grayscale(1);\n -webkit-filter: grayscale(1);\n filter: grayscale(1);\n }\n .sim-button {\n pointer-events: none;\n }\n\n .sim-button-outer:hover {\n stroke:grey;\n stroke-width: 3px;\n }\n .sim-button-nut {\n fill:#704A4A;\n pointer-events:none;\n }\n .sim-button-nut:hover {\n stroke:1px solid #704A4A;\n }\n .sim-pin:hover {\n stroke:#D4AF37;\n stroke-width:2px;\n }\n\n .sim-pin-touch.touched:hover {\n stroke:darkorange;\n }\n\n .sim-led-back:hover {\n stroke:#fff;\n stroke-width:3px;\n }\n .sim-led:hover {\n stroke:#ff7f7f;\n stroke-width:3px;\n }\n\n .sim-systemled {\n fill:#333;\n stroke:#555;\n stroke-width: 1px;\n }\n\n .sim-light-level-button {\n stroke:#ccc;\n stroke-width: 2px;\n }\n\n .sim-antenna {\n fill-opacity:0.0;\n stroke:#555;\n stroke-width: 4px;\n }\n\n .sim-text {\n font-family:\"Lucida Console\", Monaco, monospace;\n font-size:14px;\n fill:#fff;\n pointer-events: none; user-select: none;\n }\n .sim-text.inverted {\n fill:#000;\n }\n\n .sim-text-pin {\n font-family:\"Lucida Console\", Monaco, monospace;\n font-size:20px;\n fill:#fff;\n pointer-events: none;\n }\n\n .sim-thermometer {\n stroke:#aaa;\n stroke-width: 2px;\n }\n\n #rgbledcircle:hover {\n r:8px;\n }\n\n /* animations */\n .sim-theme-glow {\n animation-name: sim-theme-glow-animation;\n animation-timing-function: ease-in-out;\n animation-direction: alternate;\n animation-iteration-count: infinite;\n animation-duration: 1.25s;\n }\n @keyframes sim-theme-glow-animation {\n from { opacity: 1; }\n to { opacity: 0.75; }\n }\n\n .sim-flash {\n animation-name: sim-flash-animation;\n animation-duration: 0.1s;\n }\n\n @keyframes sim-flash-animation {\n from { fill: yellow; }\n to { fill: default; }\n }\n\n .sim-flash-stroke {\n animation-name: sim-flash-stroke-animation;\n animation-duration: 0.4s;\n animation-timing-function: ease-in;\n }\n\n @keyframes sim-flash-stroke-animation {\n from { stroke: yellow; }\n to { stroke: default; }\n }\n\n /* wireframe */\n .sim-wireframe * {\n fill: none;\n stroke: black;\n }\n .sim-wireframe .sim-display,\n .sim-wireframe .sim-led,\n .sim-wireframe .sim-led-back,\n .sim-wireframe .sim-head,\n .sim-wireframe .sim-theme,\n .sim-wireframe .sim-button-group,\n .sim-wireframe .sim-button-label,\n .sim-wireframe .sim-button,\n .sim-wireframe .sim-text-pin\n {\n visibility: hidden;\n }\n .sim-wireframe .sim-label\n {\n stroke: none;\n fill: #777;\n }\n .sim-wireframe .sim-board {\n stroke-width: 2px;\n }\n "; var BOARD_SVG = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\t\n\t\t\n\t\n\n\n\n\n\n\n\n\n"; var pinNames = [ "BTN_A", "BTN_B", "EDGE_P0", "EDGE_P1", "EDGE_P2", "EDGE_P3", "EDGE_GND", "EDGE_VCC", "C_GND1", "C_GND2", "C_GND3", "C_GND4", "C_VCC1", "C_VCC2", "C_P0", "C_P2", "C_P4", "C_P6", "C_P8", "C_P10", "C_P12", "C_P14", "C_P16", "C_P18", "C_P1", "C_P3", "C_P5", "C_P7", "C_P9", "C_P11", "C_P13", "C_P15", "C_P17", "C_P19", "M_GND1", "M_GND2", "M_OUT1", "M_OUT2", "M_VM", "G_A0_GND", "G_A0_VCC", "G_A0_SDA", "G_A0_SCL", "G_A1_RX", "G_A1_TX", "G_A1_VCC", "G_A1_GND" ]; var pinTitles = [ "Button A", "Button B", "P0", "P1, ANALOG IN", "P2, ANALOG IN", "P3", "GND", "+3v3", "GND", "GND", "GND", "GND", "+3v3", "+3v3", "C0", "C2", "C4", "C6", "C8", "C10", "C12", "C14", "C16", "C18", "C1", "C3", "C5", "C7", "C9", "C11", "C13", "C15", "C17", "C19", "GND", "GND", "MOTOR B", "MOTOR A", "MOTOR VM", "GND", "+3v3", "C18, I2C - SDA", "C19, I2C - SCL", "C16, Serial - RX", "C17, Serial - TX", "+3v3", "GND" ]; var MB_WIDTH = 530; var MB_HEIGHT = 530; visuals.themes = ["#3ADCFE"].map(function (accent) { return { accent: accent, pin: "#EFDA48", pinTouched: "#FFA500", pinActive: "#FF5500", ledOn: "#ff5555", ledOff: "#e0e1e2", buttonOuter: "#979797", buttonUps: ["#186A8C", "#D82E50"], buttonDown: "#FFA500", virtualButtonDown: "#FFA500", virtualButtonOuter: "#333", virtualButtonUp: "#fff", lightLevelOn: "yellow", lightLevelOff: "#555" }; }); function randomTheme() { return visuals.themes[Math.floor(Math.random() * visuals.themes.length)]; } visuals.randomTheme = randomTheme; var MicrobitBoardSvg = (function () { function MicrobitBoardSvg(props) { var _this = this; this.props = props; this.pinNmToCoord = { "EXT_PWR": [ 92.30997467041016, -42.92474937438965 ], "SPKR": [ 106.44635391235352, -16.370698928833008 ], "BTN_A": [ 93.8138427734375, 56.631452560424805 ], "BTN_B": [ 204.92835235595703, 56.631452560424805 ], // rings "EDGE_P0": [ 56.002254486083984, 95.43130111694336 ], "EDGE_P1": [ 103.00893783569336, 175.82388305664062 ], "EDGE_P2": [ 195.90512084960938, 175.3082733154297 ], "EDGE_P3": [ 241.79466247558594, 95.3883285522461 ], "EDGE_GND": [ 103.00893783569336, 14.86682915687561 ], "EDGE_VCC": [ 195.64733123779297, 14.86682915687561 ], "C_GND1": [ 113.1493148803711, 159.83989715576172 ], "C_GND2": [ 150.27342987060547, 159.83989715576172 ], "C_GND3": [ 150.27342987060547, 153.5666275024414 ], "C_GND4": [ 187.39752960205078, 153.5666275024414 ], "C_VCC1": [ 187.39752960205078, 159.83989715576172 ], "C_VCC2": [ 113.1922836303711, 153.5666275024414 ], "C_P0": [ 119.33667373657227, 159.83989715576172 ], "C_P2": [ 125.52401733398438, 159.83989715576172 ], "C_P4": [ 131.71136474609375, 159.83989715576172 ], "C_P6": [ 137.89871978759766, 159.83989715576172 ], "C_P8": [ 144.08607482910156, 159.83989715576172 ], "C_P10": [ 156.46077728271484, 159.83989715576172 ], "C_P12": [ 162.64812469482422, 159.83989715576172 ], "C_P14": [ 168.83545684814453, 159.83989715576172 ], "C_P16": [ 175.02281951904297, 159.83989715576172 ], "C_P20": [ 181.2101821899414, 159.83989715576172 ], "C_P1": [ 119.379638671875, 153.5666275024414 ], "C_P3": [ 125.56698226928711, 153.5666275024414 ], "C_P5": [ 131.71136474609375, 153.5666275024414 ], "C_P7": [ 137.89871978759766, 153.5666275024414 ], "C_P9": [ 144.08607482910156, 153.5666275024414 ], "C_P11": [ 156.46077728271484, 153.5666275024414 ], "C_P13": [ 162.64812469482422, 153.5666275024414 ], "C_P15": [ 168.83545684814453, 153.5666275024414 ], "C_P21": [ 175.02281951904297, 153.5666275024414 ], "C_P19": [ 181.2101821899414, 153.5666275024414 ], "M_GND1": [ 137.89871978759766, 141.70752716064453 ], "M_GND2": [ 156.46077728271484, 141.70752716064453 ], "M_OUT1": [ 144.08607482910156, 141.70752716064453 ], "M_OUT2": [ 150.27342987060547, 141.70752716064453 ], "M_VM": [ 162.64812469482422, 141.70752716064453 ], "G_A0_GND": [ 82.47036743164062, 72.35763549804688 ], "G_A0_VCC": [ 78.34546279907227, 76.3106689453125 ], "G_A0_SDA": [ 74.65023803710938, 80.00588989257812 ], "G_A0_SCL": [ 70.43940734863281, 84.21672821044922 ], "G_A1_RX": [ 216.52963256835938, 71.4982795715332 ], "G_A1_TX": [ 220.65453338623047, 75.53724670410156 ], "G_A1_VCC": [ 224.34976959228516, 79.23247528076172 ], "G_A1_GND": [ 228.56060028076172, 83.44330978393555 ] }; this.lastFlashTime = 0; this.lastAntennaFlash = 0; this.buildDom(); if (props && props.wireframe) pxsim.svg.addClass(this.element, "sim-wireframe"); if (props && props.theme) this.updateTheme(); if (props && props.runtime) { this.board = this.props.runtime.board; this.board.updateSubscribers.push(function () { return _this.updateState(); }); this.updateState(); this.attachEvents(); } } MicrobitBoardSvg.prototype.getView = function () { return { el: this.element, y: 0, x: 0, w: MB_WIDTH, h: MB_HEIGHT }; }; MicrobitBoardSvg.prototype.getCoord = function (pinNm) { return this.pinNmToCoord[pinNm]; }; MicrobitBoardSvg.prototype.highlightPin = function (pinNm) { //TODO: for instructions }; MicrobitBoardSvg.prototype.getPinDist = function () { return 10; }; MicrobitBoardSvg.prototype.recordPinCoords = function () { var _this = this; pinNames.forEach(function (nm, i) { var p = _this.pins[i]; var r = p.getBoundingClientRect(); _this.pinNmToCoord[nm] = [r.left + r.width / 2, r.top + r.height / 2]; }); console.log(JSON.stringify(this.pinNmToCoord, null, 2)); }; MicrobitBoardSvg.prototype.updateTheme = function () { var theme = this.props.theme; pxsim.svg.fills(this.leds, theme.ledOn); pxsim.svg.fills(this.ledsOuter, theme.ledOff); pxsim.svg.fills(this.buttonsOuter.slice(0, 2), theme.buttonOuter); pxsim.svg.fill(this.buttons[0], theme.buttonUps[0]); pxsim.svg.fill(this.buttons[1], theme.buttonUps[1]); pxsim.svg.fill(this.buttonsOuter[2], theme.virtualButtonOuter); pxsim.svg.fill(this.buttons[2], theme.virtualButtonUp); this.pinGradients.forEach(function (lg) { return pxsim.svg.setGradientColors(lg, theme.pin, theme.pinActive); }); pxsim.svg.setGradientColors(this.lightLevelGradient, theme.lightLevelOn, theme.lightLevelOff); pxsim.svg.setGradientColors(this.thermometerGradient, theme.ledOff, theme.ledOn); }; MicrobitBoardSvg.prototype.updateState = function () { var _this = this; var state = this.board; if (!state) return; var theme = this.props.theme; var bpState = state.buttonPairState; var buttons = [bpState.aBtn, bpState.bBtn, bpState.abBtn]; buttons.forEach(function (btn, index) { pxsim.svg.fill(_this.buttons[index], btn.pressed ? (btn.virtual ? theme.virtualButtonDown : theme.buttonDown) : (btn.virtual ? theme.virtualButtonUp : theme.buttonUps[index])); }); if (state.ledMatrixState.disabled) { this.leds.forEach(function (led, i) { var sel = led; sel.style.opacity = "0"; }); } else { var bw_1 = state.ledMatrixState.displayMode == pxsim.DisplayMode.bw; var img_1 = state.ledMatrixState.image; this.leds.forEach(function (led, i) { var sel = led; sel.style.opacity = ((bw_1 ? img_1.data[i] > 0 ? 255 : 0 : img_1.data[i]) / 255.0) + ""; }); } this.updatePins(); this.updateTilt(); this.updateHeading(); this.updateLightLevel(); this.updateTemperature(); this.updateButtonAB(); this.updateGestures(); this.updateRgbLed(); this.updateSpeaker(); if (!pxsim.runtime || pxsim.runtime.dead) pxsim.svg.addClass(this.element, "grayscale"); else pxsim.svg.removeClass(this.element, "grayscale"); }; MicrobitBoardSvg.prototype.updateRgbLed = function () { var state = this.board; if (state.rgbLedState) { if (!this.rgbLed) this.rgbLed = this.element.getElementById("rgbledcircle"); var c = state.rgbLedState; var b = c & 0xFF; var g = (c >> 8) & 0xFF; var r = (c >> 16) & 0xFF; var w = (c >> 24) & 0xFF; var ch = "rgba(" + r + ", " + g + ", " + b + ", 1)"; pxsim.svg.fill(this.rgbLed, ch); } else if (this.rgbLed) { pxsim.svg.fill(this.rgbLed, 'white'); } }; MicrobitBoardSvg.prototype.updateSpeaker = function () { var state = this.board; if (state.speakerState.frequency) { } else { } }; MicrobitBoardSvg.prototype.updateGestures = function () { var _this = this; var state = this.board; if (state.accelerometerState.useShake && !this.shakeButton) { var shake = this.mkBtn(26, MB_HEIGHT - 45); this.shakeButton = shake.inner; pxsim.svg.fill(this.shakeButton, this.props.theme.virtualButtonUp); pxsim.svg.buttonEvents(shake.outer, function (ev) { }, function (ev) { pxsim.svg.fill(_this.shakeButton, _this.props.theme.virtualButtonDown); }, function (ev) { pxsim.svg.fill(_this.shakeButton, _this.props.theme.virtualButtonUp); _this.board.bus.queue(27 /* MICROBIT_ID_GESTURE */, 11); // GESTURE_SHAKE }); var shakeText = pxsim.svg.child(shake.outer, "text", { x: 15, y: MB_HEIGHT - 10, class: "sim-text inverted" }); shakeText.textContent = "SHAKE"; } }; MicrobitBoardSvg.prototype.updateButtonAB = function () { var state = this.board; if (state.buttonPairState.usesButtonAB && this.buttons[2].style.visibility != "visible") { this.buttonsOuter[2].style.visibility = "visible"; this.buttons[2].style.visibility = "visible"; this.updateTheme(); } }; MicrobitBoardSvg.prototype.updatePin = function (pin, index) { if (!pin) return; var text = this.pinTexts[index]; var v = ""; if (pin.mode & pxsim.PinFlags.Analog) { v = Math.floor(100 - (pin.value || 0) / 1023 * 100) + "%"; if (text) text.textContent = (pin.period ? "~" : "") + (pin.value || 0) + ""; } else if (pin.mode & pxsim.PinFlags.Digital) { v = pin.value > 0 ? "0%" : "100%"; if (text) text.textContent = pin.value > 0 ? "1" : "0"; } else if (pin.mode & pxsim.PinFlags.Touch) { v = pin.touched ? "0%" : "100%"; if (text) text.textContent = ""; } else { v = "100%"; if (text) text.textContent = ""; } if (v) pxsim.svg.setGradientValue(this.pinGradients[index], v); }; MicrobitBoardSvg.prototype.updateTemperature = function () { var _this = this; var state = this.board; if (!state || !state.thermometerState.usesTemperature) return; var tmin = -5; var tmax = 50; if (!this.thermometer) { var gid = "gradient-thermometer"; this.thermometerGradient = pxsim.svg.linearGradient(this.defs, gid); var ty_1 = MB_HEIGHT - 180; this.thermometer = pxsim.svg.child(this.g, "rect", { class: "sim-thermometer", x: 28, y: ty_1, width: 10, height: 80, rx: 5, ry: 5, fill: "url(#" + gid + ")" }); this.thermometerText = pxsim.svg.child(this.g, "text", { class: 'sim-text', x: 48, y: ty_1 + 78 }); this.updateTheme(); var pt_1 = this.element.createSVGPoint(); pxsim.svg.buttonEvents(this.thermometer, function (ev) { var cur = pxsim.svg.cursorPoint(pt_1, _this.element, ev); var t = Math.max(0, Math.min(1, (cur.y - ty_1 - 5) / 70)); state.thermometerState.temperature = Math.floor(tmax - t * (tmax - tmin)); _this.updateTemperature(); }, function (ev) { }, function (ev) { }); } var t = Math.max(tmin, Math.min(tmax, state.thermometerState.temperature)); var per = Math.floor((state.thermometerState.temperature - tmin) / (tmax - tmin) * 100); pxsim.svg.setGradientValue(this.thermometerGradient, 100 - per + "%"); this.thermometerText.textContent = t + "°C"; }; MicrobitBoardSvg.prototype.updateHeading = function () { var xc = 258; var yc = 75; var state = this.board; if (!state || !state.compassState.usesHeading) return; /* if (!this.headInitialized) { let p = this.head.firstChild.nextSibling as SVGPathElement; p.setAttribute("d", "m269.9,50.134647l0,0l-39.5,0l0,0c-14.1,0.1 -24.6,10.7 -24.6,24.8c0,13.9 10.4,24.4 24.3,24.7l0,0l39.6,0c14.2,0 40.36034,-22.97069 40.36034,-24.85394c0,-1.88326 -26.06034,-24.54606 -40.16034,-24.64606m-0.2,39l0,0l-39.3,0c-7.7,-0.1 -14,-6.4 -14,-14.2c0,-7.8 6.4,-14.2 14.2,-14.2l39.1,0c7.8,0 14.2,6.4 14.2,14.2c0,7.9 -6.4,14.2 -14.2,14.2l0,0l0,0z"); this.updateTheme(); let pt = this.element.createSVGPoint(); svg.buttonEvents( this.head, (ev: MouseEvent) => { let cur = svg.cursorPoint(pt, this.element, ev); state.compassState.heading = Math.floor(Math.atan2(cur.y - yc, cur.x - xc) * 180 / Math.PI + 90); if (state.compassState.heading < 0) state.compassState.heading += 360; this.updateHeading(); }); this.headInitialized = true; } let txt = state.compassState.heading.toString() + "°"; if (txt != this.headText.textContent) { svg.rotateElement(this.head, xc, yc, state.compassState.heading + 180); this.headText.textContent = txt; } */ }; MicrobitBoardSvg.prototype.flashSystemLed = function () { if (!this.systemLed) this.systemLed = pxsim.svg.child(this.g, "circle", { class: "sim-systemled", cx: 160.8, cy: 150.9, r: 4 }); var now = Date.now(); if (now - this.lastFlashTime > 150) { this.lastFlashTime = now; pxsim.svg.animate(this.systemLed, "sim-flash"); } }; MicrobitBoardSvg.prototype.flashAntenna = function () { if (!this.antenna) { var ax = 480; var dax = 18; var ayt = 10; var ayb = 40; this.antenna = pxsim.svg.child(this.g, "polyline", { class: "sim-antenna", points: ax + "," + ayb + " " + ax + "," + ayt + " " + (ax += dax) + "," + ayt + " " + ax + "," + ayb + " " + (ax += dax) + "," + ayb + " " + ax + "," + ayt + " " + (ax += dax) + "," + ayt + " " + ax + "," + ayb + " " + (ax += dax) + "," + ayb + " " + ax + "," + ayt + " " + (ax += dax) + "," + ayt }); } var now = Date.now(); if (now - this.lastAntennaFlash > 200) { this.lastAntennaFlash = now; pxsim.svg.animate(this.antenna, 'sim-flash-stroke'); } }; MicrobitBoardSvg.prototype.updatePins = function () { var _this = this; var state = this.board; if (!state) return; state.edgeConnectorState.pins.forEach(function (pin, i) { return _this.updatePin(pin, i); }); }; MicrobitBoardSvg.prototype.updateLightLevel = function () { var _this = this; var state = this.board; if (!state || !state.lightSensorState.usesLightLevel) return; if (!this.lightLevelButton) { var gid = "gradient-light-level"; this.lightLevelGradient = pxsim.svg.linearGradient(this.defs, gid); var cx = 30; var cy_1 = 45; var r_1 = 20; this.lightLevelButton = pxsim.svg.child(this.g, "circle", { cx: cx + "px", cy: cy_1 + "px", r: r_1 + "px", class: 'sim-light-level-button', fill: "url(#" + gid + ")" }); var pt_2 = this.element.createSVGPoint(); pxsim.svg.buttonEvents(this.lightLevelButton, function (ev) { var pos = pxsim.svg.cursorPoint(pt_2, _this.element, ev); var rs = r_1 / 2; var level = Math.max(0, Math.min(255, Math.floor((pos.y - (cy_1 - rs)) / (2 * rs) * 255))); if (level != _this.board.lightSensorState.lightLevel) { _this.board.lightSensorState.lightLevel = level; _this.applyLightLevel(); } }, function (ev) { }, function (ev) { }); this.lightLevelText = pxsim.svg.child(this.g, "text", { x: cx - r_1 - 7, y: cy_1 + r_1 + 8, text: '', class: 'sim-text inverted' }); this.updateTheme(); } pxsim.svg.setGradientValue(this.lightLevelGradient, Math.min(100, Math.max(0, Math.floor(state.lightSensorState.lightLevel * 100 / 255))) + '%'); this.lightLevelText.textContent = state.lightSensorState.lightLevel.toString(); }; MicrobitBoardSvg.prototype.applyLightLevel = function () { var lv = this.board.lightSensorState.lightLevel; pxsim.svg.setGradientValue(this.lightLevelGradient, Math.min(100, Math.max(0, Math.floor(lv * 100 / 255))) + '%'); this.lightLevelText.textContent = lv.toString(); }; MicrobitBoardSvg.prototype.updateTilt = function () { if (this.props.disableTilt) return; var state = this.board; if (!state || !state.accelerometerState.accelerometer.isActive) return; var x = state.accelerometerState.accelerometer.getX(); var y = -state.accelerometerState.accelerometer.getY(); var af = 8 / 1023; var s = 1 - Math.min(0.1, Math.pow(Math.max(Math.abs(x), Math.abs(y)) / 1023, 2) / 35); this.element.style.transform = "perspective(30em) rotateX(" + y * af + "deg) rotateY(" + x * af + "deg) scale(" + s + ", " + s + ")"; this.element.style.perspectiveOrigin = "50% 50% 50%"; this.element.style.perspective = "30em"; }; MicrobitBoardSvg.prototype.buildDom = function () { var _this = this; this.element = new DOMParser().parseFromString(BOARD_SVG, "image/svg+xml").querySelector("svg"); pxsim.svg.hydrate(this.element, { "version": "1.0", "viewBox": "0 0 " + MB_WIDTH + " " + MB_HEIGHT, "class": "sim", "x": "0px", "y": "0px", "width": MB_WIDTH + "px", "height": MB_HEIGHT + "px", }); this.style = pxsim.svg.child(this.element, "style", {}); this.style.textContent = MB_STYLE; this.defs = pxsim.svg.child(this.element, "defs", {}); this.g = pxsim.svg.elt("g"); this.element.appendChild(this.g); // filters var glow = pxsim.svg.child(this.defs, "filter", { id: "filterglow", x: "-5%", y: "-5%", width: "120%", height: "120%" }); pxsim.svg.child(glow, "feGaussianBlur", { stdDeviation: "5", result: "glow" }); var merge = pxsim.svg.child(glow, "feMerge", {}); for (var i = 0; i < 3; ++i) pxsim.svg.child(merge, "feMergeNode", { in: "glow" }); // leds this.leds = []; this.ledsOuter = []; var left = Number(this.element.getElementById("LED_0_0").getAttribute("x")); var top = Number(this.element.getElementById("LED_0_0").getAttribute("y")); var ledoffw = Number(this.element.getElementById("LED_1_0").getAttribute("x")) - left; var ledoffh = Number(this.element.getElementById("LED_0_1").getAttribute("y")) - top; var ledw = 5.1; var ledh = 12.9; for (var i = 0; i < 5; ++i) { var ledtop = i * ledoffh + top; for (var j = 0; j < 5; ++j) { var ledleft = j * ledoffw + left; var k = i * 5 + j; this.ledsOuter.push(pxsim.svg.child(this.g, "rect", { class: "sim-led-back", x: ledleft, y: ledtop, width: ledw, height: ledh })); this.leds.push(pxsim.svg.child(this.g, "rect", { class: "sim-led", x: ledleft - 1, y: ledtop - 1, width: ledw + 2, height: ledh + 2, rx: 2, ry: 2, title: "(" + j + "," + i + ")" })); } } // https://www.microbit.co.uk/device/pins // P0, P1, P2 this.pins = pinNames.map(function (n) { var p = _this.element.getElementById(n); if (!p) console.log("missing " + n); pxsim.svg.addClass(p, "sim-pin"); return p; }); this.pins.forEach(function (p, i) { return pxsim.svg.hydrate(p, { title: pinTitles[i] }); }); this.pinGradients = this.pins.map(function (pin, i) { var gid = "gradient-pin-" + i; var lg = pxsim.svg.linearGradient(_this.defs, gid); pin.setAttribute("fill", "url(#" + gid + ")"); return lg; }); this.pinTexts = [67, 165, 275].map(function (x) { return pxsim.svg.child(_this.g, "text", { class: "sim-text-pin", x: x, y: 345 }); }); // BTN A, B var btnids = ["BTN_A", "BTN_B"]; this.buttonsOuter = btnids.map(function (n) { return _this.element.getElementById(n + "_BOX"); }); this.buttonsOuter.forEach(function (b) { return pxsim.svg.addClass(b, "sim-button-outer"); }); this.buttons = btnids.map(function (n) { return _this.element.getElementById(n); }); this.buttons.forEach(function (b) { return pxsim.svg.addClass(b, "sim-button"); }); // BTN A+B var outerBtn = function (left, top) { var button = _this.mkBtn(left, top); _this.buttonsOuter.push(button.outer); _this.buttons.push(button.inner); return button; }; var ab = outerBtn(69, MB_HEIGHT - 45); var abtext = pxsim.svg.child(ab.outer, "text", { x: 67, y: MB_HEIGHT - 10, class: "sim-text inverted" }); abtext.textContent = "A+B"; this.buttonsOuter[2].style.visibility = "hidden"; this.buttons[2].style.visibility = "hidden"; }; MicrobitBoardSvg.prototype.mkBtn = function (left, top) { var btnr = 2; var btnw = 20; var btnn = 1.6; var btnnm = 2; var btnb = 5; var btng = pxsim.svg.child(this.g, "g", { class: "sim-button-group" }); pxsim.svg.child(btng, "rect", { class: "sim-button-outer", x: left, y: top, rx: btnr, ry: btnr, width: btnw, height: btnw }); pxsim.svg.child(btng, "circle", { class: "sim-button-nut", cx: left + btnnm, cy: top + btnnm, r: btnn }); pxsim.svg.child(btng, "circle", { class: "sim-button-nut", cx: left + btnnm, cy: top + btnw - btnnm, r: btnn }); pxsim.svg.child(btng, "circle", { class: "sim-button-nut", cx: left + btnw - btnnm, cy: top + btnw - btnnm, r: btnn }); pxsim.svg.child(btng, "circle", { class: "sim-button-nut", cx: left + btnw - btnnm, cy: top + btnnm, r: btnn }); var outer = btng; var inner = pxsim.svg.child(btng, "circle", { class: "sim-button", cx: left + btnw / 2, cy: top + btnw / 2, r: btnb }); return { outer: outer, inner: inner }; }; MicrobitBoardSvg.prototype.attachEvents = function () { var _this = this; pxsim.Runtime.messagePosted = function (msg) { switch (msg.type || "") { case "serial": _this.flashSystemLed(); break; case "radiopacket": _this.flashAntenna(); break; } }; var tiltDecayer = 0; this.element.addEventListener(pxsim.pointerEvents.move, function (ev) { var state = _this.board; if (!state.accelerometerState.accelerometer.isActive) return; if (tiltDecayer) { clearInterval(tiltDecayer); tiltDecayer = 0; } var bbox = _this.element.getBoundingClientRect(); var ax = (ev.clientX - bbox.width / 2) / (bbox.width / 3); var ay = (ev.clientY - bbox.height / 2) / (bbox.height / 3); var x = -Math.max(-1023, Math.min(1023, Math.floor(ax * 1023))); var y = -Math.max(-1023, Math.min(1023, Math.floor(ay * 1023))); var z2 = 1023 * 1023 - x * x - y * y; var z = Math.floor((z2 > 0 ? -1 : 1) * Math.sqrt(Math.abs(z2))); state.accelerometerState.accelerometer.update(x, y, z); _this.updateTilt(); }, false); this.element.addEventListener(pxsim.pointerEvents.leave, function (ev) { var state = _this.board; if (!state.accelerometerState.accelerometer.isActive) return; if (!tiltDecayer) { tiltDecayer = setInterval(function () { var accx = state.accelerometerState.accelerometer.getX(pxsim.MicroBitCoordinateSystem.RAW); accx = Math.floor(Math.abs(accx) * 0.85) * (accx > 0 ? 1 : -1); var accy = state.accelerometerState.accelerometer.getY(pxsim.MicroBitCoordinateSystem.RAW); accy = Math.floor(Math.abs(accy) * 0.85) * (accy > 0 ? 1 : -1); var accz = -Math.sqrt(Math.max(0, 1023 * 1023 - accx * accx - accy * accy)); if (Math.abs(accx) <= 24 && Math.abs(accy) <= 24) { clearInterval(tiltDecayer); tiltDecayer = 0; accx = 0; accy = 0; accz = -1023; } state.accelerometerState.accelerometer.update(accx, accy, accz); _this.updateTilt(); }, 50); } }, false); this.pins.forEach(function (pin, index) { if (!_this.board.edgeConnectorState.pins[index]) return; var pt = _this.element.createSVGPoint(); pxsim.svg.buttonEvents(pin, // move function (ev) { var state = _this.board; var pin = state.edgeConnectorState.pins[index]; var svgpin = _this.pins[index]; if (pin.mode & pxsim.PinFlags.Input) { var cursor = pxsim.svg.cursorPoint(pt, _this.element, ev); var v = (400 - cursor.y) / 40 * 1023; pin.value = Math.max(0, Math.min(1023, Math.floor(v))); } _this.updatePin(pin, index); }, // start function (ev) { var state = _this.board; var pin = state.edgeConnectorState.pins[index]; var svgpin = _this.pins[index]; pxsim.svg.addClass(svgpin, "touched"); if (pin.mode & pxsim.PinFlags.Input) { var cursor = pxsim.svg.cursorPoint(pt, _this.element, ev); var v = (400 - cursor.y) / 40 * 1023; pin.value = Math.max(0, Math.min(1023, Math.floor(v))); } _this.updatePin(pin, index); }, // stop function (ev) { var state = _this.board; var pin = state.edgeConnectorState.pins[index]; var svgpin = _this.pins[index]; pxsim.svg.removeClass(svgpin, "touched"); _this.updatePin(pin, index); return false; }); }); this.pins.slice(0, 3).forEach(function (btn, index) { btn.addEventListener(pxsim.pointerEvents.down, function (ev) { var state = _this.board; state.edgeConnectorState.pins[index].touched = true; _this.updatePin(state.edgeConnectorState.pins[index], index); }); btn.addEventListener(pxsim.pointerEvents.leave, function (ev) { var state = _this.board; state.edgeConnectorState.pins[index].touched = false; _this.updatePin(state.edgeConnectorState.pins[index], index); }); btn.addEventListener(pxsim.pointerEvents.up, function (ev) { var state = _this.board; state.edgeConnectorState.pins[index].touched = false; _this.updatePin(state.edgeConnectorState.pins[index], index); _this.board.bus.queue(state.edgeConnectorState.pins[index].id, 2 /* MICROBIT_BUTTON_EVT_UP */); _this.board.bus.queue(state.edgeConnectorState.pins[index].id, 3 /* MICROBIT_BUTTON_EVT_CLICK */); }); }); var bpState = this.board.buttonPairState; var stateButtons = [bpState.aBtn, bpState.bBtn, bpState.abBtn]; this.buttonsOuter.slice(0, 2).forEach(function (btn, index) { btn.addEventListener(pxsim.pointerEvents.down, function (ev) { var state = _this.board; stateButtons[index].pressed = true; pxsim.svg.fill(_this.buttons[index], _this.props.theme.buttonDown); }); btn.addEventListener(pxsim.pointerEvents.leave, function (ev) { var state = _this.board; stateButtons[index].pressed = false; pxsim.svg.fill(_this.buttons[index], _this.props.theme.buttonUps[index]); }); btn.addEventListener(pxsim.pointerEvents.up, function (ev) { var state = _this.board; stateButtons[index].pressed = false; pxsim.svg.fill(_this.buttons[index], _this.props.theme.buttonUps[index]); _this.board.bus.queue(stateButtons[index].id, 2 /* MICROBIT_BUTTON_EVT_UP */); _this.board.bus.queue(stateButtons[index].id, 3 /* MICROBIT_BUTTON_EVT_CLICK */); }); }); this.buttonsOuter[2].addEventListener(pxsim.pointerEvents.down, function (ev) { var state = _this.board; stateButtons[0].pressed = true; stateButtons[1].pressed = true; stateButtons[2].pressed = true; pxsim.svg.fill(_this.buttons[0], _this.props.theme.buttonDown); pxsim.svg.fill(_this.buttons[1], _this.props.theme.buttonDown); pxsim.svg.fill(_this.buttons[2], _this.props.theme.buttonDown); }); this.buttonsOuter[2].addEventListener(pxsim.pointerEvents.leave, function (ev) { var state = _this.board; stateButtons[0].pressed = false; stateButtons[1].pressed = false; stateButtons[2].pressed = false; pxsim.svg.fill(_this.buttons[0], _this.props.theme.buttonUps[0]); pxsim.svg.fill(_this.buttons[1], _this.props.theme.buttonUps[1]); pxsim.svg.fill(_this.buttons[2], _this.props.theme.virtualButtonUp); }); this.buttonsOuter[2].addEventListener(pxsim.pointerEvents.up, function (ev) { var state = _this.board; stateButtons[0].pressed = false; stateButtons[1].pressed = false; stateButtons[2].pressed = false; pxsim.svg.fill(_this.buttons[0], _this.props.theme.buttonUps[0]); pxsim.svg.fill(_this.buttons[1], _this.props.theme.buttonUps[1]); pxsim.svg.fill(_this.buttons[2], _this.props.theme.virtualButtonUp); _this.board.bus.queue(stateButtons[2].id, 2 /* MICROBIT_BUTTON_EVT_UP */); _this.board.bus.queue(stateButtons[2].id, 3 /* MICROBIT_BUTTON_EVT_CLICK */); }); }; return MicrobitBoardSvg; }()); visuals.MicrobitBoardSvg = MicrobitBoardSvg; })(visuals = pxsim.visuals || (pxsim.visuals = {})); })(pxsim || (pxsim = {})); /// /// /// /// var pxsim; (function (pxsim) { var visuals; (function (visuals) { var PIXEL_SPACING = visuals.PIN_DIST * 3; var PIXEL_RADIUS = visuals.PIN_DIST; var CANVAS_WIDTH = 1.2 * visuals.PIN_DIST; var CANVAS_HEIGHT = 12 * visuals.PIN_DIST; var CANVAS_VIEW_WIDTH = CANVAS_WIDTH; var CANVAS_VIEW_HEIGHT = CANVAS_HEIGHT; var CANVAS_VIEW_PADDING = visuals.PIN_DIST * 4; var CANVAS_LEFT = 1.4 * visuals.PIN_DIST; var CANVAS_TOP = visuals.PIN_DIST; // For the instructions parts list function mkNeoPixelPart(xy) { if (xy === void 0) { xy = [0, 0]; } var NP_PART_XOFF = -13.5; var NP_PART_YOFF = -11; var NP_PART_WIDTH = 87.5; var NP_PART_HEIGHT = 190; var NEOPIXEL_PART_IMG = "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n"; var x = xy[0], y = xy[1]; var l = x + NP_PART_XOFF; var t = y + NP_PART_YOFF; var w = NP_PART_WIDTH; var h = NP_PART_HEIGHT; var img = pxsim.svg.elt("image"); pxsim.svg.hydrate(img, { class: "sim-neopixel-strip", x: l, y: t, width: w, height: h, href: pxsim.svg.toDataUri(NEOPIXEL_PART_IMG) }); return { el: img, x: l, y: t, w: w, h: h }; } visuals.mkNeoPixelPart = mkNeoPixelPart; var NeoPixel = (function () { function NeoPixel(xy) { if (xy === void 0) { xy = [0, 0]; } var el = pxsim.svg.elt("rect"); var r = PIXEL_RADIUS; var cx = xy[0], cy = xy[1]; var y = cy - r; pxsim.svg.hydrate(el, { x: "-50%", y: y, width: "100%", height: r * 2, class: "sim-neopixel" }); this.el = el; this.cy = cy; } NeoPixel.prototype.setRgb = function (rgb) { var hsl = visuals.rgbToHsl(rgb); var h = hsl[0], s = hsl[1], l = hsl[2]; // at least 70% luminosity l = Math.max(l, 60); var fill = "hsl(" + h + ", " + s + "%, " + l + "%)"; this.el.setAttribute("fill", fill); }; return NeoPixel; }()); visuals.NeoPixel = NeoPixel; var NeoPixelCanvas = (function () { function NeoPixelCanvas(pin) { this.pixels = []; this.pin = pin; var el = pxsim.svg.elt("svg"); pxsim.svg.hydrate(el, { "class": "sim-neopixel-canvas", "x": "0px", "y": "0px", "width": CANVAS_WIDTH + "px", "height": CANVAS_HEIGHT + "px", }); this.canvas = el; this.background = pxsim.svg.child(el, "rect", { class: "sim-neopixel-background hidden" }); this.updateViewBox(-CANVAS_VIEW_WIDTH / 2, 0, CANVAS_VIEW_WIDTH, CANVAS_VIEW_HEIGHT); } NeoPixelCanvas.prototype.updateViewBox = function (x, y, w, h) { this.viewBox = [x, y, w, h]; pxsim.svg.hydrate(this.canvas, { "viewBox": x + " " + y + " " + w + " " + h }); pxsim.svg.hydrate(this.background, { "x": x, "y": y, "width": w, "height": h }); }; NeoPixelCanvas.prototype.update = function (colors) { if (!colors || colors.length <= 0) return; for (var i = 0; i < colors.length; i++) { var pixel = this.pixels[i]; if (!pixel) { var cxy = [0, CANVAS_VIEW_PADDING + i * PIXEL_SPACING]; pixel = this.pixels[i] = new NeoPixel(cxy); pxsim.svg.hydrate(pixel.el, { title: "offset: " + i }); this.canvas.appendChild(pixel.el); } var color = colors[i]; pixel.setRgb(color); } //show the canvas if it's hidden pxsim.svg.removeClass(this.background, "hidden"); //resize if necessary var _a = [this.pixels[0], this.pixels[this.pixels.length - 1]], first = _a[0], last = _a[1]; var yDiff = last.cy - first.cy; var newH = yDiff + CANVAS_VIEW_PADDING * 2; var _b = this.viewBox, oldX = _b[0], oldY = _b[1], oldW = _b[2], oldH = _b[3]; if (oldH < newH) { var scalar = newH / oldH; var newW = oldW * scalar; this.updateViewBox(-newW / 2, oldY, newW, newH); } }; NeoPixelCanvas.prototype.setLoc = function (xy) { var x = xy[0], y = xy[1]; pxsim.svg.hydrate(this.canvas, { x: x, y: y }); }; return NeoPixelCanvas; }()); visuals.NeoPixelCanvas = NeoPixelCanvas; ; function digitalPinToPinNumber(gpioPin) { var MICROBIT_ID_IO_P0 = 7; //TODO: don't hardcode this, import enums.d.ts if (gpioPin == "*") { return MICROBIT_ID_IO_P0; } var pinSplit = gpioPin.split("DigitalPin.P"); pxsim.U.assert(pinSplit.length === 2, "Unknown format for pin (for NeoPixel): " + gpioPin); var pinNumStr = pinSplit[1]; var pinNum = Number(pinNumStr) + MICROBIT_ID_IO_P0; return pinNum; } function parseNeoPixelMode(modeStr) { var modeMap = { "NeoPixelMode.RGB": pxsim.NeoPixelMode.RGB, "NeoPixelMode.RGBW": pxsim.NeoPixelMode.RGBW }; return modeMap[modeStr] || pxsim.NeoPixelMode.RGB; } var NeoPixelView = (function () { function NeoPixelView() { this.style = "\n .sim-neopixel-canvas {\n }\n .sim-neopixel-canvas-parent:hover {\n transform-origin: center;\n transform: scale(4) translateY(-60px);\n }\n .sim-neopixel-canvas .hidden {\n visibility:hidden;\n }\n .sim-neopixel-background {\n fill: rgba(255,255,255,0.9);\n }\n .sim-neopixel-strip {\n }\n "; } NeoPixelView.prototype.init = function (bus, state, svgEl, otherParams) { pxsim.U.assert(!!otherParams["mode"], "NeoPixels assumes a RGB vs RGBW mode is passed to it"); pxsim.U.assert(!!otherParams["pin"], "NeoPixels assumes a pin is passed to it"); var modeStr = otherParams["mode"]; this.mode = parseNeoPixelMode(modeStr); this.state = state; this.stripGroup = pxsim.svg.elt("g"); this.element = this.stripGroup; var pinStr = otherParams["pin"]; this.pin = digitalPinToPinNumber(pinStr); this.lastLocation = [0, 0]; var part = mkNeoPixelPart(); this.part = part; this.stripGroup.appendChild(part.el); var canvas = new NeoPixelCanvas(this.pin); this.canvas = canvas; var canvasG = pxsim.svg.elt("g", { class: "sim-neopixel-canvas-parent" }); this.overElement = canvasG; canvasG.appendChild(canvas.canvas); this.updateStripLoc(); }; NeoPixelView.prototype.moveToCoord = function (xy) { var x = xy[0], y = xy[1]; var loc = [x, y]; this.lastLocation = loc; this.updateStripLoc(); }; NeoPixelView.prototype.updateStripLoc = function () { var _a = this.lastLocation, x = _a[0], y = _a[1]; pxsim.U.assert(typeof x === "number" && typeof y === "number", "invalid x,y for NeoPixel strip"); this.canvas.setLoc([x + CANVAS_LEFT, y + CANVAS_TOP]); pxsim.svg.hydrate(this.part.el, { transform: "translate(" + x + " " + y + ")" }); //TODO: update part's l,h, etc. }; NeoPixelView.prototype.updateState = function () { var colors = this.state.getColors(this.pin, this.mode); this.canvas.update(colors); }; NeoPixelView.prototype.updateTheme = function () { }; return NeoPixelView; }()); visuals.NeoPixelView = NeoPixelView; })(visuals = pxsim.visuals || (pxsim.visuals = {})); })(pxsim || (pxsim = {}));