UNPKG

pxt-ev3

Version:

LEGO MINDSTORMS EV3 for Microsoft MakeCode

1,322 lines 249 kB
var pxsim; (function (pxsim) { var input; (function (input) { function onGesture(gesture, handler) { let b = pxsim.accelerometer(); b.accelerometer.activate(); if (gesture == 11 /* DAL.ACCELEROMETER_EVT_SHAKE */ && !b.useShake) { b.useShake = true; pxsim.runtime.queueDisplayUpdate(); } pxsim.pxtcore.registerWithDal(13 /* DAL.DEVICE_ID_GESTURE */, gesture, handler); } input.onGesture = onGesture; function rotation(kind) { let b = pxsim.accelerometer(); let acc = b.accelerometer; acc.activate(); let x = acc.getX(pxsim.MicroBitCoordinateSystem.NORTH_EAST_DOWN); let y = acc.getY(pxsim.MicroBitCoordinateSystem.NORTH_EAST_DOWN); let z = acc.getZ(pxsim.MicroBitCoordinateSystem.NORTH_EAST_DOWN); let roll = Math.atan2(y, z); let pitch = Math.atan(-x / (y * Math.sin(roll) + z * Math.cos(roll))); let 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) { let b = pxsim.accelerometer(); b.accelerometer.setSampleRange(range); } input.setAccelerometerRange = setAccelerometerRange; function acceleration(dimension) { let b = pxsim.accelerometer(); let 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; })(input = pxsim.input || (pxsim.input = {})); })(pxsim || (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--> * */ let MicroBitCoordinateSystem; (function (MicroBitCoordinateSystem) { MicroBitCoordinateSystem[MicroBitCoordinateSystem["RAW"] = 0] = "RAW"; MicroBitCoordinateSystem[MicroBitCoordinateSystem["SIMPLE_CARTESIAN"] = 1] = "SIMPLE_CARTESIAN"; MicroBitCoordinateSystem[MicroBitCoordinateSystem["NORTH_EAST_DOWN"] = 2] = "NORTH_EAST_DOWN"; })(MicroBitCoordinateSystem = pxsim.MicroBitCoordinateSystem || (pxsim.MicroBitCoordinateSystem = {})); class Accelerometer { constructor(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 = 5 /* DAL.DEVICE_ID_ACCELEROMETER */; } setSampleRange(range) { this.activate(); this.sampleRange = Math.max(1, Math.min(8, range)); } activate() { 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! */ update(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 /* DAL.ACCELEROMETER_EVT_DATA_UPDATE */); } instantaneousAccelerationSquared() { // 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. */ instantaneousPosture() { let force = this.instantaneousAccelerationSquared(); let 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 /* DAL.ACCELEROMETER_SHAKE_TOLERANCE */ && this.shake.x) || (this.getX() > 400 /* DAL.ACCELEROMETER_SHAKE_TOLERANCE */ && !this.shake.x)) { shakeDetected = true; this.shake.x = !this.shake.x; } if ((this.getY() < -400 /* DAL.ACCELEROMETER_SHAKE_TOLERANCE */ && this.shake.y) || (this.getY() > 400 /* DAL.ACCELEROMETER_SHAKE_TOLERANCE */ && !this.shake.y)) { shakeDetected = true; this.shake.y = !this.shake.y; } if ((this.getZ() < -400 /* DAL.ACCELEROMETER_SHAKE_TOLERANCE */ && this.shake.z) || (this.getZ() > 400 /* DAL.ACCELEROMETER_SHAKE_TOLERANCE */ && !this.shake.z)) { shakeDetected = true; this.shake.z = !this.shake.z; } if (shakeDetected && this.shake.count < 4 /* DAL.ACCELEROMETER_SHAKE_COUNT_THRESHOLD */ && ++this.shake.count == 4 /* DAL.ACCELEROMETER_SHAKE_COUNT_THRESHOLD */) this.shake.shaken = 1; if (++this.shake.timer >= 10 /* DAL.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 11 /* DAL.ACCELEROMETER_EVT_SHAKE */; let sq = (n) => n * n; if (force < sq(400 /* DAL.ACCELEROMETER_FREEFALL_TOLERANCE */)) return 7 /* DAL.ACCELEROMETER_EVT_FREEFALL */; if (force > sq(3072 /* DAL.ACCELEROMETER_3G_TOLERANCE */)) return 8 /* DAL.ACCELEROMETER_EVT_3G */; if (force > sq(6144 /* DAL.ACCELEROMETER_6G_TOLERANCE */)) return 9 /* DAL.ACCELEROMETER_EVT_6G */; if (force > sq(8192 /* DAL.ACCELEROMETER_8G_TOLERANCE */)) return 10 /* DAL.ACCELEROMETER_EVT_8G */; // Determine our posture. if (this.getX() < (-1000 + 200 /* DAL.ACCELEROMETER_TILT_TOLERANCE */)) return 3 /* DAL.ACCELEROMETER_EVT_TILT_LEFT */; if (this.getX() > (1000 - 200 /* DAL.ACCELEROMETER_TILT_TOLERANCE */)) return 4 /* DAL.ACCELEROMETER_EVT_TILT_RIGHT */; if (this.getY() < (-1000 + 200 /* DAL.ACCELEROMETER_TILT_TOLERANCE */)) return 1 /* DAL.ACCELEROMETER_EVT_TILT_UP */; if (this.getY() > (1000 - 200 /* DAL.ACCELEROMETER_TILT_TOLERANCE */)) return 2 /* DAL.ACCELEROMETER_EVT_TILT_DOWN */; if (this.getZ() < (-1000 + 200 /* DAL.ACCELEROMETER_TILT_TOLERANCE */)) return 5 /* DAL.ACCELEROMETER_EVT_FACE_UP */; if (this.getZ() > (1000 - 200 /* DAL.ACCELEROMETER_TILT_TOLERANCE */)) return 6 /* DAL.ACCELEROMETER_EVT_FACE_DOWN */; return 0; } updateGesture() { // Determine what it looks like we're doing based on the latest sample... let g = this.instantaneousPosture(); // Perform some low pass filtering to reduce jitter from any detected effects if (g == this.currentGesture) { if (this.sigma < 5 /* DAL.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 /* DAL.ACCELEROMETER_GESTURE_DAMPING */) { this.lastGesture = this.currentGesture; pxsim.board().bus.queue(13 /* DAL.DEVICE_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 */ getX(system = MicroBitCoordinateSystem.SIMPLE_CARTESIAN) { this.activate(); let val; switch (system) { case MicroBitCoordinateSystem.SIMPLE_CARTESIAN: val = -this.sample.x; case MicroBitCoordinateSystem.NORTH_EAST_DOWN: val = this.sample.y; //case MicroBitCoordinateSystem.SIMPLE_CARTESIAN.RAW: default: val = this.sample.x; } return pxsim.board().invertAccelerometerXAxis ? val * -1 : val; } /** * 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 */ getY(system = MicroBitCoordinateSystem.SIMPLE_CARTESIAN) { this.activate(); let val; switch (system) { case MicroBitCoordinateSystem.SIMPLE_CARTESIAN: val = -this.sample.y; case MicroBitCoordinateSystem.NORTH_EAST_DOWN: val = -this.sample.x; //case RAW: default: val = this.sample.y; } return pxsim.board().invertAccelerometerYAxis ? val * -1 : val; } /** * 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 */ getZ(system = MicroBitCoordinateSystem.SIMPLE_CARTESIAN) { this.activate(); let val; switch (system) { case MicroBitCoordinateSystem.NORTH_EAST_DOWN: val = -this.sample.z; //case MicroBitCoordinateSystem.SIMPLE_CARTESIAN: //case MicroBitCoordinateSystem.RAW: default: val = this.sample.z; } return pxsim.board().invertAccelerometerZAxis ? val * -1 : val; } /** * 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 */ getPitch() { this.activate(); return Math.floor((360 * this.getPitchRadians()) / (2 * Math.PI)); } getPitchRadians() { 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 */ getRoll() { this.activate(); return Math.floor((360 * this.getRollRadians()) / (2 * Math.PI)); } getRollRadians() { 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... */ recalculatePitchRoll() { let x = this.getX(MicroBitCoordinateSystem.NORTH_EAST_DOWN); let y = this.getY(MicroBitCoordinateSystem.NORTH_EAST_DOWN); let 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))); } } pxsim.Accelerometer = Accelerometer; class AccelerometerState { constructor(runtime) { this.useShake = false; this.tiltDecayer = 0; this.accelerometer = new Accelerometer(runtime); } attachEvents(element) { this.element = element; this.tiltDecayer = 0; this.element.addEventListener(pxsim.pointerEvents.move, (ev) => { if (!this.accelerometer.isActive) return; if (this.tiltDecayer) { clearInterval(this.tiltDecayer); this.tiltDecayer = 0; } let bbox = element.getBoundingClientRect(); let ax = (ev.clientX - bbox.width / 2) / (bbox.width / 3); let ay = (ev.clientY - bbox.height / 2) / (bbox.height / 3); let x = -Math.max(-1023, Math.min(1023, Math.floor(ax * 1023))); let y = Math.max(-1023, Math.min(1023, Math.floor(ay * 1023))); let z2 = 1023 * 1023 - x * x - y * y; let z = Math.floor((z2 > 0 ? -1 : 1) * Math.sqrt(Math.abs(z2))); this.accelerometer.update(-x, y, z); this.updateTilt(); }, false); this.element.addEventListener(pxsim.pointerEvents.leave, (ev) => { if (!this.accelerometer.isActive) return; if (!this.tiltDecayer) { this.tiltDecayer = setInterval(() => { let accx = this.accelerometer.getX(); accx = Math.floor(Math.abs(accx) * 0.85) * (accx > 0 ? 1 : -1); let accy = this.accelerometer.getY(); accy = Math.floor(Math.abs(accy) * 0.85) * (accy > 0 ? 1 : -1); let accz = -Math.sqrt(Math.max(0, 1023 * 1023 - accx * accx - accy * accy)); if (Math.abs(accx) <= 24 && Math.abs(accy) <= 24) { clearInterval(this.tiltDecayer); this.tiltDecayer = 0; accx = 0; accy = 0; accz = -1023; } this.accelerometer.update(accx, accy, accz); this.updateTilt(); }, 50); } }, false); } updateTilt() { if (!this.accelerometer.isActive || !this.element) return; const x = this.accelerometer.getX(); const y = this.accelerometer.getY(); const af = 8 / 1023; const 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"; } } pxsim.AccelerometerState = AccelerometerState; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { function accelerometer() { return pxsim.board().accelerometerState; } pxsim.accelerometer = accelerometer; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var pxtcore; (function (pxtcore) { function getPin(id) { const b = pxsim.board(); if (b && b.edgeConnectorState) return b.edgeConnectorState.getPin(id); return undefined; } pxtcore.getPin = getPin; function lookupPinCfg(key) { return getPinCfg(key); } pxtcore.lookupPinCfg = lookupPinCfg; function getPinCfg(key) { return getPin(pxtcore.getConfig(key, -1)); } pxtcore.getPinCfg = getPinCfg; })(pxtcore = pxsim.pxtcore || (pxsim.pxtcore = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var pxtcore; (function (pxtcore) { // TODO: add in support for mode, as in CODAL function registerWithDal(id, evid, handler, mode = 0) { pxsim.board().bus.listen(id, evid, handler); } pxtcore.registerWithDal = registerWithDal; function deepSleep() { // TODO? console.log("deep sleep requested"); } pxtcore.deepSleep = deepSleep; })(pxtcore = pxsim.pxtcore || (pxsim.pxtcore = {})); })(pxsim || (pxsim = {})); (function (pxsim) { var BufferMethods; (function (BufferMethods) { function fnv1(data) { let h = 0x811c9dc5; for (let i = 0; i < data.length; ++i) { h = Math.imul(h, 0x1000193) ^ data[i]; } return h; } function hash(buf, bits) { bits |= 0; if (bits < 1) return 0; const h = fnv1(buf.data); if (bits >= 32) return h >>> 0; else return ((h ^ (h >>> bits)) & ((1 << bits) - 1)) >>> 0; } BufferMethods.hash = hash; })(BufferMethods = pxsim.BufferMethods || (pxsim.BufferMethods = {})); })(pxsim || (pxsim = {})); (function (pxsim) { var control; (function (control) { control.runInParallel = pxsim.thread.runInBackground; control.delay = pxsim.thread.pause; function reset() { pxsim.Runtime.postMessage({ type: "simulator", command: "restart", controlReset: true }); const cb = pxsim.getResume(); } control.reset = reset; function waitMicros(micros) { pxsim.thread.pause(micros / 1000); // it prempts not much we can do here. } control.waitMicros = waitMicros; function deviceName() { let b = pxsim.board(); return b && b.id ? b.id.slice(0, 4) : "abcd"; } control.deviceName = deviceName; function _ramSize() { return 32 * 1024 * 1024; } control._ramSize = _ramSize; function deviceSerialNumber() { let b = pxsim.board(); if (!b) return 42; let n = 0; if (b.id) { n = parseInt(b.id.slice(1)); if (isNaN(n)) { n = 0; for (let i = 0; i < b.id.length; ++i) { n = ((n << 5) - n) + b.id.charCodeAt(i); n |= 0; } n = Math.abs(n); } } if (!n) n = 42; return n; } control.deviceSerialNumber = deviceSerialNumber; function deviceLongSerialNumber() { let b = control.createBuffer(8); pxsim.BufferMethods.setNumber(b, pxsim.BufferMethods.NumberFormat.UInt32LE, 0, deviceSerialNumber()); return b; } control.deviceLongSerialNumber = deviceLongSerialNumber; function deviceDalVersion() { return "sim"; } control.deviceDalVersion = deviceDalVersion; function internalOnEvent(id, evid, handler) { pxsim.pxtcore.registerWithDal(id, evid, handler); } control.internalOnEvent = internalOnEvent; function waitForEvent(id, evid) { const cb = pxsim.getResume(); pxsim.board().bus.wait(id, evid, cb); } control.waitForEvent = waitForEvent; function allocateNotifyEvent() { let b = pxsim.board(); return b.bus.nextNotifyEvent++; } control.allocateNotifyEvent = allocateNotifyEvent; function raiseEvent(id, evid, mode) { // TODO mode? pxsim.board().bus.queue(id, evid); } control.raiseEvent = raiseEvent; function millis() { return pxsim.runtime.runningTime(); } control.millis = millis; function micros() { return pxsim.runtime.runningTimeUs() & 0x3fffffff; } control.micros = micros; function delayMicroseconds(us) { control.delay(us / 0.001); } control.delayMicroseconds = delayMicroseconds; function createBuffer(size) { return pxsim.BufferMethods.createBuffer(size); } control.createBuffer = createBuffer; function dmesg(msg) { console.log(`DMESG: ${msg}`); } control.dmesg = dmesg; function setDebugFlags(flags) { console.log(`debug flags: ${flags}`); } control.setDebugFlags = setDebugFlags; function heapSnapshot() { console.log(pxsim.runtime.traceObjects()); } control.heapSnapshot = heapSnapshot; function toStr(v) { if (v instanceof pxsim.RefRecord) { return `${v.vtable.name}@${v.id}`; } if (v instanceof pxsim.RefCollection) { let r = "["; for (let e of v.toArray()) { if (r.length > 200) { r += "..."; break; } r += toStr(e) + ", "; } r += "]"; return r; } if (typeof v == "function") { return (v + "").slice(0, 60) + "..."; } return v + ""; } function dmesgPtr(msg, ptr) { console.log(`DMESG: ${msg} ${toStr(ptr)}`); } control.dmesgPtr = dmesgPtr; function dmesgValue(ptr) { console.log(`DMESG: ${toStr(ptr)}`); } control.dmesgValue = dmesgValue; function gc() { } control.gc = gc; function profilingEnabled() { return !!pxsim.runtime.perfCounters; } control.profilingEnabled = profilingEnabled; function __log(priority, str) { switch (priority) { case 0: console.debug("d>" + str); break; case 1: console.log("l>" + str); break; case 2: console.warn("w>" + str); break; case 3: console.error("e>" + str); break; } pxsim.runtime.board.writeSerial(str); } control.__log = __log; function heapDump() { // TODO something better } control.heapDump = heapDump; function isUSBInitialized() { return false; } control.isUSBInitialized = isUSBInitialized; })(control = pxsim.control || (pxsim.control = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var pxtcore; (function (pxtcore) { // general purpose message sending mechanism function sendMessage(channel, message, parentOnly) { if (!channel) return; pxsim.Runtime.postMessage({ type: "messagepacket", broadcast: !parentOnly, channel: channel, data: message && message.data }); } pxtcore.sendMessage = sendMessage; function peekMessageChannel() { const state = pxsim.getControlMessageState(); const msg = state && state.peek(); return msg && msg.channel; } pxtcore.peekMessageChannel = peekMessageChannel; function readMessageData() { const state = pxsim.getControlMessageState(); const msg = state && state.read(); return msg && new pxsim.RefBuffer(msg.data); } pxtcore.readMessageData = readMessageData; })(pxtcore = pxsim.pxtcore || (pxsim.pxtcore = {})); })(pxsim || (pxsim = {})); (function (pxsim) { // keep in sync with ts pxsim.CONTROL_MESSAGE_EVT_ID = 2999; pxsim.CONTROL_MESSAGE_RECEIVED = 1; class ControlMessageState { constructor(board) { this.board = board; this.messages = []; this.enabled = false; this.board.addMessageListener(msg => this.messageHandler(msg)); } messageHandler(msg) { if (msg.type == "messagepacket") { let packet = msg; this.enqueue(packet); } } enqueue(message) { this.messages.push(message); this.board.bus.queue(pxsim.CONTROL_MESSAGE_EVT_ID, pxsim.CONTROL_MESSAGE_RECEIVED); } peek() { return this.messages[0]; } read() { return this.messages.shift(); } } pxsim.ControlMessageState = ControlMessageState; function getControlMessageState() { return pxsim.board().controlMessageState; } pxsim.getControlMessageState = getControlMessageState; })(pxsim || (pxsim = {})); /// <reference path="../../../node_modules/pxt-core/built/pxtsim.d.ts" /> var pxsim; (function (pxsim) { function board() { return pxsim.runtime && pxsim.runtime.board; } pxsim.board = board; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var loops; (function (loops) { loops.pause = pxsim.thread.pause; loops.forever = pxsim.thread.forever; })(loops = pxsim.loops || (pxsim.loops = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var browserEvents; (function (browserEvents) { function mouseX() { return pxsim.board().mouseState.mouseX(); } browserEvents.mouseX = mouseX; function mouseY() { return pxsim.board().mouseState.mouseY(); } browserEvents.mouseY = mouseY; function wheelDx() { return pxsim.board().mouseState.wheelDx(); } browserEvents.wheelDx = wheelDx; function wheelDy() { return pxsim.board().mouseState.wheelDy(); } browserEvents.wheelDy = wheelDy; function wheelDz() { return pxsim.board().mouseState.wheelDz(); } browserEvents.wheelDz = wheelDz; })(browserEvents = pxsim.browserEvents || (pxsim.browserEvents = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var browserEvents; (function (browserEvents) { let Key; (function (Key) { Key[Key["Zero"] = 48] = "Zero"; Key[Key["One"] = 49] = "One"; Key[Key["Two"] = 50] = "Two"; Key[Key["Three"] = 51] = "Three"; Key[Key["Four"] = 52] = "Four"; Key[Key["Five"] = 53] = "Five"; Key[Key["Six"] = 54] = "Six"; Key[Key["Seven"] = 55] = "Seven"; Key[Key["Eight"] = 56] = "Eight"; Key[Key["Nine"] = 57] = "Nine"; Key[Key["BackTick"] = 192] = "BackTick"; Key[Key["Hyphen"] = 189] = "Hyphen"; Key[Key["Equals"] = 187] = "Equals"; Key[Key["Q"] = 81] = "Q"; Key[Key["W"] = 87] = "W"; Key[Key["E"] = 69] = "E"; Key[Key["R"] = 82] = "R"; Key[Key["T"] = 84] = "T"; Key[Key["Y"] = 89] = "Y"; Key[Key["U"] = 85] = "U"; Key[Key["I"] = 73] = "I"; Key[Key["O"] = 79] = "O"; Key[Key["P"] = 80] = "P"; Key[Key["OpenBracket"] = 219] = "OpenBracket"; Key[Key["CloseBracket"] = 221] = "CloseBracket"; Key[Key["BackSlash"] = 220] = "BackSlash"; Key[Key["A"] = 65] = "A"; Key[Key["S"] = 83] = "S"; Key[Key["D"] = 68] = "D"; Key[Key["F"] = 70] = "F"; Key[Key["G"] = 71] = "G"; Key[Key["H"] = 72] = "H"; Key[Key["Space"] = 32] = "Space"; Key[Key["PageUp"] = 33] = "PageUp"; Key[Key["J"] = 74] = "J"; Key[Key["K"] = 75] = "K"; Key[Key["L"] = 76] = "L"; Key[Key["SemiColon"] = 186] = "SemiColon"; Key[Key["Apostrophe"] = 222] = "Apostrophe"; Key[Key["Z"] = 90] = "Z"; Key[Key["X"] = 88] = "X"; Key[Key["C"] = 67] = "C"; Key[Key["V"] = 86] = "V"; Key[Key["B"] = 66] = "B"; Key[Key["N"] = 78] = "N"; Key[Key["M"] = 77] = "M"; Key[Key["Comma"] = 188] = "Comma"; Key[Key["Period"] = 190] = "Period"; Key[Key["ForwardSlash"] = 191] = "ForwardSlash"; Key[Key["Shift"] = 16] = "Shift"; Key[Key["Enter"] = 13] = "Enter"; Key[Key["CapsLock"] = 20] = "CapsLock"; Key[Key["Tab"] = 9] = "Tab"; Key[Key["Control"] = 17] = "Control"; Key[Key["Meta"] = 91] = "Meta"; Key[Key["Alt"] = 18] = "Alt"; Key[Key["ArrowUp"] = 38] = "ArrowUp"; Key[Key["ArrowDown"] = 40] = "ArrowDown"; Key[Key["ArrowLeft"] = 37] = "ArrowLeft"; Key[Key["ArrowRight"] = 39] = "ArrowRight"; Key[Key["PageDown"] = 34] = "PageDown"; Key[Key["End"] = 35] = "End"; Key[Key["Home"] = 36] = "Home"; })(Key = browserEvents.Key || (browserEvents.Key = {})); function onKeyboardEvent(event, pressed) { if (pressed) { pxsim.board().bus.queue(6866, getValueForKey(event)); } else { pxsim.board().bus.queue(6867, getValueForKey(event)); } } browserEvents.onKeyboardEvent = onKeyboardEvent; function getValueForKey(event) { switch (event.key) { case "0": case ")": return Key.Zero; case "1": case "!": return Key.One; case "2": case "@": return Key.Two; case "3": case "#": return Key.Three; case "4": case "$": return Key.Four; case "5": case "%": return Key.Five; case "6": case "^": return Key.Six; case "7": case "&": return Key.Seven; case "8": case "*": return Key.Eight; case "9": case "(": return Key.Nine; case "`": case "~": return Key.BackTick; case "-": case "_": return Key.Hyphen; case "=": case "+": return Key.Equals; case "Q": case "q": return Key.Q; case "W": case "w": return Key.W; case "E": case "e": return Key.E; case "R": case "r": return Key.R; case "T": case "t": return Key.T; case "Y": case "y": return Key.Y; case "U": case "u": return Key.U; case "I": case "i": return Key.I; case "O": case "o": return Key.O; case "P": case "p": return Key.P; case "[": case "{": return Key.OpenBracket; case "]": case "}": return Key.CloseBracket; case "\\": case "|": return Key.BackSlash; case "A": case "a": return Key.A; case "S": case "s": return Key.S; case "D": case "d": return Key.D; case "F": case "f": return Key.F; case "G": case "g": return Key.G; case "H": case "h": return Key.H; case " ": return Key.Space; case "PageUp": return Key.PageUp; case "J": case "j": return Key.J; case "K": case "k": return Key.K; case "L": case "l": return Key.L; case ";": case ":": return Key.SemiColon; case "'": case "\"": return Key.Apostrophe; case "Z": case "z": return Key.Z; case "X": case "x": return Key.X; case "C": case "c": return Key.C; case "V": case "v": return Key.V; case "B": case "b": return Key.B; case "N": case "n": return Key.N; case "M": case "m": return Key.M; case ",": case "<": return Key.Comma; case ".": case ">": return Key.Period; case "/": case "?": return Key.ForwardSlash; case "Shift": return Key.Shift; case "Enter": return Key.Enter; case "CapsLock": return Key.CapsLock; case "Tab": return Key.Tab; case "Control": return Key.Control; case "Meta": return Key.Meta; case "Alt": return Key.Alt; case "ArrowUp": return Key.ArrowUp; case "ArrowDown": return Key.ArrowDown; case "ArrowLeft": return Key.ArrowLeft; case "ArrowRight": return Key.ArrowRight; case "PageDown": return Key.PageDown; case "End": return Key.End; case "Home": return Key.Home; default: return 0; } } browserEvents.getValueForKey = getValueForKey; })(browserEvents = pxsim.browserEvents || (pxsim.browserEvents = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var browserEvents; (function (browserEvents) { const THROTTLE_INTERVAL = 50; class MouseState { constructor() { this.onMove = pxsim.U.throttle(() => { pxsim.board().bus.queue(6859, 0); }, THROTTLE_INTERVAL, true); this.onWheel = pxsim.U.throttle(() => { pxsim.board().bus.queue(6865, 0); }, THROTTLE_INTERVAL, true); } onEvent(event, x, y) { this.x = x; this.y = y; const events = [ "pointerdown", "pointerup", "pointermove", "pointerleave", "pointerenter", "pointercancel", "pointerover", "pointerout", ]; // We add 1 to the button here because the left button is 0 and // that's used as a wildcard in our event bus pxsim.board().bus.queue(6857 + events.indexOf(event.type), (event.button || 0) + 1); } onWheelEvent(dx, dy, dz) { this.dx = dx; this.dy = dy; this.dz = dz; this.onWheel(); } mouseX() { return this.x || 0; } mouseY() { return this.y || 0; } wheelDx() { return this.dx || 0; } wheelDy() { return this.dy || 0; } wheelDz() { return this.dz || 0; } } browserEvents.MouseState = MouseState; })(browserEvents = pxsim.browserEvents || (pxsim.browserEvents = {})); })(pxsim || (pxsim = {})); /// <reference path="../../core/dal.d.ts"/> var pxsim; (function (pxsim) { const DOUBLE_CLICK_TIME = 500; class CommonButton extends pxsim.Button { constructor() { super(...arguments); this._pressedTime = -1; this._clickedTime = -1; } setPressed(p) { if (this.pressed === p) { return; } this.pressed = p; if (p) { this._wasPressed = true; pxsim.board().bus.queue(this.id, 1 /* DAL.DEVICE_BUTTON_EVT_DOWN */); this._pressedTime = pxsim.runtime.runningTime(); } else if (this._pressedTime !== -1) { pxsim.board().bus.queue(this.id, 2 /* DAL.DEVICE_BUTTON_EVT_UP */); const current = pxsim.runtime.runningTime(); if (current - this._pressedTime >= 1000 /* DAL.DEVICE_BUTTON_LONG_CLICK_TIME */) { pxsim.board().bus.queue(this.id, 4 /* DAL.DEVICE_BUTTON_EVT_LONG_CLICK */); } else { pxsim.board().bus.queue(this.id, 3 /* DAL.DEVICE_BUTTON_EVT_CLICK */); } if (this._clickedTime !== -1) { if (current - this._clickedTime <= DOUBLE_CLICK_TIME) { pxsim.board().bus.queue(this.id, 6 /* DAL.DEVICE_BUTTON_EVT_DOUBLE_CLICK */); } } this._clickedTime = current; } } wasPressed() { const temp = this._wasPressed; this._wasPressed = false; return temp; } pressureLevel() { // digital for now return this.isPressed() ? 512 : 0; } isPressed() { return this.pressed; } } pxsim.CommonButton = CommonButton; class CommonButtonState { constructor(buttons) { this.usesButtonAB = false; this.buttonsByPin = {}; this.buttons = buttons || [ new CommonButton(1 /* DAL.DEVICE_ID_BUTTON_A */), new CommonButton(2 /* DAL.DEVICE_ID_BUTTON_B */), new CommonButton(3 /* DAL.DEVICE_ID_BUTTON_AB */) ]; this.buttons.forEach(btn => this.buttonsByPin[btn.id] = btn); } } pxsim.CommonButtonState = CommonButtonState; })(pxsim || (pxsim = {})); (function (pxsim) { var pxtcore; (function (pxtcore) { function getButtonByPin(pinId) { let m = pxsim.board().buttonState.buttonsByPin; let b = m[pinId + ""]; if (!b) { b = m[pinId + ""] = new pxsim.CommonButton(pinId); } return b; } pxtcore.getButtonByPin = getButtonByPin; function getButtonByPinCfg(key) { return getButtonByPin(pxtcore.getConfig(key, -1)); } pxtcore.getButtonByPinCfg = getButtonByPinCfg; function getButton(buttonId) { const buttons = pxsim.board().buttonState.buttons; if (buttonId === 2) { pxsim.board().buttonState.usesButtonAB = true; pxsim.runtime.queueDisplayUpdate(); } if (buttonId < buttons.length && buttonId >= 0) { return buttons[buttonId]; } // panic return undefined; } pxtcore.getButton = getButton; })(pxtcore = pxsim.pxtcore || (pxsim.pxtcore = {})); })(pxsim || (pxsim = {})); (function (pxsim) { var ButtonMethods; (function (ButtonMethods) { function onEvent(button, ev, body) { pxsim.pxtcore.registerWithDal(button.id, ev, body); } ButtonMethods.onEvent = onEvent; function isPressed(button) { return button.pressed; } ButtonMethods.isPressed = isPressed; function pressureLevel(button) { return button.pressureLevel(); } ButtonMethods.pressureLevel = pressureLevel; function wasPressed(button) { return button.wasPressed(); } ButtonMethods.wasPressed = wasPressed; function id(button) { return button.id; } ButtonMethods.id = id; })(ButtonMethods = pxsim.ButtonMethods || (pxsim.ButtonMethods = {})); })(pxsim || (pxsim = {})); (function (pxsim) { var DigitalInOutPinMethods; (function (DigitalInOutPinMethods) { function pushButton(pin) { return pxsim.pxtcore.getButtonByPin(pin.id); } DigitalInOutPinMethods.pushButton = pushButton; })(DigitalInOutPinMethods = pxsim.DigitalInOutPinMethods || (pxsim.DigitalInOutPinMethods = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { var network; (function (network) { function cableSendPacket(buf) { const state = pxsim.getCableState(); state.send(buf); } network.cableSendPacket = cableSendPacket; function cablePacket() { const state = pxsim.getCableState(); return (state.packet); } network.cablePacket = cablePacket; function onCablePacket(body) { const state = pxsim.getCableState(); state.listen(body); } network.onCablePacket = onCablePacket; function onCableError(body) { const state = pxsim.getCableState(); state.listenError(body); } network.onCableError = onCableError; })(network = pxsim.network || (pxsim.network = {})); })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { class CableState { constructor() { // notify view that a packet was received this.packetReceived = false; // PULSE_IR_COMPONENT_ID = 0x2042; this.PULSE_CABLE_COMPONENT_ID = 0x2043; this.PULSE_PACKET_EVENT = 0x2; this.PULSE_PACKET_ERROR_EVENT = 0x3; } send(buf) { pxsim.Runtime.postMessage({ type: "irpacket", packet: buf.data }); } listen(body) { pxsim.pxtcore.registerWithDal(this.PULSE_CABLE_COMPONENT_ID, this.PULSE_PACKET_EVENT, body); } listenError(body) { pxsim.pxtcore.registerWithDal(this.PULSE_CABLE_COMPONENT_ID, this.PULSE_PACKET_ERROR_EVENT, body); } receive(buf) { this.packet = buf; this.packetReceived = true; pxsim.board().bus.queue(this.PULSE_CABLE_COMPONENT_ID, this.PULSE_PACKET_EVENT); } } pxsim.CableState = CableState; function getCableState() { return pxsim.board().cableState; } pxsim.getCableState = getCableState; })(pxsim || (pxsim = {})); var pxsim; (function (pxsim) { let ThresholdState; (function (ThresholdState) { ThresholdState[ThresholdState["High"] = 0] = "High"; ThresholdState[ThresholdState["Low"] = 1] = "Low"; ThresholdState[ThresholdState["Normal"] = 2] = "Normal"; })(ThresholdState || (ThresholdState = {})); class AnalogSensorState { constructor(id, min = 0, max = 255, lowThreshold = 64, highThreshold = 192) { this.id = id; this.min = min; this.max = max; this.lowThreshold = lowThreshold; this.highThreshold = highThreshold; this.sensorUsed = false; this.state = ThresholdState.Normal; this.level = Math.ceil((max - min) / 2); } setUsed() { if (!this.sensorUsed) { this.sensorUsed = true; pxsim.runtime.queueDisplayUpdate(); } } setLevel(level) { this.level = this.clampValue(level); if (this.level >= this.highThreshold) { this.setState(ThresholdState.High); } else if (this.level <= this.lowThreshold) { this.setState(ThresholdState.Low); } else { this.setState(ThresholdState.Normal); } } getLevel() { return this.level; } setLowThreshold(value) { this.lowThreshold = this.clampValue(value); this.highThreshold = Math.max(this.lowThreshold + 1, this.highThreshold); } setHighThreshold(value) { this.highThreshold = this.clampValue(value); this.lowThreshold = Math.min(this.highThreshold - 1, this.lowThreshold); } clampValue(value) { if (value < this.min) { return this.min; } else if (value > this.max) { return this.max; } return value; } setState(state) { if (this.state === state) { return; } this.state = state; switch (state) { case ThresholdState.High: pxsim.board().bus.queue(this.id, 2 /* DAL.SENSOR_THRESHOLD_HIGH */); break; case ThresholdState.Low: pxsim.board().bus.queue(this.id, 1 /* DAL.SENSOR_THRESHOLD_LOW */); break; case ThresholdState.Normal: break; } } } pxsim.AnalogSensorState = An