pxt-ev3
Version:
LEGO MINDSTORMS EV3 for Microsoft MakeCode
1,322 lines • 249 kB
JavaScript
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