Compare commits

...

45 Commits

Author SHA1 Message Date
f175f973f0 0.3.76 2016-09-05 14:26:24 +01:00
c7e5fa490e Bump pxt-core to 0.3.87 2016-09-05 14:26:24 +01:00
61a29f7c67 Always diplay sad face on errors; use nullCheck() function; see https://github.com/Microsoft/pxt/issues/302 2016-09-05 14:26:07 +01:00
50293fc654 don't repace spaces 2016-09-02 21:38:22 -07:00
a9ecadaf09 Merge pull request #238 from Microsoft/power-usage
Direct power wires for single usages
2016-09-02 21:13:15 -07:00
6e56107eb5 Merge branch 'master' into power-usage 2016-09-02 16:12:48 -07:00
1f077beb65 directly wires power if there is single usage 2016-09-02 16:11:58 -07:00
8fff762156 removed uwp info 2016-09-02 16:08:49 -07:00
cebded2526 Merge pull request #237 from Microsoft/power-usage
finer grain power wires based on usage
2016-09-02 16:07:02 -07:00
13f53d730a fixes instruction steps for finer power usage 2016-09-02 15:43:26 -07:00
8adcab1cab finer grain power wires based on usage 2016-09-02 15:24:16 -07:00
8cb5f442f9 0.3.75 2016-09-02 12:07:49 -07:00
96448d5237 Bump pxt-core to 0.3.86 2016-09-02 12:07:34 -07:00
30f01bb0ac 0.3.74 2016-09-02 17:32:54 +01:00
3d0b397de2 Bump pxt-core to 0.3.85 2016-09-02 17:32:54 +01:00
e0de55d689 Add pxtrt::runtimeWarning() support; see https://github.com/Microsoft/pxt/issues/31 2016-09-02 17:29:40 +01:00
7637a98f07 0.3.73 2016-09-02 16:54:27 +01:00
95f94e0886 Bump pxt-core to 0.3.84 2016-09-02 16:54:26 +01:00
9a2367cf8e Add dummy implementations for some bluetooth functions to avoid crashes 2016-09-02 16:03:55 +01:00
15fecb77c4 0.3.72 2016-09-01 23:23:16 -07:00
4f69bbabfb Bump pxt-core to 0.3.82 2016-09-01 23:23:13 -07:00
8351ed0513 Merge pull request #227 from Microsoft/max6675
adds MAX6675; adds general SPI & I2C support to sim
2016-09-01 22:48:33 -07:00
c34b0a1aeb Merge branch 'master' into max6675 2016-09-01 22:48:02 -07:00
9bcd44d7e4 0.3.71 2016-09-01 22:39:31 -07:00
3403da8ce8 Bump pxt-core to 0.3.81 2016-09-01 22:39:27 -07:00
39c146329f perf optimization 2016-09-01 22:18:36 -07:00
8d0d0a7e9a 0.3.70 2016-09-01 22:00:15 -07:00
61b3783dd4 Bump pxt-core to 0.3.80 2016-09-01 22:00:13 -07:00
da16428842 merging master 2016-09-01 21:12:03 -07:00
359c456577 adds full-page instruction printing 2016-09-01 19:07:01 -07:00
b3d9c167e1 0.3.69 2016-09-01 17:13:25 -07:00
78398b220f Bump pxt-core to 0.3.79 2016-09-01 17:13:24 -07:00
a656fbbd7b embedding parts svg files in pxt.json 2016-09-01 16:24:12 -07:00
e681cc8c97 added parts to microbit 2016-09-01 15:37:39 -07:00
03beec9c49 0.3.68 2016-09-01 12:13:07 -07:00
1600644be5 Bump pxt-core to 0.3.77 2016-09-01 12:13:06 -07:00
a3dd64eb4c Merge branch 'master' of https://github.com/Microsoft/pxt-microbit 2016-09-01 12:12:48 -07:00
b865cce44e embedding neopixel / speaker svgs 2016-09-01 10:56:06 -07:00
dc42900c7f merges with master 2016-09-01 10:08:32 -07:00
dcc3bd95fe ignores max6675 2016-09-01 10:07:11 -07:00
4070d4e691 Merge branch 'master' into max6675 2016-08-31 22:41:59 -07:00
7048156b46 draws small wires for small micro:bit pins 2016-08-31 22:41:30 -07:00
232758805b removes "debugger" statement 2016-08-31 21:56:46 -07:00
211d4e5538 adds max6675 2016-08-31 21:55:55 -07:00
374d8c590d adds spi and i2c pins 2016-08-31 21:53:48 -07:00
23 changed files with 511 additions and 346 deletions

View File

@ -53,11 +53,6 @@ pxt update
More instructions at https://github.com/Microsoft/pxt#running-a-target-from-localhost
## Universal Windows App
The Windows 10 app is a [Universal Windows Hosted Web App](https://microsoftedge.github.io/WebAppsDocs/en-US/win10/CreateHWA.htm)
that wraps ``codethemicrobit.com`` and provides additional features.
### Building
* Install Visual Studio 2015 Update 2 or higher. Make sure the Windows 10 templates are installed.

View File

@ -101,38 +101,18 @@ namespace bluetooth {
uart = new MicroBitUARTService(*uBit.ble, 61, 60);
}
/**
* Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device.
*/
//% help=bluetooth/uart-write
//% blockId=bluetooth_uart_write block="bluetooth uart write %data" blockGap=8
//% parts="bluetooth"
//%
void uartWrite(StringData *data) {
startUartService();
uart->send(ManagedString(data));
}
/**
* Reads from the Bluetooth UART service buffer, returning its contents when the specified delimiter character is encountered.
*/
//% help=bluetooth/uart-read
//% blockId=bluetooth_uart_read block="bluetooth uart read %del=bluetooth_uart_delimiter_conv" blockGap=8
//% parts="bluetooth"
//%
StringData* uartRead(StringData *del) {
startUartService();
return uart->readUntil(ManagedString(del)).leakData();
}
/**
* Returns the delimiter corresponding string
*/
//% blockId="bluetooth_uart_delimiter_conv" block="%del"
//% weight=1
//% parts="bluetooth"
StringData* delimiters(Delimiters del) {
ManagedString c("\n\n,$:.#"[max(0, min(6, (int)del))]);
return c.leakData();
}
/**
* Register code to run when the micro:bit is connected to over Bluetooth
* @param body Code to run when a Bluetooth connection is established

View File

@ -0,0 +1,43 @@
namespace bluetooth {
/**
* Returns the delimiter corresponding string
*/
//% blockId="bluetooth_uart_delimiter_conv" block="%del"
//% weight=1 parts="bluetooth"
export function delimiters(del: Delimiters): string {
// even though it might not look like, this is more
// (memory) efficient than the C++ implementation, because the
// strings are statically allocated and take no RAM
switch (del) {
case Delimiters.NewLine: return "\n"
case Delimiters.Comma: return ","
case Delimiters.Dollar: return "$"
case Delimiters.Colon: return ":"
case Delimiters.Fullstop: return "."
case Delimiters.Hash: return "#"
default: return "\n"
}
}
/**
* Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device.
*/
//% help=bluetooth/uart-write
//% blockId=bluetooth_uart_write block="bluetooth uart write %data" blockGap=8
//% parts="bluetooth" shim=bluetooth::uartWrite
export function uartWrite(data: string): void {
// dummy implementation for simulator
console.log("UART Write: " + data)
}
/**
* Reads from the Bluetooth UART service buffer, returning its contents when the specified delimiter character is encountered.
*/
//% help=bluetooth/uart-read
//% blockId=bluetooth_uart_read block="bluetooth uart read %del=bluetooth_uart_delimiter_conv" blockGap=8
//% parts="bluetooth" shim=bluetooth::uartRead
export function uartRead(del: string): string {
// dummy implementation for simulator
return "???"
}
}

View File

@ -5,6 +5,7 @@
"README.md",
"enums.d.ts",
"shims.d.ts",
"bluetooth.ts",
"bluetooth.cpp"
],
"public": true,

View File

