2.1.28, initiation update to PXT v5.28.24 (#54)
This commit is contained in:
committed by
Peli de Halleux
parent
38a964516e
commit
5c114a0c57
@ -1,37 +1,53 @@
|
||||
namespace pxsim.input {
|
||||
export function onGesture(gesture: number, handler: RefAction) {
|
||||
function accForGesture(gesture: number) {
|
||||
let b = board().accelerometerState;
|
||||
b.accelerometer.activate();
|
||||
|
||||
if (gesture == 11 && !b.useShake) { // SAKE
|
||||
if (gesture == 11 && !b.useShake) { // SHAKE
|
||||
b.useShake = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
export function onGesture(gesture: number, handler: RefAction) {
|
||||
const b = accForGesture(gesture);
|
||||
pxtcore.registerWithDal(DAL.MICROBIT_ID_GESTURE, gesture, handler);
|
||||
}
|
||||
|
||||
export function isGesture(gesture: number): boolean {
|
||||
const b = accForGesture(gesture);
|
||||
return b.accelerometer.getGesture() == gesture;
|
||||
}
|
||||
|
||||
export function acceleration(dimension: number): number {
|
||||
let b = board().accelerometerState;
|
||||
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()));
|
||||
case 0:
|
||||
acc.activate(AccelerometerFlag.X);
|
||||
return acc.getX();
|
||||
case 1:
|
||||
acc.activate(AccelerometerFlag.Y);
|
||||
return acc.getY();
|
||||
case 2:
|
||||
acc.activate(AccelerometerFlag.Z);
|
||||
return acc.getZ();
|
||||
default:
|
||||
acc.activate();
|
||||
return Math.floor(Math.sqrt(acc.instantaneousAccelerationSquared()));
|
||||
}
|
||||
}
|
||||
|
||||
export function rotation(kind: number): number {
|
||||
let b = board().accelerometerState;
|
||||
let acc = b.accelerometer;
|
||||
const b = board().accelerometerState;
|
||||
const acc = b.accelerometer;
|
||||
acc.activate();
|
||||
let x = acc.getX(MicroBitCoordinateSystem.NORTH_EAST_DOWN);
|
||||
let y = acc.getX(MicroBitCoordinateSystem.NORTH_EAST_DOWN);
|
||||
let z = acc.getX(MicroBitCoordinateSystem.NORTH_EAST_DOWN);
|
||||
const x = acc.getX(MicroBitCoordinateSystem.NORTH_EAST_DOWN);
|
||||
const y = acc.getY(MicroBitCoordinateSystem.NORTH_EAST_DOWN);
|
||||
const z = acc.getZ(MicroBitCoordinateSystem.NORTH_EAST_DOWN);
|
||||
|
||||
let roll = Math.atan2(y, z);
|
||||
let pitch = Math.atan(-x / (y * Math.sin(roll) + z * Math.cos(roll)));
|
||||
const roll = Math.atan2(y, z);
|
||||
const pitch = Math.atan(-x / (y * Math.sin(roll) + z * Math.cos(roll)));
|
||||
|
||||
let r = 0;
|
||||
switch (kind) {
|
||||
@ -99,6 +115,12 @@ namespace pxsim {
|
||||
NORTH_EAST_DOWN
|
||||
}
|
||||
|
||||
export enum AccelerometerFlag {
|
||||
X = 1,
|
||||
Y = 2,
|
||||
Z = 4
|
||||
}
|
||||
|
||||
export class Accelerometer {
|
||||
private sigma: number = 0; // the number of ticks that the instantaneous gesture has been stable.
|
||||
private lastGesture: number = 0; // the last, stable gesture recorded.
|
||||
@ -110,6 +132,7 @@ namespace pxsim {
|
||||
private id: number;
|
||||
public isActive = false;
|
||||
public sampleRange = 2;
|
||||
public flags: AccelerometerFlag = 0;
|
||||
|
||||
constructor(public runtime: Runtime) {
|
||||
this.id = DAL.MICROBIT_ID_ACCELEROMETER;
|
||||
@ -120,11 +143,13 @@ namespace pxsim {
|
||||
this.sampleRange = Math.max(1, Math.min(8, range));
|
||||
}
|
||||
|
||||
public activate() {
|
||||
public activate(flags?: AccelerometerFlag) {
|
||||
if (!this.isActive) {
|
||||
this.isActive = true;
|
||||
this.runtime.queueDisplayUpdate();
|
||||
}
|
||||
if (flags)
|
||||
this.flags |= flags;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,9 +224,8 @@ namespace pxsim {
|
||||
if (force < sq(DAL.MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE))
|
||||
return DAL.MICROBIT_ACCELEROMETER_EVT_FREEFALL;
|
||||
|
||||
// TODO: fix this
|
||||
//if (force > sq(DAL.MICROBIT_ACCELEROMETER_3G_TOLERANCE))
|
||||
// return DAL.MICROBIT_ACCELEROMETER_EVT_3G;
|
||||
if (force > sq(DAL.MICROBIT_ACCELEROMETER_3G_TOLERANCE))
|
||||
return DAL.MICROBIT_ACCELEROMETER_EVT_3G;
|
||||
|
||||
if (force > sq(DAL.MICROBIT_ACCELEROMETER_6G_TOLERANCE))
|
||||
return DAL.MICROBIT_ACCELEROMETER_EVT_6G;
|
||||
@ -223,10 +247,10 @@ namespace pxsim {
|
||||
return DAL.MICROBIT_ACCELEROMETER_EVT_TILT_UP;
|
||||
|
||||
if (this.getZ() < (-1000 + DAL.MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return DAL.MICROBIT_ACCELEROMETER_EVT_FACE_DOWN;
|
||||
return DAL.MICROBIT_ACCELEROMETER_EVT_FACE_UP;
|
||||
|
||||
if (this.getZ() > (1000 - DAL.MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
|
||||
return DAL.MICROBIT_ACCELEROMETER_EVT_FACE_UP;
|
||||
return DAL.MICROBIT_ACCELEROMETER_EVT_FACE_DOWN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -236,22 +260,28 @@ namespace pxsim {
|
||||
let g = this.instantaneousPosture();
|
||||
|
||||
// Perform some low pass filtering to reduce jitter from any detected effects
|
||||
if (g == this.currentGesture) {
|
||||
if (this.sigma < DAL.MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
|
||||
this.sigma++;
|
||||
}
|
||||
else {
|
||||
if (g != this.currentGesture) {
|
||||
this.currentGesture = g;
|
||||
this.sigma = 0;
|
||||
} else if (this.sigma < DAL.MICROBIT_ACCELEROMETER_GESTURE_DAMPING) {
|
||||
++this.sigma;
|
||||
}
|
||||
|
||||
// If we've reached threshold, update our record and raise the relevant event...
|
||||
if (this.currentGesture != this.lastGesture && this.sigma >= DAL.MICROBIT_ACCELEROMETER_GESTURE_DAMPING) {
|
||||
this.lastGesture = this.currentGesture;
|
||||
board().bus.queue(DAL.MICROBIT_ID_GESTURE, this.lastGesture);
|
||||
if (this.currentGesture !== this.lastGesture && this.sigma >= DAL.MICROBIT_ACCELEROMETER_GESTURE_DAMPING) {
|
||||
this.enqueueCurrentGesture();
|
||||
}
|
||||
}
|
||||
|
||||
forceGesture(gesture: number) {
|
||||
this.currentGesture = gesture;
|
||||
this.enqueueCurrentGesture();
|
||||
}
|
||||
|
||||
private enqueueCurrentGesture() {
|
||||
this.lastGesture = this.currentGesture;
|
||||
board().bus.queue(DAL.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.
|
||||
@ -363,6 +393,10 @@ namespace pxsim {
|
||||
return this.roll;
|
||||
}
|
||||
|
||||
getGesture(): number {
|
||||
return this.lastGesture;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -384,7 +418,11 @@ namespace pxsim {
|
||||
useShake = false;
|
||||
|
||||
constructor(runtime: Runtime) {
|
||||
this.accelerometer = new Accelerometer(runtime);
|
||||
this.accelerometer = new Accelerometer(runtime);
|
||||
}
|
||||
|
||||
shake() {
|
||||
this.accelerometer.forceGesture(DAL.MICROBIT_ACCELEROMETER_EVT_SHAKE); // SHAKE == 11
|
||||
}
|
||||
}
|
||||
}
|
201
sim/state/buttonpairsim.ts
Normal file
201
sim/state/buttonpairsim.ts
Normal file
@ -0,0 +1,201 @@
|
||||
namespace pxsim.visuals {
|
||||
export function mkBtnSvg(xy: Coord): SVGAndSize<SVGGElement> {
|
||||
let [innerCls, outerCls] = ["sim-button", "sim-button-outer"];
|
||||
const tabSize = PIN_DIST / 2.5;
|
||||
const pegR = PIN_DIST / 5;
|
||||
const btnR = PIN_DIST * .8;
|
||||
const pegMargin = PIN_DIST / 8;
|
||||
const plateR = PIN_DIST / 12;
|
||||
|
||||
const pegOffset = pegMargin + pegR;
|
||||
let [x, y] = xy;
|
||||
const left = x - tabSize / 2;
|
||||
const top = y - tabSize / 2;
|
||||
const plateH = 3 * PIN_DIST - tabSize;
|
||||
const plateW = 2 * PIN_DIST + tabSize;
|
||||
const plateL = left;
|
||||
const plateT = top + tabSize;
|
||||
const btnCX = plateL + plateW / 2;
|
||||
const btnCY = plateT + plateH / 2;
|
||||
|
||||
let btng = <SVGGElement>svg.elt("g");
|
||||
//tabs
|
||||
const mkTab = (x: number, y: number) => {
|
||||
svg.child(btng, "rect", { class: "sim-button-tab", x: x, y: y, width: tabSize, height: tabSize})
|
||||
}
|
||||
mkTab(left, top);
|
||||
mkTab(left + 2 * PIN_DIST, top);
|
||||
mkTab(left, top + 3 * PIN_DIST);
|
||||
mkTab(left + 2 * PIN_DIST, top + 3 * PIN_DIST);
|
||||
|
||||
//plate
|
||||
svg.child(btng, "rect", { class: outerCls, x: plateL, y: plateT, rx: plateR, ry: plateR, width: plateW, height: plateH });
|
||||
|
||||
//pegs
|
||||
const mkPeg = (x: number, y: number) => {
|
||||
svg.child(btng, "circle", { class: "sim-button-nut", cx: x, cy: y, r: pegR });
|
||||
}
|
||||
mkPeg(plateL + pegOffset, plateT + pegOffset)
|
||||
mkPeg(plateL + plateW - pegOffset, plateT + pegOffset)
|
||||
mkPeg(plateL + pegOffset, plateT + plateH - pegOffset)
|
||||
mkPeg(plateL + plateW - pegOffset, plateT + plateH - pegOffset)
|
||||
|
||||
//inner btn
|
||||
let innerBtn = svg.child(btng, "circle", { class: innerCls, cx: btnCX, cy: btnCY, r: btnR });
|
||||
|
||||
//return
|
||||
return { el: btng, y: top, x: left, w: plateW, h: plateH + 2 * tabSize };
|
||||
}
|
||||
export const BUTTON_PAIR_STYLE = `
|
||||
.sim-button {
|
||||
pointer-events: none;
|
||||
fill: #000;
|
||||
}
|
||||
.sim-button-outer:active ~ .sim-button,
|
||||
.sim-button-virtual:active {
|
||||
fill: #FFA500;
|
||||
}
|
||||
.sim-button-outer {
|
||||
cursor: pointer;
|
||||
fill: #979797;
|
||||
}
|
||||
.sim-button-outer:hover {
|
||||
stroke:gray;
|
||||
stroke-width: ${PIN_DIST / 5}px;
|
||||
}
|
||||
.sim-button-nut {
|
||||
fill:#000;
|
||||
pointer-events:none;
|
||||
}
|
||||
.sim-button-nut:hover {
|
||||
stroke:${PIN_DIST / 15}px solid #704A4A;
|
||||
}
|
||||
.sim-button-tab {
|
||||
fill:#FFF;
|
||||
pointer-events:none;
|
||||
}
|
||||
.sim-button-virtual {
|
||||
cursor: pointer;
|
||||
fill: rgba(255, 255, 255, 0.6);
|
||||
stroke: rgba(255, 255, 255, 1);
|
||||
stroke-width: ${PIN_DIST / 5}px;
|
||||
}
|
||||
.sim-button-virtual:hover {
|
||||
stroke: rgba(128, 128, 128, 1);
|
||||
}
|
||||
.sim-text-virtual {
|
||||
fill: #000;
|
||||
pointer-events:none;
|
||||
}
|
||||
`;
|
||||
export class ButtonPairView implements IBoardPart<ButtonPairState> {
|
||||
public element: SVGElement;
|
||||
public defs: SVGElement[];
|
||||
public style = BUTTON_PAIR_STYLE;
|
||||
private state: ButtonPairState;
|
||||
private bus: EventBus;
|
||||
private aBtn: SVGGElement;
|
||||
private bBtn: SVGGElement;
|
||||
private abBtn: SVGGElement;
|
||||
|
||||
public init(bus: EventBus, state: ButtonPairState) {
|
||||
this.state = state;
|
||||
this.bus = bus;
|
||||
this.defs = [];
|
||||
this.element = this.mkBtns();
|
||||
this.updateState();
|
||||
this.attachEvents();
|
||||
}
|
||||
|
||||
public moveToCoord(xy: Coord) {
|
||||
let btnWidth = PIN_DIST * 3;
|
||||
let [x, y] = xy;
|
||||
translateEl(this.aBtn, [x, y])
|
||||
translateEl(this.bBtn, [x + btnWidth, y])
|
||||
translateEl(this.abBtn, [x + PIN_DIST * 1.5, y + PIN_DIST * 4])
|
||||
}
|
||||
|
||||
public updateState() {
|
||||
let stateBtns = [this.state.aBtn, this.state.bBtn, this.state.abBtn];
|
||||
let svgBtns = [this.aBtn, this.bBtn, this.abBtn];
|
||||
|
||||
if (this.state.usesButtonAB && this.abBtn.style.visibility != "visible") {
|
||||
this.abBtn.style.visibility = "visible";
|
||||
}
|
||||
}
|
||||
|
||||
public updateTheme() {}
|
||||
|
||||
private mkBtns() {
|
||||
this.aBtn = mkBtnSvg([0, 0]).el;
|
||||
this.bBtn = mkBtnSvg([0, 0]).el;
|
||||
|
||||
const mkVirtualBtn = () => {
|
||||
const numPins = 2;
|
||||
const w = PIN_DIST * 2.8;
|
||||
const offset = (w - (numPins * PIN_DIST)) / 2;
|
||||
const corner = PIN_DIST / 2;
|
||||
const cx = 0 - offset + w / 2;
|
||||
const cy = cx;
|
||||
const txtSize = PIN_DIST * 1.3;
|
||||
const x = -offset;
|
||||
const y = -offset;
|
||||
const txtXOff = PIN_DIST / 7;
|
||||
const txtYOff = PIN_DIST / 10;
|
||||
|
||||
let btng = <SVGGElement>svg.elt("g");
|
||||
let btn = svg.child(btng, "rect", { class: "sim-button-virtual", x: x, y: y, rx: corner, ry: corner, width: w, height: w});
|
||||
let btnTxt = mkTxt(cx + txtXOff, cy + txtYOff, txtSize, 0, "A+B");
|
||||
|
||||
U.addClass(btnTxt, "sim-text")
|
||||
U.addClass(btnTxt, "sim-text-virtual");
|
||||
btng.appendChild(btnTxt);
|
||||
|
||||
return btng;
|
||||
}
|
||||
|
||||
this.abBtn = mkVirtualBtn();
|
||||
this.abBtn.style.visibility = "hidden";
|
||||
|
||||
let el = svg.elt("g");
|
||||
U.addClass(el, "sim-buttonpair")
|
||||
el.appendChild(this.aBtn);
|
||||
el.appendChild(this.bBtn);
|
||||
el.appendChild(this.abBtn);
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
private attachEvents() {
|
||||
let btnStates = [this.state.aBtn, this.state.bBtn];
|
||||
let btnSvgs = [this.aBtn, this.bBtn];
|
||||
btnSvgs.forEach((btn, index) => {
|
||||
pxsim.pointerEvents.down.forEach(evid => btn.addEventListener(evid, ev => {
|
||||
btnStates[index].pressed = true;
|
||||
}))
|
||||
btn.addEventListener(pointerEvents.leave, ev => {
|
||||
btnStates[index].pressed = false;
|
||||
})
|
||||
btn.addEventListener(pointerEvents.up, ev => {
|
||||
btnStates[index].pressed = false;
|
||||
this.bus.queue(btnStates[index].id, this.state.props.BUTTON_EVT_UP);
|
||||
this.bus.queue(btnStates[index].id, this.state.props.BUTTON_EVT_CLICK);
|
||||
})
|
||||
})
|
||||
let updateBtns = (s: boolean) => {
|
||||
btnStates.forEach(b => b.pressed = s)
|
||||
};
|
||||
pxsim.pointerEvents.down.forEach(evid => this.abBtn.addEventListener(evid, ev => {
|
||||
updateBtns(true);
|
||||
}));
|
||||
this.abBtn.addEventListener(pointerEvents.leave, ev => {
|
||||
updateBtns(false);
|
||||
})
|
||||
this.abBtn.addEventListener(pointerEvents.up, ev => {
|
||||
updateBtns(false);
|
||||
this.bus.queue(this.state.abBtn.id, this.state.props.BUTTON_EVT_UP);
|
||||
this.bus.queue(this.state.abBtn.id, this.state.props.BUTTON_EVT_CLICK);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ namespace pxsim.input {
|
||||
let pin = getPin(pinId);
|
||||
if (!pin) return;
|
||||
pin.isTouched();
|
||||
runtime.queueDisplayUpdate();
|
||||
pxtcore.registerWithDal(pin.id, DAL.MICROBIT_BUTTON_EVT_CLICK, handler);
|
||||
}
|
||||
|
||||
@ -10,6 +11,7 @@ namespace pxsim.input {
|
||||
let pin = getPin(pinId);
|
||||
if (!pin) return;
|
||||
pin.isTouched();
|
||||
runtime.queueDisplayUpdate();
|
||||
pxtcore.registerWithDal(pin.id, DAL.MICROBIT_BUTTON_EVT_UP, handler);
|
||||
}
|
||||
|
||||
@ -29,7 +31,7 @@ namespace pxsim {
|
||||
namespace pxsim.pins {
|
||||
export function digitalReadPin(pinId: number): number {
|
||||
let pin = getPin(pinId);
|
||||
if (!pin) return;
|
||||
if (!pin) return -1;
|
||||
pin.mode = PinFlags.Digital | PinFlags.Input;
|
||||
return pin.value > 100 ? 1 : 0;
|
||||
}
|
||||
@ -50,7 +52,7 @@ namespace pxsim.pins {
|
||||
|
||||
export function analogReadPin(pinId: number): number {
|
||||
let pin = getPin(pinId);
|
||||
if (!pin) return;
|
||||
if (!pin) return -1;
|
||||
pin.mode = PinFlags.Analog | PinFlags.Input;
|
||||
return pin.value || 0;
|
||||
}
|
||||
@ -76,7 +78,7 @@ namespace pxsim.pins {
|
||||
if (!pin) return;
|
||||
|
||||
analogSetPeriod(pinId, 20000);
|
||||
pin.servoAngle = Math.max(0, Math.min(180, value));
|
||||
pin.servoAngle = value;
|
||||
}
|
||||
|
||||
export function servoSetPulse(pinId: number, micros: number) {
|
||||
|
89
sim/state/edgeconnectorsim.ts
Normal file
89
sim/state/edgeconnectorsim.ts
Normal file
@ -0,0 +1,89 @@
|
||||
namespace pxsim {
|
||||
export enum PinFlags {
|
||||
Unused = 0,
|
||||
Digital = 0x0001,
|
||||
Analog = 0x0002,
|
||||
Input = 0x0004,
|
||||
Output = 0x0008,
|
||||
Touch = 0x0010
|
||||
}
|
||||
|
||||
export class Pin {
|
||||
constructor(public id: number) { }
|
||||
touched = false;
|
||||
value = 0;
|
||||
period = 0;
|
||||
servoAngle = 0;
|
||||
mode = PinFlags.Unused;
|
||||
pitch = false;
|
||||
pull = 0; // PullDown
|
||||
|
||||
digitalReadPin(): number {
|
||||
this.mode = PinFlags.Digital | PinFlags.Input;
|
||||
return this.value > 100 ? 1 : 0;
|
||||
}
|
||||
|
||||
digitalWritePin(value: number) {
|
||||
this.mode = PinFlags.Digital | PinFlags.Output;
|
||||
this.value = value > 0 ? 200 : 0;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
|
||||
setPull(pull: number) {
|
||||
this.pull = pull;
|
||||
}
|
||||
|
||||
analogReadPin(): number {
|
||||
this.mode = PinFlags.Analog | PinFlags.Input;
|
||||
return this.value || 0;
|
||||
}
|
||||
|
||||
analogWritePin(value: number) {
|
||||
value = value >> 0;
|
||||
this.mode = PinFlags.Analog | PinFlags.Output;
|
||||
this.value = Math.max(0, Math.min(1023, value));
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
|
||||
analogSetPeriod(micros: number) {
|
||||
micros = micros >> 0;
|
||||
this.mode = PinFlags.Analog | PinFlags.Output;
|
||||
this.period = micros;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
|
||||
servoWritePin(value: number) {
|
||||
value = value >> 0;
|
||||
this.analogSetPeriod(20000);
|
||||
this.servoAngle = Math.max(0, Math.min(180, value));
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
|
||||
servoSetPulse(pinId: number, micros: number) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
isTouched(): boolean {
|
||||
this.mode = PinFlags.Touch | PinFlags.Analog | PinFlags.Input;
|
||||
return this.touched;
|
||||
}
|
||||
}
|
||||
|
||||
export interface EdgeConnectorProps {
|
||||
pins: number[];
|
||||
servos?: { [name: string]: number; }
|
||||
}
|
||||
|
||||
export class EdgeConnectorState {
|
||||
pins: Pin[];
|
||||
|
||||
constructor(public props: EdgeConnectorProps) {
|
||||
this.pins = props.pins.map(id => id != undefined ? new Pin(id) : null);
|
||||
}
|
||||
|
||||
public getPin(id: number) {
|
||||
return this.pins.filter(p => p && p.id == id)[0] || null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -15,4 +15,10 @@ namespace pxsim.files {
|
||||
const b = board();
|
||||
b.fileSystem.remove(filename);
|
||||
}
|
||||
export function readToSerial(filename: string) {
|
||||
const b = board();
|
||||
let f = b.fileSystem.files[filename];
|
||||
if (f)
|
||||
b.serialState.writeSerial(f);
|
||||
}
|
||||
}
|
@ -28,17 +28,24 @@ namespace pxsim {
|
||||
this.data = data;
|
||||
}
|
||||
public print() {
|
||||
// console.debug(`Image id:${this.id} refs:${this.refcnt} size:${this.width}x${Image.height}`)
|
||||
console.debug(`Image id:${this.id} size:${this.width}x${Image.height}`)
|
||||
}
|
||||
public get(x: number, y: number): number {
|
||||
x = x >> 0;
|
||||
y = y >> 0;
|
||||
if (x < 0 || x >= this.width || y < 0 || y >= 5) return 0;
|
||||
return this.data[y * this.width + x];
|
||||
}
|
||||
public set(x: number, y: number, v: number) {
|
||||
x = x >> 0;
|
||||
y = y >> 0;
|
||||
if (x < 0 || x >= this.width || y < 0 || y >= 5) return;
|
||||
this.data[y * this.width + x] = Math.max(0, Math.min(255, v));
|
||||
}
|
||||
public copyTo(xSrcIndex: number, length: number, target: Image, xTargetIndex: number): void {
|
||||
xSrcIndex = xSrcIndex >> 0;
|
||||
length = length >> 0;
|
||||
xTargetIndex = xTargetIndex >> 0;
|
||||
for (let x = 0; x < length; x++) {
|
||||
for (let y = 0; y < 5; y++) {
|
||||
let value = this.get(xSrcIndex + x, y);
|
||||
@ -47,12 +54,14 @@ namespace pxsim {
|
||||
}
|
||||
}
|
||||
public shiftLeft(cols: number) {
|
||||
cols = cols >> 0;
|
||||
for (let x = 0; x < this.width; ++x)
|
||||
for (let y = 0; y < 5; ++y)
|
||||
this.set(x, y, x < this.width - cols ? this.get(x + cols, y) : 0);
|
||||
}
|
||||
|
||||
public shiftRight(cols: number) {
|
||||
cols = cols >> 0;
|
||||
for (let x = this.width - 1; x >= 0; --x)
|
||||
for (let y = 0; y < 5; ++y)
|
||||
this.set(x, y, x >= cols ? this.get(x - cols, y) : 0);
|
||||
@ -65,12 +74,13 @@ namespace pxsim {
|
||||
}
|
||||
|
||||
export function createInternalImage(width: number): Image {
|
||||
width = width >> 0;
|
||||
let img = createImage(width)
|
||||
pxsim.noLeakTracking(img)
|
||||
return img
|
||||
}
|
||||
|
||||
export function createImage(width: number): Image {
|
||||
width = width >> 0;
|
||||
return new Image(width, new Array(width * 5));
|
||||
}
|
||||
|
||||
@ -131,9 +141,12 @@ namespace pxsim.images {
|
||||
namespace pxsim.ImageMethods {
|
||||
export function showImage(leds: Image, offset: number, interval: number) {
|
||||
pxtrt.nullCheck(leds)
|
||||
offset = offset >> 0;
|
||||
interval = interval >> 0;
|
||||
let cb = getResume();
|
||||
let first = true;
|
||||
|
||||
leds = clampPixelBrightness(leds);
|
||||
board().ledMatrixState.animationQ.enqueue({
|
||||
interval,
|
||||
frame: () => {
|
||||
@ -150,7 +163,9 @@ namespace pxsim.ImageMethods {
|
||||
|
||||
export function plotImage(leds: Image, offset: number): void {
|
||||
pxtrt.nullCheck(leds)
|
||||
offset = offset >> 0;
|
||||
|
||||
leds = clampPixelBrightness(leds);
|
||||
board().ledMatrixState.animationQ.enqueue({
|
||||
interval: 0,
|
||||
frame: () => {
|
||||
@ -205,12 +220,15 @@ namespace pxsim.ImageMethods {
|
||||
|
||||
export function scrollImage(leds: Image, stride: number, interval: number): void {
|
||||
pxtrt.nullCheck(leds)
|
||||
stride = stride >> 0;
|
||||
interval = interval >> 0;
|
||||
if (stride == 0) stride = 1;
|
||||
|
||||
let cb = getResume();
|
||||
let off = stride > 0 ? 0 : leds.width - 1;
|
||||
let display = board().ledMatrixState.image;
|
||||
|
||||
leds = clampPixelBrightness(leds);
|
||||
board().ledMatrixState.animationQ.enqueue({
|
||||
interval: interval,
|
||||
frame: () => {
|
||||
@ -230,10 +248,27 @@ namespace pxsim.ImageMethods {
|
||||
whenDone: cb
|
||||
})
|
||||
}
|
||||
|
||||
function clampPixelBrightness(img: Image): Image {
|
||||
let res = img;
|
||||
if (led.displayMode() === DisplayMode.greyscale && led.brightness() < 0xff) {
|
||||
res = new Image(img.width, img.data);
|
||||
const b = led.brightness();
|
||||
for (let x = 0; x < res.width; ++x) {
|
||||
for (let y = 0; y < 5; ++y) {
|
||||
if (pixelBrightness(res, x, y) > b) {
|
||||
setPixelBrightness(res, x, y, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.basic {
|
||||
export function showNumber(x: number, interval: number) {
|
||||
interval = interval >> 0;
|
||||
if (interval <= 0)
|
||||
interval = 1;
|
||||
let leds = createImageFromString(x.toString());
|
||||
@ -242,19 +277,21 @@ namespace pxsim.basic {
|
||||
}
|
||||
|
||||
export function showString(s: string, interval: number) {
|
||||
interval = interval >> 0;
|
||||
if (interval <= 0)
|
||||
interval = 1;
|
||||
if (s.length == 0) {
|
||||
clearScreen();
|
||||
pause(interval * 5);
|
||||
} else if (s.length > 1) {
|
||||
ImageMethods.scrollImage(createImageFromString(s + " "), 1, interval);
|
||||
} else {
|
||||
if (s.length == 1) showLeds(createImageFromString(s), 0);
|
||||
else ImageMethods.scrollImage(createImageFromString(s + " "), 1, interval);
|
||||
showLeds(createImageFromString(s), interval * 5);
|
||||
}
|
||||
}
|
||||
|
||||
export function showLeds(leds: Image, delay: number): void {
|
||||
showAnimation(leds, delay);
|
||||
export function showLeds(leds: Image, interval: number): void {
|
||||
showAnimation(leds, interval);
|
||||
}
|
||||
|
||||
export function clearScreen() {
|
||||
@ -279,9 +316,10 @@ namespace pxsim.led {
|
||||
|
||||
export function plotBrightness(x: number, y: number, brightness: number) {
|
||||
const state = board().ledMatrixState;
|
||||
brightness = Math.max(0, Math.min(0xff, brightness));
|
||||
brightness = brightness >> 0;
|
||||
brightness = Math.max(0, Math.min(led.brightness(), brightness));
|
||||
if (brightness != 0 && brightness != 0xff && state.displayMode != DisplayMode.greyscale)
|
||||
state.displayMode = DisplayMode.greyscale;
|
||||
state.displayMode = DisplayMode.greyscale;
|
||||
state.image.set(x, y, brightness);
|
||||
runtime.queueDisplayUpdate()
|
||||
}
|
||||
@ -300,6 +338,7 @@ namespace pxsim.led {
|
||||
}
|
||||
|
||||
export function setBrightness(value: number): void {
|
||||
value = value >> 0;
|
||||
board().ledMatrixState.brigthness = Math.max(0, Math.min(255, value));
|
||||
runtime.queueDisplayUpdate()
|
||||
}
|
||||
|
83
sim/state/microservo.ts
Normal file
83
sim/state/microservo.ts
Normal file
@ -0,0 +1,83 @@
|
||||
namespace pxsim.visuals {
|
||||
function createMicroServoElement() {
|
||||
return svg.parseString(`
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="svg2" width="112.188" height="299.674">
|
||||
<g id="layer1" stroke-linecap="round" stroke-linejoin="round" transform="scale(0.8)">
|
||||
<path id="path8212" fill="#0061ff" stroke-width="6.6" d="M.378 44.61v255.064h112.188V44.61H.378z"/>
|
||||
<path id="crankbase" fill="#00f" stroke-width="6.6" d="M56.57 88.047C25.328 88.047 0 113.373 0 144.615c.02 22.352 11.807 42.596 32.238 51.66.03 3.318.095 5.24.088 7.938 0 13.947 11.307 25.254 25.254 25.254 13.947 0 25.254-11.307 25.254-25.254-.006-2.986-.415-5.442-.32-8.746 19.487-9.45 30.606-29.195 30.625-50.852 0-31.24-25.33-56.568-56.57-56.568z"/>
|
||||
<path id="lowertip" fill="#00a2ff" stroke-width="2" d="M.476 260.78v38.894h53.82v-10.486a6.82 6.566 0 0 1-4.545-6.182 6.82 6.566 0 0 1 6.82-6.566 6.82 6.566 0 0 1 6.82 6.566 6.82 6.566 0 0 1-4.545 6.182v10.486h53.82V260.78H.475z"/>
|
||||
<path id="uppertip" fill="#00a2ff" stroke-width="2" d="M112.566 83.503V44.61h-53.82v10.487a6.82 6.566 0 0 1 4.544 6.18 6.82 6.566 0 0 1-6.818 6.568 6.82 6.566 0 0 1-6.82-6.567 6.82 6.566 0 0 1 4.546-6.18V44.61H.378v38.893h112.188z"/>
|
||||
<path id="VCC" fill="red" stroke-width="2" d="M53.72 21.93h5.504v22.627H53.72z"/>
|
||||
<path id="LOGIC" fill="#fc0" stroke-width="2" d="M47.3 21.93h5.503v22.627H47.3z"/>
|
||||
<path id="GND" fill="#a02c2c" stroke-width="2" d="M60.14 21.93h5.505v22.627H60.14z"/>
|
||||
<path id="connector" fill="#111" stroke-width="2" d="M45.064 0a1.488 1.488 0 0 0-1.488 1.488v24.5a1.488 1.488 0 0 0 1.488 1.487h22.71a1.488 1.488 0 0 0 1.49-1.488v-24.5A1.488 1.488 0 0 0 67.774 0h-22.71z"/>
|
||||
<g id="crank" transform="translate(0 -752.688)">
|
||||
<path id="arm" fill="#ececec" stroke="#000" stroke-width="1.372" d="M47.767 880.88c-4.447 1.162-8.412 8.278-8.412 18.492s3.77 18.312 8.412 18.494c8.024.314 78.496 5.06 78.51-16.952.012-22.013-74.377-21.117-78.51-20.035z"/>
|
||||
<circle id="path8216" cx="56.661" cy="899.475" r="8.972" fill="gray" stroke-width="2"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
`).firstElementChild as SVGGElement;
|
||||
}
|
||||
|
||||
export function mkMicroServoPart(xy: Coord = [0, 0]): SVGElAndSize {
|
||||
return { el: createMicroServoElement(), x: xy[0], y: xy[1], w: 112.188, h: 299.674 };
|
||||
}
|
||||
|
||||
export class MicroServoView implements IBoardPart<EdgeConnectorState> {
|
||||
public style: string = "";
|
||||
public overElement: SVGElement = undefined;
|
||||
public element: SVGElement;
|
||||
public defs: SVGElement[] = [];
|
||||
public state: EdgeConnectorState;
|
||||
public bus: EventBus;
|
||||
private currentAngle = 0;
|
||||
private targetAngle = 0;
|
||||
private lastAngleTime = 0;
|
||||
private pin: number;
|
||||
|
||||
private crankEl: SVGGElement;
|
||||
private crankTransform: string;
|
||||
|
||||
public init(bus: EventBus, state: EdgeConnectorState, svgEl: SVGSVGElement, otherParams: Map<string>) {
|
||||
this.state = state;
|
||||
this.pin = this.state.props.servos[
|
||||
pxsim.readPin(otherParams["name"] || otherParams["pin"])
|
||||
];
|
||||
this.bus = bus;
|
||||
this.defs = [];
|
||||
this.initDom();
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
initDom() {
|
||||
this.element = createMicroServoElement();
|
||||
this.crankEl = this.element.querySelector("#crank") as SVGGElement;
|
||||
this.crankTransform = this.crankEl.getAttribute("transform");
|
||||
}
|
||||
|
||||
moveToCoord(xy: visuals.Coord): void {
|
||||
let [x, y] = xy;
|
||||
translateEl(this.element, [x, y])
|
||||
}
|
||||
updateState(): void {
|
||||
this.targetAngle = 180.0 - this.state.getPin(this.pin).servoAngle;
|
||||
if (this.targetAngle != this.currentAngle) {
|
||||
const now = U.now();
|
||||
const cx = 56.661;
|
||||
const cy = 899.475;
|
||||
const speed = 300; // 0.1s/60 degree
|
||||
const dt = Math.min(now - this.lastAngleTime, 50) / 1000;
|
||||
const delta = this.targetAngle - this.currentAngle;
|
||||
this.currentAngle += Math.min(Math.abs(delta), speed * dt) * (delta > 0 ? 1 : -1);
|
||||
this.crankEl.setAttribute("transform", this.crankTransform
|
||||
+ ` rotate(${this.currentAngle}, ${cx}, ${cy})`)
|
||||
this.lastAngleTime = now;
|
||||
setTimeout(() => runtime.updateDisplay(), 20);
|
||||
}
|
||||
}
|
||||
updateTheme(): void {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
6
sim/state/midi.ts
Normal file
6
sim/state/midi.ts
Normal file
@ -0,0 +1,6 @@
|
||||
namespace pxsim.control {
|
||||
export function __midiSend(data: RefBuffer) {
|
||||
const b = board();
|
||||
pxsim.AudioContextManager.sendMidiMessage(data);
|
||||
}
|
||||
}
|
@ -35,8 +35,13 @@ namespace pxsim.basic {
|
||||
namespace pxsim.control {
|
||||
export var inBackground = thread.runInBackground;
|
||||
|
||||
export function createBuffer(sz: number) {
|
||||
return pxsim.BufferMethods.createBuffer(sz)
|
||||
}
|
||||
|
||||
export function reset() {
|
||||
U.userError("reset not implemented in simulator yet")
|
||||
const cb = getResume();
|
||||
pxsim.runtime.restart();
|
||||
}
|
||||
|
||||
export function waitMicros(micros: number) {
|
||||
@ -58,6 +63,13 @@ namespace pxsim.control {
|
||||
}
|
||||
|
||||
export function onEvent(id: number, evid: number, handler: RefAction) {
|
||||
if (id == DAL.MICROBIT_ID_BUTTON_AB) {
|
||||
const b = board().buttonPairState;
|
||||
if (!b.usesButtonAB) {
|
||||
b.usesButtonAB = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
pxtcore.registerWithDal(id, evid, handler)
|
||||
}
|
||||
|
||||
@ -65,6 +77,14 @@ namespace pxsim.control {
|
||||
// TODO mode?
|
||||
board().bus.queue(id, evid)
|
||||
}
|
||||
|
||||
export function eventTimestamp() {
|
||||
return board().bus.getLastEventTime()
|
||||
}
|
||||
|
||||
export function eventValue() {
|
||||
return board().bus.getLastEventValue()
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.pxtcore {
|
||||
@ -78,7 +98,12 @@ namespace pxsim.input {
|
||||
return runtime.runningTime();
|
||||
}
|
||||
|
||||
export function calibrate() {
|
||||
export function runningTimeMicros(): number {
|
||||
return runtime.runningTimeUs();
|
||||
}
|
||||
|
||||
export function calibrateCompass() {
|
||||
// device calibrates...
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,6 +131,18 @@ namespace pxsim.pins {
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function spiFrequency(f: number): void {
|
||||
// TODO
|
||||
}
|
||||
|
||||
export function spiFormat(bits: number, mode: number): void {
|
||||
// TODO
|
||||
}
|
||||
|
||||
export function spiPins(mosi: number, miso: number, sck: number) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
export function i2cReadBuffer(address: number, size: number, repeat?: boolean): RefBuffer {
|
||||
// fake reading zeros
|
||||
return createBuffer(size)
|
||||
@ -137,7 +174,7 @@ namespace pxsim.devices {
|
||||
export function onSignalStrengthChanged(action: number) {
|
||||
// TODO
|
||||
}
|
||||
export function signalStrength() : number {
|
||||
export function signalStrength(): number {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
@ -168,25 +205,34 @@ namespace pxsim.bluetooth {
|
||||
export function startUartService(): void {
|
||||
// TODO
|
||||
}
|
||||
export function uartWrite(s : string): void {
|
||||
export function uartWriteString(s: string): void {
|
||||
serial.writeString(s)
|
||||
}
|
||||
|
||||
export function uartWriteBuffer(b: RefBuffer): void {
|
||||
serial.writeBuffer(b);
|
||||
}
|
||||
|
||||
export function uartReadBuffer(): RefBuffer {
|
||||
return pins.createBuffer(0);
|
||||
}
|
||||
|
||||
export function uartReadUntil(del: string): string {
|
||||
return serial.readUntil(del);
|
||||
}
|
||||
export function onDataReceived(delimiters: string, handler: RefAction) {
|
||||
export function onUartDataReceived(delimiters: string, handler: RefAction) {
|
||||
let b = board();
|
||||
b.bus.listen(DAL.MICROBIT_ID_BLE_UART, DAL.MICROBIT_UART_S_EVT_DELIM_MATCH, handler);
|
||||
}
|
||||
export function onBluetoothConnected(a : RefAction) {
|
||||
export function onBluetoothConnected(a: RefAction) {
|
||||
// TODO
|
||||
}
|
||||
export function onBluetoothDisconnected(a : RefAction) {
|
||||
export function onBluetoothDisconnected(a: RefAction) {
|
||||
// TODO
|
||||
}
|
||||
export function advertiseUrl(url: string, power: number, connectable: boolean) { }
|
||||
export function advertiseUidBuffer(nsAndInstance: Buffer, power: number, connectable: boolean) { }
|
||||
export function advertiseUidBuffer(nsAndInstance: RefBuffer, power: number, connectable: boolean) { }
|
||||
export function stopAdvertising() { }
|
||||
export function setTransmitPower(power: number) {}
|
||||
export function setTransmitPower(power: number) { }
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
namespace pxsim {
|
||||
export function sendBufferAsm(buffer: Buffer, pin: DigitalPin) {
|
||||
export function sendBufferAsm(buffer: RefBuffer, pin: DigitalPin) {
|
||||
let b = board();
|
||||
if (b) {
|
||||
let np = b.neopixelState;
|
||||
if (np) {
|
||||
let buf = <Uint8Array>(<any>buffer).data;
|
||||
np.updateBuffer(buf, pin);
|
||||
let buf = buffer.data;
|
||||
np.updateBuffer(buf as any, pin); // TODO this is wrong
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,11 @@ namespace pxsim {
|
||||
time: number;
|
||||
}
|
||||
|
||||
// Extends interface in pxt-core
|
||||
export interface SimulatorRadioPacketPayload {
|
||||
bufferData?: Uint8Array;
|
||||
}
|
||||
|
||||
export class RadioDatagram {
|
||||
datagram: PacketBuffer[] = [];
|
||||
lastReceived: PacketBuffer = RadioDatagram.defaultPacket();
|
||||
@ -24,8 +29,9 @@ namespace pxsim {
|
||||
const b = board();
|
||||
Runtime.postMessage(<SimulatorRadioPacketMessage>{
|
||||
type: "radiopacket",
|
||||
rssi: 70, // Not yet supported
|
||||
serial: b.radioState.bus.transmitSerialNumber ? pxsim.control.deviceSerialNumber() : 0,
|
||||
broadcast: true,
|
||||
rssi: -42, // -42 is the strongest signal
|
||||
serial: b.radioState.transmitSerialNumber ? pxsim.control.deviceSerialNumber() : 0,
|
||||
time: new Date().getTime(),
|
||||
payload
|
||||
})
|
||||
@ -42,22 +48,31 @@ namespace pxsim {
|
||||
rssi: -1,
|
||||
serial: 0,
|
||||
time: 0,
|
||||
payload: { type: -1, groupId: 0 }
|
||||
payload: { type: -1, groupId: 0, bufferData: new Uint8Array(0) }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class RadioBus {
|
||||
// uint8_t radioDefaultGroup = MICROBIT_RADIO_DEFAULT_GROUP;
|
||||
export class RadioState {
|
||||
power = 0;
|
||||
transmitSerialNumber = false;
|
||||
datagram: RadioDatagram;
|
||||
groupId: number;
|
||||
band: number;
|
||||
|
||||
constructor(private runtime: Runtime) {
|
||||
constructor(runtime: Runtime) {
|
||||
this.datagram = new RadioDatagram(runtime);
|
||||
this.power = 6; // default value
|
||||
this.groupId = 0;
|
||||
this.band = 7; // https://github.com/lancaster-university/microbit-dal/blob/master/inc/core/MicroBitConfig.h#L320
|
||||
}
|
||||
|
||||
public setGroup(id: number) {
|
||||
this.groupId = id & 0xff; // byte only
|
||||
}
|
||||
|
||||
setTransmitPower(power: number) {
|
||||
power = power | 0;
|
||||
this.power = Math.max(0, Math.min(7, power));
|
||||
}
|
||||
|
||||
@ -65,54 +80,33 @@ namespace pxsim {
|
||||
this.transmitSerialNumber = !!sn;
|
||||
}
|
||||
|
||||
broadcast(msg: number, groupId: number) {
|
||||
setFrequencyBand(band: number) {
|
||||
band = band | 0;
|
||||
if (band < 0 || band > 83) return;
|
||||
this.band = band;
|
||||
}
|
||||
|
||||
raiseEvent(id: number, eventid: number) {
|
||||
Runtime.postMessage(<SimulatorEventBusMessage>{
|
||||
type: "eventbus",
|
||||
id: DAL.MES_BROADCAST_GENERAL_ID,
|
||||
eventid: msg,
|
||||
broadcast: true,
|
||||
id,
|
||||
eventid,
|
||||
power: this.power,
|
||||
group: groupId
|
||||
group: this.groupId
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export class RadioState {
|
||||
bus: RadioBus;
|
||||
groupId: number;
|
||||
|
||||
constructor(runtime: Runtime) {
|
||||
this.bus = new RadioBus(runtime);
|
||||
this.groupId = 0;
|
||||
}
|
||||
|
||||
public setGroup(id: number) {
|
||||
this.groupId = id & 0xff; // byte only
|
||||
}
|
||||
|
||||
public broadcast(msg: number) {
|
||||
this.bus.broadcast(msg, this.groupId)
|
||||
}
|
||||
|
||||
public receivePacket(packet: SimulatorRadioPacketMessage) {
|
||||
receivePacket(packet: SimulatorRadioPacketMessage) {
|
||||
if (this.groupId == packet.payload.groupId)
|
||||
this.bus.datagram.queue(packet)
|
||||
this.datagram.queue(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.radio {
|
||||
enum PacketPayloadType {
|
||||
NUMBER = 0,
|
||||
VALUE = 1,
|
||||
STRING = 2
|
||||
}
|
||||
|
||||
export function broadcastMessage(msg: number): void {
|
||||
board().radioState.broadcast(msg);
|
||||
}
|
||||
|
||||
export function onBroadcastMessageReceived(msg: number, handler: RefAction): void {
|
||||
pxtcore.registerWithDal(DAL.MES_BROADCAST_GENERAL_ID, msg, handler);
|
||||
export function raiseEvent(id: number, eventid: number): void {
|
||||
board().radioState.raiseEvent(id, eventid);
|
||||
}
|
||||
|
||||
export function setGroup(id: number): void {
|
||||
@ -120,99 +114,34 @@ namespace pxsim.radio {
|
||||
}
|
||||
|
||||
export function setTransmitPower(power: number): void {
|
||||
board().radioState.bus.setTransmitPower(power);
|
||||
board().radioState.setTransmitPower(power);
|
||||
}
|
||||
|
||||
export function setTransmitSerialNumber(transmit: boolean): void {
|
||||
board().radioState.bus.setTransmitSerialNumber(transmit);
|
||||
export function setFrequencyBand(band: number) {
|
||||
board().radioState.setFrequencyBand(band);
|
||||
}
|
||||
|
||||
export function sendNumber(value: number): void {
|
||||
board().radioState.bus.datagram.send({
|
||||
type: PacketPayloadType.NUMBER,
|
||||
export function sendRawPacket(buf: RefBuffer) {
|
||||
let cb = getResume();
|
||||
board().radioState.datagram.send({
|
||||
type: 0,
|
||||
groupId: board().radioState.groupId,
|
||||
numberData: value,
|
||||
bufferData: buf.data
|
||||
});
|
||||
setTimeout(cb, 1);
|
||||
}
|
||||
|
||||
export function sendString(msg: string): void {
|
||||
msg = msg.substr(0, 19);
|
||||
board().radioState.bus.datagram.send({
|
||||
type: PacketPayloadType.STRING,
|
||||
groupId: board().radioState.groupId,
|
||||
stringData: msg,
|
||||
});
|
||||
}
|
||||
|
||||
export function writeValueToSerial(): void {
|
||||
const b = board();
|
||||
writePacketToSerial(b, b.radioState.bus.datagram.recv())
|
||||
}
|
||||
|
||||
export function writeReceivedPacketToSerial(): void {
|
||||
const b = board();
|
||||
writePacketToSerial(b, b.radioState.bus.datagram.lastReceived);
|
||||
}
|
||||
|
||||
export function sendValue(name: string, value: number) {
|
||||
name = name.substr(0, 12);
|
||||
const msg: number[] = [];
|
||||
msg.push()
|
||||
board().radioState.bus.datagram.send({
|
||||
type: PacketPayloadType.VALUE,
|
||||
groupId: board().radioState.groupId,
|
||||
stringData: name,
|
||||
numberData: value
|
||||
});
|
||||
}
|
||||
|
||||
export function receiveNumber(): number {
|
||||
const packet = board().radioState.bus.datagram.recv();
|
||||
return receivedNumber();
|
||||
}
|
||||
|
||||
export function receiveString(): string {
|
||||
const packet = board().radioState.bus.datagram.recv();
|
||||
return receivedString();
|
||||
export function readRawPacket() {
|
||||
const packet = board().radioState.datagram.recv();
|
||||
return new RefBuffer(packet.payload.bufferData)
|
||||
}
|
||||
|
||||
export function receivedSignalStrength(): number {
|
||||
return board().radioState.bus.datagram.lastReceived.rssi;
|
||||
return board().radioState.datagram.lastReceived.rssi;
|
||||
}
|
||||
|
||||
export function onDataReceived(handler: RefAction): void {
|
||||
pxtcore.registerWithDal(DAL.MICROBIT_ID_RADIO, DAL.MICROBIT_RADIO_EVT_DATAGRAM, handler);
|
||||
radio.receiveNumber();
|
||||
}
|
||||
|
||||
export function receivedNumber(): number {
|
||||
return board().radioState.bus.datagram.lastReceived.payload.numberData || 0;
|
||||
}
|
||||
|
||||
export function receivedSerial(): number {
|
||||
return board().radioState.bus.datagram.lastReceived.serial;
|
||||
}
|
||||
|
||||
export function receivedString(): string {
|
||||
return initString(board().radioState.bus.datagram.lastReceived.payload.stringData || "");
|
||||
}
|
||||
|
||||
export function receivedTime(): number {
|
||||
return board().radioState.bus.datagram.lastReceived.time;
|
||||
}
|
||||
|
||||
function writePacketToSerial(b: DalBoard, p: PacketBuffer) {
|
||||
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:
|
||||
}
|
||||
readRawPacket();
|
||||
}
|
||||
}
|
@ -28,11 +28,21 @@ namespace pxsim {
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.control {
|
||||
export function __log(s: string) {
|
||||
board().writeSerial(s + "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.serial {
|
||||
export function writeString(s: string) {
|
||||
board().writeSerial(s);
|
||||
}
|
||||
|
||||
export function writeBuffer(buf: RefBuffer) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
export function readUntil(del: string): string {
|
||||
return readString();
|
||||
}
|
||||
@ -53,4 +63,18 @@ namespace pxsim.serial {
|
||||
export function redirectToUSB() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
export function setRxBufferSize(size: number) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
export function setTxBufferSize(size: number) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
export function readBuffer(length: number) {
|
||||
if (length <= 0)
|
||||
length = 64;
|
||||
return pins.createBuffer(length);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user