Compare commits
45 Commits
Author | SHA1 | Date | |
---|---|---|---|
f175f973f0 | |||
c7e5fa490e | |||
61a29f7c67 | |||
50293fc654 | |||
a9ecadaf09 | |||
6e56107eb5 | |||
1f077beb65 | |||
8fff762156 | |||
cebded2526 | |||
13f53d730a | |||
8adcab1cab | |||
8cb5f442f9 | |||
96448d5237 | |||
30f01bb0ac | |||
3d0b397de2 | |||
e0de55d689 | |||
7637a98f07 | |||
95f94e0886 | |||
9a2367cf8e | |||
15fecb77c4 | |||
4f69bbabfb | |||
8351ed0513 | |||
c34b0a1aeb | |||
9bcd44d7e4 | |||
3403da8ce8 | |||
39c146329f | |||
8d0d0a7e9a | |||
61b3783dd4 | |||
da16428842 | |||
359c456577 | |||
b3d9c167e1 | |||
78398b220f | |||
a656fbbd7b | |||
e681cc8c97 | |||
03beec9c49 | |||
1600644be5 | |||
a3dd64eb4c | |||
b865cce44e | |||
dc42900c7f | |||
dcc3bd95fe | |||
4070d4e691 | |||
7048156b46 | |||
232758805b | |||
211d4e5538 | |||
374d8c590d |
@ -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.
|
||||
|
@ -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
|
||||
|
43
libs/microbit-bluetooth/bluetooth.ts
Normal file
43
libs/microbit-bluetooth/bluetooth.ts
Normal 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 "???"
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
"README.md",
|
||||
"enums.d.ts",
|
||||
"shims.d.ts",
|
||||
"bluetooth.ts",
|
||||
"bluetooth.cpp"
|
||||
],
|
||||
"public": true,
|
||||
|
24
libs/microbit-bluetooth/shims.d.ts
vendored
24
libs/microbit-bluetooth/shims.d.ts
vendored
@ -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
|
||||
|
@ -37,4 +37,11 @@ namespace control {
|
||||
panic(98)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display warning in the simulator.
|
||||
*/
|
||||
//% shim=pxtrt::runtimeWarning
|
||||
export function runtimeWarning(message: string) {
|
||||
}
|
||||
}
|
||||
|
@ -316,4 +316,9 @@ namespace pxtrt {
|
||||
void* getGlobalsPtr() {
|
||||
return globals;
|
||||
}
|
||||
|
||||
//%
|
||||
void runtimeWarning(StringData *s) {
|
||||
// noop for now
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
@ -27,6 +27,8 @@
|
||||
"serial.cpp",
|
||||
"serial.ts",
|
||||
"buffer.cpp",
|
||||
"pxtparts.json",
|
||||
"parts/speaker.svg",
|
||||
"_locales/fr/microbit-jsdoc-strings.json"
|
||||
],
|
||||
"public": true,
|
||||
|
78
libs/microbit/pxtparts.json
Normal file
78
libs/microbit/pxtparts.json
Normal 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}
|
||||
]
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
188
sim/allocator.ts
188
sim/allocator.ts
@ -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]));
|
||||
|
@ -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({
|
||||
|
@ -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(),
|
||||
|
@ -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({});
|
||||
|
@ -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",
|
||||
|
3
sim/public/parts/.gitignore
vendored
3
sim/public/parts/.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
# don't check in until OSS request is approved
|
||||
sparkfun-*
|
||||
raspberrypi-*
|
||||
arduino-*
|
||||
arduino-*
|
||||
max6675*
|
||||
|
@ -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%;
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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 { }
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user