@ -63,30 +63,6 @@ declare namespace bluetooth {
//% parts="bluetooth" shim=bluetooth::startUartService
function startUartService(): void;
/**
* Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device.
*/
//% help=bluetooth/uart-write
//% blockId=bluetooth_uart_write block="bluetooth uart write %data" blockGap=8
//% parts="bluetooth" shim=bluetooth::uartWrite
function uartWrite(data: string): void;
/**
* Reads from the Bluetooth UART service buffer, returning its contents when the specified delimiter character is encountered.
*/
//% help=bluetooth/uart-read
//% blockId=bluetooth_uart_read block="bluetooth uart read %del=bluetooth_uart_delimiter_conv" blockGap=8
//% parts="bluetooth" shim=bluetooth::uartRead
function uartRead(del: string): string;
/**
* Returns the delimiter corresponding string
*/
//% blockId="bluetooth_uart_delimiter_conv" block="%del"
//% weight=1
//% parts="bluetooth" shim=bluetooth::delimiters
function delimiters(del: Delimiters): string;
/**
* Register code to run when the micro:bit is connected to over Bluetooth
* @param body Code to run when a Bluetooth connection is established

View File

@ -37,4 +37,11 @@ namespace control {
panic(98)
}
}
/**
* Display warning in the simulator.
*/
//% shim=pxtrt::runtimeWarning
export function runtimeWarning(message: string) {
}
}

View File

@ -316,4 +316,9 @@ namespace pxtrt {
void* getGlobalsPtr() {
return globals;
}
//%
void runtimeWarning(StringData *s) {
// noop for now
}
}

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -27,6 +27,8 @@
"serial.cpp",
"serial.ts",
"buffer.cpp",
"pxtparts.json",
"parts/speaker.svg",
"_locales/fr/microbit-jsdoc-strings.json"
],
"public": true,

View File

@ -0,0 +1,78 @@
{
"ledmatrix": {
"visual": "ledmatrix",
"breadboardColumnsNeeded": 8,
"breadboardStartRow": "h",
"pinAllocation": {
"type": "auto",
"gpioPinsNeeded": [5, 5]
},
"assemblyStep": 0,
"wires": [
{"start": ["breadboard", "j", 0], "end": ["GPIO", 5], "color": "purple", "assemblyStep": 1},
{"start": ["breadboard", "j", 1], "end": ["GPIO", 6], "color": "purple", "assemblyStep": 1},
{"start": ["breadboard", "j", 2], "end": ["GPIO", 7], "color": "purple", "assemblyStep": 1},
{"start": ["breadboard", "j", 3], "end": ["GPIO", 8], "color": "purple", "assemblyStep": 1},
{"start": ["breadboard", "a", 7], "end": ["GPIO", 9], "color": "purple", "assemblyStep": 1},
{"start": ["breadboard", "a", 0], "end": ["GPIO", 0], "color": "green", "assemblyStep": 2},
{"start": ["breadboard", "a", 1], "end": ["GPIO", 1], "color": "green", "assemblyStep": 2},
{"start": ["breadboard", "a", 2], "end": ["GPIO", 2], "color": "green", "assemblyStep": 2},
{"start": ["breadboard", "a", 3], "end": ["GPIO", 3], "color": "green", "assemblyStep": 2},
{"start": ["breadboard", "j", 4], "end": ["GPIO", 4], "color": "green", "assemblyStep": 2}
]
},
"buttonpair": {
"visual": "buttonpair",
"breadboardColumnsNeeded": 6,
"breadboardStartRow": "f",
"pinAllocation": {
"type": "predefined",
"pins": ["P13", "P12"]
},
"assemblyStep": 0,
"wires": [
{"start": ["breadboard", "j", 0], "end": ["GPIO", 0], "color": "yellow", "assemblyStep": 1},
{"start": ["breadboard", "a", 2], "end": "ground", "color": "blue", "assemblyStep": 1},
{"start": ["breadboard", "j", 3], "end": ["GPIO", 1], "color": "orange", "assemblyStep": 2},
{"start": ["breadboard", "a", 5], "end": "ground", "color": "blue", "assemblyStep": 2}
]
},
"neopixel": {
"visual": "neopixel",
"breadboardColumnsNeeded": 5,
"breadboardStartRow": "h",
"pinAllocation": {
"type": "factoryfunction",
"functionName": "neopixel.create",
"pinArgPositions": [0],
"otherArgPositions": [1]
},
"assemblyStep": 0,
"wires": [
{"start": ["breadboard", "j", 1], "end": "ground", "color": "blue", "assemblyStep": 1},
{"start": ["breadboard", "j", 2], "end": "threeVolt", "color": "red", "assemblyStep": 2},
{"start": ["breadboard", "j", 3], "end": ["GPIO", 0], "color": "green", "assemblyStep": 2}
]
},
"speaker": {
"visual": {
"image": "/parts/speaker.svg",
"width": 500,
"height": 500,
"firstPin": [180, 135],
"pinDist": 70,
"extraColumnOffset": 1
},
"breadboardColumnsNeeded": 5,
"breadboardStartRow": "f",
"pinAllocation": {
"type": "auto",
"gpioPinsNeeded": 1
},
"assemblyStep": 0,
"wires": [
{"start": ["breadboard", "j", 1], "end": ["GPIO", 0], "color": "#ff80fa", "assemblyStep": 1},
{"start": ["breadboard", "j", 3], "end": "ground", "color": "blue", "assemblyStep": 1}
]
}
}

View File

@ -1,6 +1,6 @@
{
"name": "pxt-microbit",
"version": "0.3.67",
"version": "0.3.76",
"description": "micro:bit target for PXT",
"keywords": [
"JavaScript",
@ -29,6 +29,6 @@
"typescript": "^1.8.7"
},
"dependencies": {
"pxt-core": "0.3.76"
"pxt-core": "0.3.87"
}
}

View File

@ -55,6 +55,63 @@ namespace pxsim {
gpioNeeded: number,
gpioAssigned: string[]
}
interface PowerUsage {
topGround: boolean,
topThreeVolt: boolean,
bottomGround: boolean,
bottomThreeVolt: boolean,
singleGround: boolean,
singleThreeVolt: boolean,
}
function isOnBreadboardBottom(location: WireLocationDefinition) {
let isBot = false;
if (location[0] === "breadboard") {
let row = <string>location[1];
isBot = 0 <= ["a", "b", "c", "d", "e"].indexOf(row);
}
return isBot;
}
const arrCount = (a: boolean[]) => a.reduce((p, n) => p + (n ? 1 : 0), 0);
const arrAny = (a: boolean[]) => arrCount(a) > 0;
function computePowerUsage(wireDef: WireDefinition): PowerUsage {
let ends = [wireDef.start, wireDef.end];
let endIsGround = ends.map(e => e === "ground");
let endIsThreeVolt = ends.map(e => e === "threeVolt");
let endIsBot = ends.map(e => isOnBreadboardBottom(e));
let hasGround = arrAny(endIsGround);
let hasThreeVolt = arrAny(endIsThreeVolt);
let hasBot = arrAny(endIsBot);
return {
topGround: hasGround && !hasBot,
topThreeVolt: hasThreeVolt && !hasBot,
bottomGround: hasGround && hasBot,
bottomThreeVolt: hasThreeVolt && hasBot,
singleGround: hasGround,
singleThreeVolt: hasThreeVolt
};
}
function mergePowerUsage(powerUsages: PowerUsage[]) {
let finalPowerUsage = powerUsages.reduce((p, n) => ({
topGround: p.topGround || n.topGround,
topThreeVolt: p.topThreeVolt || n.topThreeVolt,
bottomGround: p.bottomGround || n.bottomGround,
bottomThreeVolt: p.bottomThreeVolt || n.bottomThreeVolt,
singleGround: n.singleGround ? p.singleGround === null : p.singleGround,
singleThreeVolt: n.singleThreeVolt ? p.singleThreeVolt === null : p.singleThreeVolt,
}), {
topGround: false,
topThreeVolt: false,
bottomGround: false,
bottomThreeVolt: false,
singleGround: null,
singleThreeVolt: null,
});
if (finalPowerUsage.singleGround)
finalPowerUsage.topGround = finalPowerUsage.bottomGround = false;
if (finalPowerUsage.singleThreeVolt)
finalPowerUsage.topThreeVolt = finalPowerUsage.bottomThreeVolt = false;
return finalPowerUsage;
}
function copyDoubleArray(a: string[][]) {
return a.map(b => b.map(p => p));
}
@ -90,6 +147,7 @@ namespace pxsim {
ground: mkRange(1, 26).map(n => <BBRowCol>["-", `${n}`]),
},
};
private powerUsage: PowerUsage;
constructor(opts: AllocatorOpts) {
this.opts = opts;
@ -97,9 +155,17 @@ namespace pxsim {
private allocateLocation(location: WireLocationDefinition, opts: AllocLocOpts): Loc {
if (location === "ground" || location === "threeVolt") {
//special case if there is only a single ground or three volt pin in the whole build
if (location === "ground" && this.powerUsage.singleGround) {
let boardGroundPin = this.getBoardGroundPin();
return {type: "dalboard", pin: boardGroundPin};
} else if (location === "threeVolt" && this.powerUsage.singleThreeVolt) {
let boardThreeVoltPin = this.getBoardThreeVoltPin();
return {type: "dalboard", pin: boardThreeVoltPin};
}
U.assert(!!opts.nearestBBPin);
let nearLoc = opts.nearestBBPin;
let nearestCoord = this.opts.getBBCoord(nearLoc);
let nearestCoord = this.opts.getBBCoord(opts.nearestBBPin);
let firstTopAndBot = [
this.availablePowerPins.top.ground[0] || this.availablePowerPins.top.threeVolt[0],
this.availablePowerPins.bottom.ground[0] || this.availablePowerPins.bottom.threeVolt[0]
@ -111,31 +177,31 @@ namespace pxsim {
//TODO
}
let nearTop = visuals.findClosestCoordIdx(nearestCoord, firstTopAndBot) == 0;
let pins: BBRowCol[];
let barPins: BBRowCol[];
if (nearTop) {
if (location === "ground") {
pins = this.availablePowerPins.top.ground;
barPins = this.availablePowerPins.top.ground;
} else if (location === "threeVolt") {
pins = this.availablePowerPins.top.threeVolt;
barPins = this.availablePowerPins.top.threeVolt;
}
} else {
if (location === "ground") {
pins = this.availablePowerPins.bottom.ground;
barPins = this.availablePowerPins.bottom.ground;
} else if (location === "threeVolt") {
pins = this.availablePowerPins.bottom.threeVolt;
barPins = this.availablePowerPins.bottom.threeVolt;
}
}
let pinCoords = pins.map(rowCol => {
let pinCoords = barPins.map(rowCol => {
return this.opts.getBBCoord(rowCol);
});
let pinIdx = visuals.findClosestCoordIdx(nearestCoord, pinCoords);
let pin = pins[pinIdx];
let closestPinIdx = visuals.findClosestCoordIdx(nearestCoord, pinCoords);
let pin = barPins[closestPinIdx];
if (nearTop) {
this.availablePowerPins.top.ground.splice(pinIdx, 1);
this.availablePowerPins.top.threeVolt.splice(pinIdx, 1);
this.availablePowerPins.top.ground.splice(closestPinIdx, 1);
this.availablePowerPins.top.threeVolt.splice(closestPinIdx, 1);
} else {
this.availablePowerPins.bottom.ground.splice(pinIdx, 1);
this.availablePowerPins.bottom.threeVolt.splice(pinIdx, 1);
this.availablePowerPins.bottom.ground.splice(closestPinIdx, 1);
this.availablePowerPins.bottom.threeVolt.splice(closestPinIdx, 1);
}
return {type: "breadboard", rowCol: pin};
} else if (location[0] === "breadboard") {
@ -148,23 +214,41 @@ namespace pxsim {
let idx = <number>location[1];
let pin = opts.cmpGPIOPins[idx];
return {type: "dalboard", pin: pin};
} else if (location === "MOSI" || location === "MISO" || location === "SCK") {
if (!this.opts.boardDef.spiPins)
console.debug("No SPI pin mappings found!");
let pin = (<any>this.opts.boardDef.spiPins)[location as string] as string;
return {type: "dalboard", pin: pin};
} else if (location === "SDA" || location === "SCL") {
if (!this.opts.boardDef.i2cPins)
console.debug("No I2C pin mappings found!");
let pin = (<any>this.opts.boardDef.i2cPins)[location as string] as string;
return {type: "dalboard", pin: pin};
} else {
//TODO
U.assert(false);
return null;
}
}
private allocatePowerWires(): WireInst[] {
private getBoardGroundPin() {
let boardGround = this.opts.boardDef.groundPins[0] || null;
if (!boardGround) {
console.log("No available ground pin on board!");
//TODO
}
return boardGround;
}
private getBoardThreeVoltPin() {
let threeVoltPin = this.opts.boardDef.threeVoltPins[0] || null;
if (!threeVoltPin) {
console.log("No available 3.3V pin on board!");
//TODO
}
return threeVoltPin;
}
private allocatePowerWires(powerUsage: PowerUsage): WireInst[] {
let boardGroundPin = this.getBoardGroundPin();
let threeVoltPin = this.getBoardThreeVoltPin();
let topLeft: BBRowCol = ["-", "26"];
let botLeft: BBRowCol = ["-", "1"];
let topRight: BBRowCol = ["-", "50"];
@ -179,34 +263,71 @@ namespace pxsim {
}
const GROUND_COLOR = "blue";
const POWER_COLOR = "red";
const wires: WireInst[] = [
{start: this.allocateLocation("ground", {nearestBBPin: top}),
end: this.allocateLocation("ground", {nearestBBPin: bot}),
color: GROUND_COLOR, assemblyStep: 0},
{start: this.allocateLocation("ground", {nearestBBPin: top}),
end: {type: "dalboard", pin: boardGround},
color: GROUND_COLOR, assemblyStep: 0},
{start: this.allocateLocation("threeVolt", {nearestBBPin: top}),
end: this.allocateLocation("threeVolt", {nearestBBPin: bot}),
color: POWER_COLOR, assemblyStep: 1},
{start: this.allocateLocation("threeVolt", {nearestBBPin: top}),
end: {type: "dalboard", pin: threeVoltPin},
color: POWER_COLOR, assemblyStep: 1},
];
const wires: WireInst[] = [];
let groundStep = 0;
let threeVoltStep = (powerUsage.bottomGround || powerUsage.topGround) ? 1 : 0;
if (powerUsage.bottomGround && powerUsage.topGround) {
//bb top - <==> bb bot -
wires.push({
start: this.allocateLocation("ground", {nearestBBPin: top}),
end: this.allocateLocation("ground", {nearestBBPin: bot}),
color: GROUND_COLOR, assemblyStep: groundStep
});
}
if (powerUsage.topGround) {
//board - <==> bb top -
wires.push({
start: this.allocateLocation("ground", {nearestBBPin: top}),
end: {type: "dalboard", pin: boardGroundPin},
color: GROUND_COLOR, assemblyStep: groundStep
});
} else if (powerUsage.bottomGround) {
//board - <==> bb bot -
wires.push({
start: this.allocateLocation("ground", {nearestBBPin: bot}),
end: {type: "dalboard", pin: boardGroundPin},
color: GROUND_COLOR, assemblyStep: groundStep
});
}
if (powerUsage.bottomThreeVolt && powerUsage.bottomGround) {
//bb top + <==> bb bot +
wires.push({
start: this.allocateLocation("threeVolt", {nearestBBPin: top}),
end: this.allocateLocation("threeVolt", {nearestBBPin: bot}),
color: POWER_COLOR, assemblyStep: threeVoltStep
});
}
if (powerUsage.topThreeVolt) {
//board + <==> bb top +
wires.push({
start: this.allocateLocation("threeVolt", {nearestBBPin: top}),
end: {type: "dalboard", pin: threeVoltPin},
color: POWER_COLOR, assemblyStep: threeVoltStep
});
} else if (powerUsage.bottomThreeVolt) {
//board + <==> bb bot +
wires.push({
start: this.allocateLocation("threeVolt", {nearestBBPin: bot}),
end: {type: "dalboard", pin: threeVoltPin},
color: POWER_COLOR, assemblyStep: threeVoltStep
});
}
return wires;
}
private allocateWire(wireDef: WireDefinition, opts: AllocWireOpts): WireInst {
let ends = [wireDef.start, wireDef.end];
let endIsPower = ends.map(e => e === "ground" || e === "threeVolt");
//allocate non-power first so we know the nearest pin for the power end
let endInsts = ends.map((e, idx) => !endIsPower[idx] ? this.allocateLocation(e, opts) : null)
//allocate power pins closest to the other end of the wire
endInsts = endInsts.map((e, idx) => {
if (e)
return e;
let locInst = <BBLoc>endInsts[1 - idx];
let locInst = <BBLoc>endInsts[1 - idx]; // non-power end
let l = this.allocateLocation(ends[idx], {
nearestBBPin: locInst.rowCol,
startColumn: opts.startColumn,
cmpGPIOPins: opts.cmpGPIOPins
cmpGPIOPins: opts.cmpGPIOPins,
});
return l;
});
@ -404,8 +525,11 @@ namespace pxsim {
let basicWires: WireInst[] = [];
let cmpsAndWires: CmpAndWireInst[] = [];
if (cmpList.length > 0) {
basicWires = this.allocatePowerWires();
let partialCmps = this.allocatePartialCmps();
let allWireDefs = partialCmps.map(p => p.def.wires).reduce((p, n) => p.concat(n), []);
let allPowerUsage = allWireDefs.map(w => computePowerUsage(w));
this.powerUsage = mergePowerUsage(allPowerUsage);
basicWires = this.allocatePowerWires(this.powerUsage);
let cmpGPIOPins = this.allocateGPIOPins(partialCmps);
let reverseMap = mkReverseMap(this.opts.boardDef.gpioPinMap);
let cmpMicrobitPins = cmpGPIOPins.map(pins => pins.map(p => reverseMap[p]));

View File

@ -1,3 +1,5 @@
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
namespace pxsim {
export class DalBoard extends BaseBoard {
id: string;
@ -69,12 +71,14 @@ namespace pxsim {
}
initAsync(msg: SimulatorRunMessage): Promise<void> {
super.initAsync(msg);
let options = (msg.options || {}) as RuntimeOptions;
let boardDef = CURRENT_BOARD; //TODO: read from pxt.json/pxttarget.json
let cmpsList = msg.parts;
let cmpDefs = PART_DEFINITIONS; //TODO: read from pxt.json/pxttarget.json
let cmpDefs = msg.partDefinitions || {}; //TODO: read from pxt.json/pxttarget.json
let fnArgs = msg.fnArgs;
let viewHost = new visuals.BoardHost({

View File

@ -1,73 +1,10 @@
/// <reference path="../node_modules/pxt-core/typings/bluebird/bluebird.d.ts"/>
/// <reference path="../node_modules/pxt-core/built/pxtparts.d.ts"/>
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
/// <reference path="../libs/microbit/dal.d.ts"/>
/// <reference path="./visuals/neopixel.ts"/>
namespace pxsim {
export interface PinBlockDefinition {
x: number,
y: number,
labelPosition: "above" | "below";
labels: string[]
}
export interface BoardImageDefinition {
image: string,
outlineImage?: string,
width: number,
height: number,
pinDist: number,
pinBlocks: PinBlockDefinition[],
};
export interface BoardDefinition {
visual: BoardImageDefinition | string,
gpioPinBlocks?: string[][],
gpioPinMap: {[pin: string]: string},
groundPins: string[],
threeVoltPins: string[],
attachPowerOnRight?: boolean,
onboardComponents?: string[]
useCrocClips?: boolean,
marginWhenBreadboarding?: [number, number, number, number],
}
export interface FactoryFunctionPinAlloc {
type: "factoryfunction",
functionName: string,
pinArgPositions: number[],
otherArgPositions?: number[],
}
export interface PredefinedPinAlloc {
type: "predefined",
pins: string[],
}
export interface AutoPinAlloc {
type: "auto",
gpioPinsNeeded: number | number[],
}
export interface PartVisualDefinition {
image: string,
width: number,
height: number,
pinDist: number,
extraColumnOffset?: number,
firstPin: [number, number],
}
export interface PartDefinition {
visual: string | PartVisualDefinition,
breadboardColumnsNeeded: number,
breadboardStartRow: string,
wires: WireDefinition[],
assemblyStep: number,
pinAllocation: FactoryFunctionPinAlloc | PredefinedPinAlloc | AutoPinAlloc,
}
export interface WireDefinition {
start: WireLocationDefinition,
end: WireLocationDefinition,
color: string,
assemblyStep: number
};
export type WireLocationDefinition =
["breadboard", string, number] | ["GPIO", number] | "ground" | "threeVolt";
export const MICROBIT_DEF: BoardDefinition = {
visual: "microbit",
gpioPinBlocks: [
@ -75,8 +12,7 @@ namespace pxsim {
["P3"],
["P4", "P5", "P6", "P7"],
["P8", "P9", "P10", "P11", "P12"],
["P13", "P14", "P15", "P16"],
["P19", "P20"],
["P16"],
],
gpioPinMap: {
"P0": "P0",
@ -99,6 +35,16 @@ namespace pxsim {
"P19": "P19",
"P20": "P20",
},
spiPins: {
MOSI: "P15",
MISO: "P14",
SCK: "P13",
},
i2cPins: {
SDA: "P20",
SCL: "P19",
},
analogInPins: ["P0", "P1", "P2", "P3", "P10"],
groundPins: ["GND"],
threeVoltPins: ["+3v3"],
attachPowerOnRight: true,
@ -107,85 +53,6 @@ namespace pxsim {
marginWhenBreadboarding: [0, 0, 80, 0],
}
export const PART_DEFINITIONS: Map<PartDefinition> = {
"ledmatrix": {
visual: "ledmatrix",
breadboardColumnsNeeded: 8,
breadboardStartRow: "h",
pinAllocation: {
type: "auto",
gpioPinsNeeded: [5, 5],
},
assemblyStep: 0,
wires: [
{start: ["breadboard", `j`, 0], end: ["GPIO", 5], color: "purple", assemblyStep: 1},
{start: ["breadboard", `j`, 1], end: ["GPIO", 6], color: "purple", assemblyStep: 1},
{start: ["breadboard", `j`, 2], end: ["GPIO", 7], color: "purple", assemblyStep: 1},
{start: ["breadboard", `j`, 3], end: ["GPIO", 8], color: "purple", assemblyStep: 1},
{start: ["breadboard", `a`, 7], end: ["GPIO", 9], color: "purple", assemblyStep: 1},
{start: ["breadboard", `a`, 0], end: ["GPIO", 0], color: "green", assemblyStep: 2},
{start: ["breadboard", `a`, 1], end: ["GPIO", 1], color: "green", assemblyStep: 2},
{start: ["breadboard", `a`, 2], end: ["GPIO", 2], color: "green", assemblyStep: 2},
{start: ["breadboard", `a`, 3], end: ["GPIO", 3], color: "green", assemblyStep: 2},
{start: ["breadboard", `j`, 4], end: ["GPIO", 4], color: "green", assemblyStep: 2},
]
},
"buttonpair": {
visual: "buttonpair",
breadboardColumnsNeeded: 6,
breadboardStartRow: "f",
pinAllocation: {
type: "predefined",
pins: ["P13", "P12"],
},
assemblyStep: 0,
wires: [
{start: ["breadboard", "j", 0], end: ["GPIO", 0], color: "yellow", assemblyStep: 1},
{start: ["breadboard", "a", 2], end: "ground", color: "blue", assemblyStep: 1},
{start: ["breadboard", "j", 3], end: ["GPIO", 1], color: "orange", assemblyStep: 2},
{start: ["breadboard", "a", 5], end: "ground", color: "blue", assemblyStep: 2},
],
},
"neopixel": {
visual: "neopixel",
breadboardColumnsNeeded: 5,
breadboardStartRow: "h",
pinAllocation: {
type: "factoryfunction",
functionName: "neopixel.create",
pinArgPositions: [0],
otherArgPositions: [1],
},
assemblyStep: 0,
wires: [
{start: ["breadboard", "j", 1], end: "ground", color: "blue", assemblyStep: 1},
{start: ["breadboard", "j", 2], end: "threeVolt", color: "red", assemblyStep: 2},
{start: ["breadboard", "j", 3], end: ["GPIO", 0], color: "green", assemblyStep: 2},
],
},
"speaker": {
visual: {
image: "/parts/speaker.svg",
width: 500,
height: 500,
firstPin: [180, 135],
pinDist: 70,
extraColumnOffset: 1,
},
breadboardColumnsNeeded: 5,
breadboardStartRow: "f",
pinAllocation: {
type: "auto",
gpioPinsNeeded: 1,
},
assemblyStep: 0,
wires: [
{start: ["breadboard", "j", 1], end: ["GPIO", 0], color: "#ff80fa", assemblyStep: 1},
{start: ["breadboard", "j", 3], end: "ground", color: "blue", assemblyStep: 1},
],
},
}
export const builtinComponentSimVisual: Map<() => visuals.IBoardComponent<any>> = {
"buttonpair": () => new visuals.ButtonPairView(),
"ledmatrix": () => new visuals.LedMatrixView(),

View File

@ -20,34 +20,37 @@ namespace pxsim.instructions {
const LBL_LEFT_PAD = 5;
const REQ_WIRE_HEIGHT = 45;
const REQ_CMP_HEIGHT = 55;
const REQ_CMP_SCALE = 0.5;
const REQ_CMP_SCALE = 0.5 * 4;
type Orientation = "landscape" | "portrait";
const ORIENTATION: Orientation = "portrait";
const PPI = 96.0;
const PAGE_SCALAR = 0.95;
const [FULL_PAGE_WIDTH, FULL_PAGE_HEIGHT]
= (ORIENTATION == "portrait" ? [PPI * 8.5, PPI * 11.0] : [PPI * 11.0, PPI * 8.5]);
= (ORIENTATION == "portrait" ? [PPI * 8.5 * PAGE_SCALAR, PPI * 11.0 * PAGE_SCALAR] : [PPI * 11.0 * PAGE_SCALAR, PPI * 8.5 * PAGE_SCALAR]);
const PAGE_MARGIN = PPI * 0.45;
const PAGE_WIDTH = FULL_PAGE_WIDTH - PAGE_MARGIN * 2;
const PAGE_HEIGHT = FULL_PAGE_HEIGHT - PAGE_MARGIN * 2;
const BORDER_COLOR = "gray";
const BORDER_RADIUS = 5;
const BORDER_WIDTH = 2;
const [PANEL_ROWS, PANEL_COLS] = [2, 2];
const BORDER_RADIUS = 5 * 4;
const BORDER_WIDTH = 2 * 2;
const [PANEL_ROWS, PANEL_COLS] = [1, 1];
const PANEL_MARGIN = 20;
const PANEL_PADDING = 8;
const PANEL_PADDING = 8 * 3;
const PANEL_WIDTH = PAGE_WIDTH / PANEL_COLS - (PANEL_MARGIN + PANEL_PADDING + BORDER_WIDTH) * PANEL_COLS;
const PANEL_HEIGHT = PAGE_HEIGHT / PANEL_ROWS - (PANEL_MARGIN + PANEL_PADDING + BORDER_WIDTH) * PANEL_ROWS;
const BOARD_WIDTH = 240;
const BOARD_WIDTH = 465;
const BOARD_LEFT = (PANEL_WIDTH - BOARD_WIDTH) / 2.0 + PANEL_PADDING;
const BOARD_BOT = PANEL_PADDING;
const NUM_BOX_SIZE = 60;
const NUM_FONT = 40;
const NUM_MARGIN = 5;
const FRONT_PAGE_BOARD_WIDTH = 200;
const NUM_BOX_SIZE = 120;
const NUM_FONT = 80;
const NUM_MARGIN = 10;
const FRONT_PAGE_BOARD_WIDTH = 400;
const PART_SCALAR = 2.3
const PARTS_BOARD_SCALE = 0.17;
const PARTS_BB_SCALE = 0.25;
const PARTS_CMP_SCALE = 0.3;
const PARTS_WIRE_SCALE = 0.23;
const BACK_PAGE_BOARD_WIDTH = PANEL_WIDTH - PANEL_PADDING * 1.5;
const STYLE = `
.instr-panel {
margin: ${PANEL_MARGIN}px;
@ -56,11 +59,12 @@ namespace pxsim.instructions {
border-color: ${BORDER_COLOR};
border-style: solid;
border-radius: ${BORDER_RADIUS}px;
display: inline-block;
display: block;
width: ${PANEL_WIDTH}px;
height: ${PANEL_HEIGHT}px;
position: relative;
overflow: hidden;
page-break-inside: avoid;
}
.board-svg {
margin: 0 auto;
@ -90,10 +94,11 @@ namespace pxsim.instructions {
}
.reqs-div {
margin-left: ${PANEL_PADDING + NUM_BOX_SIZE}px;
margin-top: 5px;
}
.partslist-wire,
.partslist-cmp {
margin: 5px;
margin: 10px;
}
.partslist-wire {
display: inline-block;
@ -149,7 +154,7 @@ namespace pxsim.instructions {
//TODO: Refactor this function; it is too complicated. There is a lot of error-prone math being done
// to scale and place all elements which could be simplified with more forethought.
let svgEl = <SVGSVGElement>document.createElementNS("http://www.w3.org/2000/svg", "svg");
let dims = {l: 0, t: 0, w: 0, h: 0};
let dims = { l: 0, t: 0, w: 0, h: 0 };
let cmpSvgEl = <SVGSVGElement>document.createElementNS("http://www.w3.org/2000/svg", "svg");
svgEl.appendChild(cmpSvgEl);
@ -176,7 +181,7 @@ namespace pxsim.instructions {
scale(opts.cmpHeight / dims.h)
}
svg.hydrate(cmpSvgEl, cmpSvgAtts);
let elDims = {l: dims.l, t: dims.t, w: dims.w, h: dims.h};
let elDims = { l: dims.l, t: dims.t, w: dims.w, h: dims.h };
let updateL = (newL: number) => {
if (newL < dims.l) {
@ -269,8 +274,8 @@ namespace pxsim.instructions {
let svgAtts = {
"viewBox": `${dims.l} ${dims.t} ${dims.w} ${dims.h}`,
"width": dims.w,
"height": dims.h,
"width": dims.w * PART_SCALAR,
"height": dims.h * PART_SCALAR,
"preserveAspectRatio": "xMidYMid",
};
svg.hydrate(svgEl, svgAtts);
@ -288,7 +293,7 @@ namespace pxsim.instructions {
let cnstr = builtinComponentPartVisual[builtinVis];
el = cnstr([0, 0]);
} else {
let partVis = <PartVisualDefinition> cmp;
let partVis = <PartVisualDefinition>cmp;
el = visuals.mkGenericPartSVG(partVis);
}
return wrapSvg(el, opts);
@ -315,8 +320,8 @@ namespace pxsim.instructions {
let step = w.assemblyStep + 1;
(stepToWires[step] || (stepToWires[step] = [])).push(w)
});
let getMaxStep = (ns: {assemblyStep: number}[]) => ns.reduce((m, n) => Math.max(m, n.assemblyStep), 0);
let stepOffset = getMaxStep(powerWires) + 2;
let getMaxStep = (ns: { assemblyStep: number }[]) => ns.reduce((m, n) => Math.max(m, n.assemblyStep), 0);
let stepOffset = powerWires.length > 0 ? getMaxStep(powerWires) + 2 : 1;
components.forEach(cAndWs => {
let {component, wires} = cAndWs;
let cStep = component.assemblyStep + stepOffset;
@ -359,10 +364,10 @@ namespace pxsim.instructions {
function mkBlankBoardAndBreadboard(boardDef: BoardDefinition, cmpDefs: Map<PartDefinition>, fnArgs: any, width: number, buildMode: boolean = false): visuals.BoardHost {
let state = runtime.board as pxsim.DalBoard;
let boardHost = new visuals.BoardHost({
state: state,
boardDef: boardDef,
state: state,
boardDef: boardDef,
forceBreadboard: true,
cmpDefs: cmpDefs,
cmpDefs: cmpDefs,
maxWidth: `${width}px`,
fnArgs: fnArgs,
wireframe: buildMode,
@ -446,10 +451,10 @@ namespace pxsim.instructions {
// board and breadboard
let boardImg = mkBoardImgSvg(props.boardDef.visual);
let board = wrapSvg(boardImg, {left: QUANT_LBL(1), leftSize: QUANT_LBL_SIZE, cmpScale: PARTS_BOARD_SCALE});
let board = wrapSvg(boardImg, { left: QUANT_LBL(1), leftSize: QUANT_LBL_SIZE, cmpScale: PARTS_BOARD_SCALE });
panel.appendChild(board);
let bbRaw = mkBBSvg();
let bb = wrapSvg(bbRaw, {left: QUANT_LBL(1), leftSize: QUANT_LBL_SIZE, cmpScale: PARTS_BB_SCALE});
let bb = wrapSvg(bbRaw, { left: QUANT_LBL(1), leftSize: QUANT_LBL_SIZE, cmpScale: PARTS_BB_SCALE });
panel.appendChild(bb);
// components
@ -560,7 +565,6 @@ namespace pxsim.instructions {
return [panel, props];
}
function mkFinalPanel(props: BoardProps) {
const BACK_PAGE_BOARD_WIDTH = PANEL_WIDTH - 20;
let panel = mkPanel();
addClass(panel, "back-panel");
@ -587,8 +591,8 @@ namespace pxsim.instructions {
if (tsCode) {
//we use the docs renderer to decompile the code to blocks and render it
//TODO: render the blocks code directly
let md =
`\`\`\`blocks
let md =
`\`\`\`blocks
${tsCode}
\`\`\`
\`\`\`package
@ -596,9 +600,9 @@ ${tsPackage}
\`\`\`
`
pxtdocs.requireMarked = function() { return (<any>window).marked; }
pxtdocs.requireMarked = function () { return (<any>window).marked; }
pxtrunner.renderMarkdownAsync(codeContainerDiv, md)
.done(function() {
.done(function () {
let codeSvg = $("#proj-code-container svg");
if (codeSvg.length > 0) {
//code rendered successfully as blocks
@ -620,6 +624,9 @@ ${tsPackage}
let parts = (getQsVal("parts") || "").split(" ");
parts.sort();
// parts definitions
let partDefinitions = JSON.parse(getQsVal("partdefs") || "{}") as pxsim.Map<PartDefinition>
//fn args
let fnArgs = JSON.parse((getQsVal("fnArgs") || "{}"));
@ -637,7 +644,7 @@ ${tsPackage}
style.textContent += STYLE;
const boardDef = CURRENT_BOARD;
const cmpDefs = PART_DEFINITIONS;
const cmpDefs = partDefinitions;
//props
let dummyBreadboard = new visuals.Breadboard({});

View File

@ -147,7 +147,7 @@ namespace pxsim.visuals {
const pin3Vmid = pins4onMids[13] + bigPinWidth / 2.0;
const pinGNDmid = pins4onMids[pins4onMids.length - 1] + bigPinWidth / 2.0;
const pinGND2mid = pinGNDmid + bigPinWidth / 2.0;
const pinMids = [pin0mid, pin1mid, pin2mid, pin3mid].concat(pins4onXs).concat([pinGNDmid, pin3Vmid, pinGND2mid]);
const pinMids = [pin0mid, pin1mid, pin2mid, pin3mid].concat(pins4onMids).concat([pinGNDmid, pin3Vmid, pinGND2mid]);
const pinNames = [
"P0", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P9", "P10",
"P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20",

View File

@ -1,4 +1,5 @@
# don't check in until OSS request is approved
sparkfun-*
raspberrypi-*
arduino-*
arduino-*
max6675*

View File

@ -96,9 +96,9 @@
.organization {
position: absolute;
bottom: 1rem;
right: 1rem;
height: 2rem;
bottom: 2rem;
right: 2rem;
height: 4rem;
}
h1 {
@ -112,23 +112,23 @@
#front-panel .board-svg {
position: absolute;
left: 1rem;
width: 140px;
top: 8rem;
left: 2rem;
width: 300px;
top: 16rem;
}
#proj-title {
top: 20px;
position: absolute;
width: 100%;
font-size: 70px;
margin-top: 20px;
}
#proj-code {
width: 140px;
height: 200px;
width: 300px;
height: 400px;
position: absolute;
right: 1rem;
top: 8rem;
right: 2rem;
top: 16rem;
}
#proj-code-container {
width: 100%;

View File

@ -5,14 +5,33 @@
namespace pxsim {
export type BBRowCol = [/*row*/string, /*column*/string];
export type BoardPin = string;
export interface BBLoc {type: "breadboard", rowCol: BBRowCol};
export interface BoardLoc {type: "dalboard", pin: BoardPin};
export interface BBLoc { type: "breadboard", rowCol: BBRowCol };
export interface BoardLoc { type: "dalboard", pin: BoardPin };
export type Loc = BBLoc | BoardLoc;
export function initRuntimeWithDalBoard() {
U.assert(!runtime.board);
let b = new DalBoard();
runtime.board = b;
runtime.postError = (e) => {
led.setBrightness(255);
let img = board().ledMatrixState.image;
img.clear();
img.set(0, 4, 255);
img.set(1, 3, 255);
img.set(2, 3, 255);
img.set(3, 3, 255);
img.set(4, 4, 255);
img.set(0, 0, 255);
img.set(1, 0, 255);
img.set(0, 1, 255);
img.set(1, 1, 255);
img.set(3, 0, 255);
img.set(4, 0, 255);
img.set(3, 1, 255);
img.set(4, 1, 255);
runtime.updateDisplay();
}
}
if (!pxsim.initCurrentRuntime) {
pxsim.initCurrentRuntime = initRuntimeWithDalBoard;
@ -31,7 +50,7 @@ namespace pxsim {
export function parseQueryString(): (key: string) => string {
let qs = window.location.search.substring(1);
let getQsVal = (key: string) => decodeURIComponent((qs.split(`${key}=`)[1] || "").split("&")[0] || "").replace(/\+/g, " ");
let getQsVal = (key: string) => decodeURIComponent((qs.split(`${key}=`)[1] || "").split("&")[0] || ""); //.replace(/\+/g, " ");
return getQsVal;
}
}
@ -50,15 +69,15 @@ namespace pxsim.visuals {
move: "pointermove",
leave: "pointerleave"
} : {
up: "mouseup",
down: "mousedown",
move: "mousemove",
leave: "mouseleave"
};
up: "mouseup",
down: "mousedown",
move: "mousemove",
leave: "mouseleave"
};
export function translateEl(el: SVGElement, xy: [number, number]) {
//TODO append translation instead of replacing the full transform
svg.hydrate(el, {transform: `translate(${xy[0]} ${xy[1]})`});
svg.hydrate(el, { transform: `translate(${xy[0]} ${xy[1]})` });
}
export interface ComposeOpts {
@ -83,14 +102,14 @@ namespace pxsim.visuals {
export function composeSVG(opts: ComposeOpts): ComposeResult {
let [a, b] = [opts.el1, opts.el2];
U.assert(a.x == 0 && a.y == 0 && b.x == 0 && b.y == 0, "el1 and el2 x,y offsets not supported");
let setXY = (e: SVGSVGElement, x: number, y: number) => svg.hydrate(e, {x: x, y: y});
let setXY = (e: SVGSVGElement, x: number, y: number) => svg.hydrate(e, { x: x, y: y });
let setWH = (e: SVGSVGElement, w: string, h: string) => {
if (w)
svg.hydrate(e, {width: w});
svg.hydrate(e, { width: w });
if (h)
svg.hydrate(e, {height: h});
svg.hydrate(e, { height: h });
}
let setWHpx = (e: SVGSVGElement, w: number, h: number) => svg.hydrate(e, {width: `${w}px`, height: `${h}px`});
let setWHpx = (e: SVGSVGElement, w: number, h: number) => svg.hydrate(e, { width: `${w}px`, height: `${h}px` });
let scaleUnit = opts.scaleUnit2;
let aScalar = opts.scaleUnit2 / opts.scaleUnit1;
let bScalar = 1.0;
@ -157,11 +176,11 @@ namespace pxsim.visuals {
let w = scaleFn(opts.width);
let h = scaleFn(opts.height);
let img = <SVGImageElement>svg.elt("image", {
width: w,
height: h,
"href": `${opts.image}`
});
return {el: img, w: w, h: h, x: 0, y: 0};
width: w,
height: h,
"href": `${opts.image}`
});
return { el: img, w: w, h: h, x: 0, y: 0 };
}
export type Coord = [number, number];
@ -190,13 +209,15 @@ namespace pxsim.visuals {
export function mkTxt(cx: number, cy: number, size: number, rot: number, txt: string, txtXOffFactor?: number, txtYOffFactor?: number): SVGTextElement {
let el = <SVGTextElement>svg.elt("text")
//HACK: these constants (txtXOffFactor, txtYOffFactor) tweak the way this algorithm knows how to center the text
//HACK: these constants (txtXOffFactor, txtYOffFactor) tweak the way this algorithm knows how to center the text
txtXOffFactor = txtXOffFactor || -0.33333;
txtYOffFactor = txtYOffFactor || 0.3;
const xOff = txtXOffFactor * size * txt.length;
const yOff = txtYOffFactor * size;
svg.hydrate(el, {style: `font-size:${size}px;`,
transform: `translate(${cx} ${cy}) rotate(${rot}) translate(${xOff} ${yOff})` });
svg.hydrate(el, {
style: `font-size:${size}px;`,
transform: `translate(${cx} ${cy}) rotate(${rot}) translate(${xOff} ${yOff})`
});
svg.addClass(el, "noselect");
el.textContent = txt;
return el;

View File

@ -195,26 +195,24 @@ namespace pxsim.images {
namespace pxsim.ImageMethods {
export function showImage(leds: Image, offset: number) {
if (!leds) panic(PanicCode.MICROBIT_NULL_DEREFERENCE);
pxtrt.nullCheck(leds)
leds.copyTo(offset, 5, board().ledMatrixState.image, 0)
runtime.queueDisplayUpdate()
}
export function plotImage(leds: Image, offset: number): void {
if (!leds) panic(PanicCode.MICROBIT_NULL_DEREFERENCE);
pxtrt.nullCheck(leds)
leds.copyTo(offset, 5, board().ledMatrixState.image, 0)
runtime.queueDisplayUpdate()
}
export function height(leds: Image): number {
if (!leds) panic(PanicCode.MICROBIT_NULL_DEREFERENCE);
pxtrt.nullCheck(leds)
return Image.height;
}
export function width(leds: Image): number {
if (!leds) panic(PanicCode.MICROBIT_NULL_DEREFERENCE);
pxtrt.nullCheck(leds)
return leds.width;
}
@ -227,35 +225,32 @@ namespace pxsim.ImageMethods {
}
export function pixel(leds: Image, x: number, y: number): number {
if (!leds) panic(PanicCode.MICROBIT_NULL_DEREFERENCE);
pxtrt.nullCheck(leds)
return leds.get(x, y);
}
export function setPixel(leds: Image, x: number, y: number, v: number) {
if (!leds) panic(PanicCode.MICROBIT_NULL_DEREFERENCE);
pxtrt.nullCheck(leds)
leds.set(x, y, v);
}
export function clear(leds: Image) {
if (!leds) panic(PanicCode.MICROBIT_NULL_DEREFERENCE);
pxtrt.nullCheck(leds)
leds.clear();
}
export function setPixelBrightness(i: Image, x: number, y: number, b: number) {
if (!i) panic(PanicCode.MICROBIT_NULL_DEREFERENCE);
pxtrt.nullCheck(i)
i.set(x, y, b);
}
export function pixelBrightness(i: Image, x: number, y: number): number {
if (!i) panic(PanicCode.MICROBIT_NULL_DEREFERENCE);
pxtrt.nullCheck(i)
return i.get(x, y);
}
export function scrollImage(leds: Image, stride: number, interval: number): void {
if (!leds) panic(PanicCode.MICROBIT_NULL_DEREFERENCE);
pxtrt.nullCheck(leds)
if (stride == 0) stride = 1;
let cb = getResume();

View File

@ -19,24 +19,6 @@ namespace pxsim {
export function panic(code: number) {
console.log("PANIC:", code)
led.setBrightness(255);
let img = board().ledMatrixState.image;
img.clear();
img.set(0, 4, 255);
img.set(1, 3, 255);
img.set(2, 3, 255);
img.set(3, 3, 255);
img.set(4, 4, 255);
img.set(0, 0, 255);
img.set(1, 0, 255);
img.set(0, 1, 255);
img.set(1, 1, 255);
img.set(3, 0, 255);
img.set(4, 0, 255);
img.set(3, 1, 255);
img.set(4, 1, 255);
runtime.updateDisplay();
throw new Error("PANIC " + code)
}

View File

@ -59,16 +59,48 @@ namespace pxsim.visuals {
const NP_PART_YOFF = -11;
const NP_PART_WIDTH = 87.5;
const NP_PART_HEIGHT = 190;
const NEOPIXEL_PART_IMG = "neopixel.svg";
const NEOPIXEL_PART_IMG = `<svg viewBox="-5 -1 53 112" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
<rect x="2.5" width="38" height="100" style="fill: rgb(68, 68, 68);"/>
<rect x="11.748" y="3.2" width="1.391" height="2.553" style="fill: none; stroke-linejoin: round; stroke-width: 3; stroke: rgb(165, 103, 52);"/>
<rect x="20.75" y="3.2" width="1.391" height="2.553" style="fill: none; stroke-linejoin: round; stroke-width: 3; stroke: rgb(165, 103, 52);"/>
<rect x="29.75" y="3.2" width="1.391" height="2.553" style="fill: none; stroke-linejoin: round; stroke-width: 3; stroke: rgb(165, 103, 52);"/>
<g>
<rect x="9" y="16.562" width="25" height="3.238" style="fill: rgb(216, 216, 216);"/>
<rect x="9" y="22.562" width="25" height="3.238" style="fill: rgb(216, 216, 216);"/>
<rect x="9" y="28.563" width="25" height="3.238" style="fill: rgb(216, 216, 216);"/>
<rect x="11.607" y="14.833" width="19.787" height="18.697" style="fill: rgb(0, 0, 0);"/>
<ellipse style="fill: rgb(216, 216, 216);" cx="21.5" cy="24.181" rx="7" ry="7"/>
</g>
<path d="M -7.25 -103.2 L -2.5 -100.003 L -12 -100.003 L -7.25 -103.2 Z" style="fill: rgb(68, 68, 68);" transform="matrix(-1, 0, 0, -1, 0, 0)" bx:shape="triangle -12 -103.2 9.5 3.197 0.5 0 1@ad6f5cac"/>
<path d="M -16.75 -103.197 L -12 -100 L -21.5 -100 L -16.75 -103.197 Z" style="fill: rgb(68, 68, 68);" transform="matrix(-1, 0, 0, -1, 0, 0)" bx:shape="triangle -21.5 -103.197 9.5 3.197 0.5 0 1@07d73149"/>
<path d="M -26.25 -103.2 L -21.5 -100.003 L -31 -100.003 L -26.25 -103.2 Z" style="fill: rgb(68, 68, 68);" transform="matrix(-1, 0, 0, -1, 0, 0)" bx:shape="triangle -31 -103.2 9.5 3.197 0.5 0 1@54403e2d"/>
<path d="M -35.75 -103.197 L -31 -100 L -40.5 -100 L -35.75 -103.197 Z" style="fill: rgb(68, 68, 68);" transform="matrix(-1, 0, 0, -1, 0, 0)" bx:shape="triangle -40.5 -103.197 9.5 3.197 0.5 0 1@21c9b772"/>
<g transform="matrix(1, 0, 0, 1, 0.000002, 29.999994)">
<rect x="9" y="16.562" width="25" height="3.238" style="fill: rgb(216, 216, 216);"/>
<rect x="9" y="22.562" width="25" height="3.238" style="fill: rgb(216, 216, 216);"/>
<rect x="9" y="28.563" width="25" height="3.238" style="fill: rgb(216, 216, 216);"/>
<rect x="11.607" y="14.833" width="19.787" height="18.697" style="fill: rgb(0, 0, 0);"/>
<ellipse style="fill: rgb(216, 216, 216);" cx="21.5" cy="24.181" rx="7" ry="7"/>
</g>
<g transform="matrix(1, 0, 0, 1, 0.000005, 59.999992)">
<rect x="9" y="16.562" width="25" height="3.238" style="fill: rgb(216, 216, 216);"/>
<rect x="9" y="22.562" width="25" height="3.238" style="fill: rgb(216, 216, 216);"/>
<rect x="9" y="28.563" width="25" height="3.238" style="fill: rgb(216, 216, 216);"/>
<rect x="11.607" y="14.833" width="19.787" height="18.697" style="fill: rgb(0, 0, 0);"/>
<ellipse style="fill: rgb(216, 216, 216);" cx="21.5" cy="24.181" rx="7" ry="7"/>
</g>
</svg>`;
let [x, y] = xy;
let l = x + NP_PART_XOFF;
let t = y + NP_PART_YOFF;
let w = NP_PART_WIDTH;
let h = NP_PART_HEIGHT;
let img = <SVGImageElement>svg.elt("image");
svg.hydrate(img, {class: "sim-neopixel-strip", x: l, y: t, width: w, height: h,
href: `/parts/${NEOPIXEL_PART_IMG}`});
return {el: img, x: l, y: t, w: w, h: h};
svg.hydrate(img, {
class: "sim-neopixel-strip", x: l, y: t, width: w, height: h,
href: svg.toDataUri(NEOPIXEL_PART_IMG)
});
return { el: img, x: l, y: t, w: w, h: h };
}
export class NeoPixel implements SVGAndSize<SVGCircleElement> {
public el: SVGCircleElement;
@ -83,7 +115,7 @@ namespace pxsim.visuals {
let circle = <SVGCircleElement>svg.elt("circle");
let r = PIXEL_RADIUS;
let [cx, cy] = xy;
svg.hydrate(circle, {cx: cx, cy: cy, r: r, class: "sim-neopixel"});
svg.hydrate(circle, { cx: cx, cy: cy, r: r, class: "sim-neopixel" });
this.el = circle;
this.w = r * 2;
this.h = r * 2;
@ -121,14 +153,14 @@ namespace pxsim.visuals {
"height": `${CANVAS_HEIGHT}px`,
});
this.canvas = el;
this.background = <SVGRectElement>svg.child(el, "rect", { class: "sim-neopixel-background hidden"});
this.background = <SVGRectElement>svg.child(el, "rect", { class: "sim-neopixel-background hidden" });
this.updateViewBox(-CANVAS_VIEW_WIDTH / 2, 0, CANVAS_VIEW_WIDTH, CANVAS_VIEW_HEIGHT);
}
private updateViewBox(x: number, y: number, w: number, h: number) {
this.viewBox = [x, y, w, h];
svg.hydrate(this.canvas, {"viewBox": `${x} ${y} ${w} ${h}`});
svg.hydrate(this.background, {"x": x, "y": y, "width": w, "height": h});
svg.hydrate(this.canvas, { "viewBox": `${x} ${y} ${w} ${h}` });
svg.hydrate(this.background, { "x": x, "y": y, "width": w, "height": h });
}
public update(colors: RGBW[]) {
@ -140,11 +172,11 @@ namespace pxsim.visuals {
if (!pixel) {
let cxy: Coord = [0, CANVAS_VIEW_PADDING + i * PIXEL_SPACING];
pixel = this.pixels[i] = new NeoPixel(cxy);
svg.hydrate(pixel.el, { title: `offset: ${i}` });
this.canvas.appendChild(pixel.el);
}
let color = colors[i];
pixel.setRgb(color);
svg.hydrate(pixel.el, {title: `offset: ${i}`});
}
//show the canvas if it's hidden
@ -164,7 +196,7 @@ namespace pxsim.visuals {
public setLoc(xy: Coord) {
let [x, y] = xy;
svg.hydrate(this.canvas, {x: x, y: y});
svg.hydrate(this.canvas, { x: x, y: y });
}
};
@ -232,7 +264,7 @@ namespace pxsim.visuals {
this.stripGroup.appendChild(part.el);
let canvas = new NeoPixelCanvas(this.pin);
this.canvas = canvas;
let canvasG = svg.child(this.stripGroup, "g", {class: "sim-neopixel-canvas-parent"});
let canvasG = svg.child(this.stripGroup, "g", { class: "sim-neopixel-canvas-parent" });
canvasG.appendChild(canvas.canvas);
this.updateStripLoc();
}
@ -245,12 +277,12 @@ namespace pxsim.visuals {
private updateStripLoc() {
let [x, y] = this.lastLocation;
this.canvas.setLoc([x + CANVAS_LEFT, y + CANVAS_TOP]);
svg.hydrate(this.part.el, {transform: `translate(${x} ${y})`}); //TODO: update part's l,h, etc.
svg.hydrate(this.part.el, { transform: `translate(${x} ${y})` }); //TODO: update part's l,h, etc.
}
public updateState(): void {
let colors = this.state.getColors(this.pin, this.mode);
this.canvas.update(colors);
}
public updateTheme (): void { }
public updateTheme(): void { }
}
}

View File

@ -163,6 +163,41 @@ namespace pxsim.visuals {
g.appendChild(el);
return {el: g, x: x1 - strokeWidth, y: Math.min(y1, y2), w: w1 + strokeWidth * 2, h: h1 + h2};
}
function mkSmallMBPinEnd(p: [number, number], top: boolean, clr: string): visuals.SVGElAndSize {
//HACK
//TODO: merge with mkOpenJumperEnd()
let k = visuals.PIN_DIST * 0.24;
let plasticLength = k * 4;
let plasticWidth = k * 1.2;
let metalLength = k * 10;
let metalWidth = k;
const strokeWidth = visuals.PIN_DIST / 4.0;
let [cx, cy] = p;
let yOffset = 10;
let o = top ? -1 : 1;
let g = svg.elt("g")
let el = svg.elt("rect");
let h1 = plasticLength;
let w1 = plasticWidth;
let x1 = cx - w1 / 2;
let y1 = cy + yOffset - (h1 / 2);
svg.hydrate(el, {x: x1, y: y1, width: w1, height: h1, rx: 0.5, ry: 0.5, class: "sim-bb-wire-end"});
(<any>el).style["stroke-width"] = `${strokeWidth}px`;
let el2 = svg.elt("rect");
let h2 = metalLength;
let w2 = metalWidth;
let cy2 = cy + yOffset + o * (h1 / 2 + h2 / 2);
let x2 = cx - w2 / 2;
let y2 = cy2 - (h2 / 2);
svg.hydrate(el2, {x: x2, y: y2, width: w2, height: h2, class: "sim-bb-wire-bare-end"});
(<any>el2).style["fill"] = `#bbb`;
g.appendChild(el2);
g.appendChild(el);
return {el: g, x: x1 - strokeWidth, y: Math.min(y1, y2), w: w1 + strokeWidth * 2, h: h1 + h2};
}
function mkCrocEnd(p: [number, number], top: boolean, clr: string): SVGElAndSize {
//TODO: merge with mkOpenJumperEnd()
let k = visuals.PIN_DIST * 0.24;
@ -325,7 +360,7 @@ namespace pxsim.visuals {
return {endG: endG, end1: end1, end2: end2, wires: wires};
}
private drawWireWithCrocs(pin1: Coord, pin2: Coord, color: string): Wire {
private drawWireWithCrocs(pin1: Coord, pin2: Coord, color: string, smallPin: boolean = false): Wire {
//TODO: merge with drawWire()
const PIN_Y_OFF = 40;
const CROC_Y_OFF = -17;
@ -349,7 +384,11 @@ namespace pxsim.visuals {
pin2 = [x2, y2 + PIN_Y_OFF];//HACK
[x2, y2] = pin2;
let endCoord2: Coord = [x2, y2 + CROC_Y_OFF]
let end2AndSize = mkCrocEnd(endCoord2, true, color);
let end2AndSize: SVGElAndSize;
if (smallPin)
end2AndSize = mkSmallMBPinEnd(endCoord2, true, color);
else
end2AndSize = mkCrocEnd(endCoord2, true, color);
let end2 = end2AndSize.el;
let endG = <SVGGElement>svg.child(g, "g", {class: "sim-bb-wire-ends-g"});
endG.appendChild(end1);
@ -415,7 +454,13 @@ namespace pxsim.visuals {
let endLoc = this.getLocCoord(end);
let wireEls: Wire;
if (withCrocs && end.type == "dalboard") {
wireEls = this.drawWireWithCrocs(startLoc, endLoc, color);
let boardPin = (<BoardLoc>end).pin;
if (boardPin == "P0" || boardPin == "P1" || boardPin == "P0" || boardPin == "GND" || boardPin == "+3v3" ) {
//HACK
wireEls = this.drawWireWithCrocs(startLoc, endLoc, color);
} else {
wireEls = this.drawWireWithCrocs(startLoc, endLoc, color, true);
}
} else {
wireEls = this.drawWire(startLoc, endLoc, color);
}