Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
90f7b229d1 | |||
c54e0b0e9d | |||
ea088ac828 | |||
29cf4d3e53 | |||
6d637eefd7 | |||
6310e96ac2 | |||
dbb1e31822 | |||
5376bc2dce | |||
57bd293df8 | |||
e570d46755 | |||
d37f284fce | |||
b716226889 | |||
1bd19cc1a0 | |||
ac8c9c5e85 | |||
057260c483 | |||
568ae32f81 | |||
ae605ff829 | |||
f25ddb1085 | |||
f175f973f0 | |||
c7e5fa490e | |||
61a29f7c67 | |||
50293fc654 | |||
a9ecadaf09 | |||
6e56107eb5 | |||
1f077beb65 | |||
8fff762156 | |||
cebded2526 | |||
13f53d730a | |||
8adcab1cab | |||
8cb5f442f9 | |||
96448d5237 | |||
30f01bb0ac | |||
3d0b397de2 | |||
e0de55d689 |
@ -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.
|
||||
|
@ -28,7 +28,7 @@ export function deployCoreAsync(res: ts.pxtc.CompileResult) {
|
||||
|
||||
function getBitDrivesAsync(): Promise<string[]> {
|
||||
if (process.platform == "win32") {
|
||||
let rx = new RegExp("^([A-Z]:).* " + pxt.appTarget.compile.deployDrives)
|
||||
const rx = new RegExp("^([A-Z]:).* " + pxt.appTarget.compile.deployDrives)
|
||||
return execAsync("wmic PATH Win32_LogicalDisk get DeviceID, VolumeName, FileSystem")
|
||||
.then(buf => {
|
||||
let res: string[] = []
|
||||
@ -42,9 +42,14 @@ function getBitDrivesAsync(): Promise<string[]> {
|
||||
})
|
||||
}
|
||||
else if (process.platform == "darwin") {
|
||||
let rx = new RegExp(pxt.appTarget.compile.deployDrives)
|
||||
const rx = new RegExp(pxt.appTarget.compile.deployDrives)
|
||||
return readDirAsync("/Volumes")
|
||||
.then(lst => lst.filter(s => rx.test(s)).map(s => "/Volumes/" + s + "/"))
|
||||
} else if (process.platform == "linux") {
|
||||
const rx = new RegExp(pxt.appTarget.compile.deployDrives)
|
||||
const user = process.env["USER"]
|
||||
return readDirAsync(`/media/${user}`)
|
||||
.then(lst => lst.filter(s => rx.test(s)).map(s => `/media/${user}/${s}/`))
|
||||
} else {
|
||||
return Promise.resolve([])
|
||||
}
|
||||
|
@ -1,19 +1,24 @@
|
||||
# Run Scripts on your micro:bit
|
||||
# Running programs on your micro:bit
|
||||
|
||||
How to compile, transfer, and run a script on your micro:bit.
|
||||
How to compile, transfer, and run a program on your micro:bit.
|
||||
|
||||
While you're writing and testing your scripts, you'll mostly be running scripts in your browser by clicking the `PLay` button
|
||||
(see [run code in your browser](/device/simulator) for info about this).
|
||||
While you're writing and testing your programs, you'll mostly be [running them
|
||||
in the simulator](/device/simulator), but once you've finished your program you
|
||||
can **compile** it and run it on your micro:bit.
|
||||
|
||||
Once your masterpiece is complete, you can compile your script and run it on your micro:bit.
|
||||
The basic steps are:
|
||||
|
||||
1. Connect your micro:bit to your computer via USB
|
||||
2. Click **Download** and download the `.hex` file
|
||||
3. Copy the `.hex` file from your computer onto the micro:bit drive
|
||||
|
||||
## Requirements
|
||||
|
||||
You need the following things to transfer and run a script on your micro:bit:
|
||||
|
||||
* A-Male to Micro USB cable to connect your computer to your micro:bit. This is the same cable that is commonly used to connect a smart phone to a computer.
|
||||
* a PC running Windows 7 of later, or a Mac running OS X 10.6 or later
|
||||
* access to the Internet
|
||||
* A-Male to Micro USB cable to connect your computer to your micro:bit. This is
|
||||
the same cable that is commonly used to connect a smart phone to a computer.
|
||||
* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later
|
||||
|
||||
## Step 1: Connect your micro:bit to your computer
|
||||
|
||||
@ -23,108 +28,151 @@ First, connect the micro:bit:
|
||||
|
||||
2. Connect the other end of the USB cable to a USB port on your computer.
|
||||
|
||||
Your computer should recognise your micro:bit as a new drive. On computers running Windows, MICROBIT appears as a drive under Devices and drives. On a Mac it appears as a new drive under Devices.
|
||||
Your computer should recognise your micro:bit as a new drive. On computers
|
||||
running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac
|
||||
it appears as a new drive under Devices.
|
||||
|
||||
Windows
|
||||
**Windows**
|
||||
|
||||

|
||||

|
||||
|
||||
Mac (picture bvabdbco)
|
||||
WARN: unknown picture: bvabdbco:5x3
|
||||
**Mac**
|
||||
|
||||
## Step 2: Compile your script
|
||||

|
||||
|
||||
Next, compile your script:
|
||||
## Step 2: Download your program
|
||||
|
||||
1. Sign in to Touch Develop on your computer.
|
||||
|
||||
2. Open your script (find the script in **My Scripts** and click `Edit`).
|
||||
|
||||
3. Click **Download**. Your script is converted into a hex file that you can transfer and run on your micro:bit.
|
||||
|
||||
4. When prompted, choose to save the compiled file on your computer (or anywhere other than the micro:bit). Depending on which browser you are using, the download will adopt the download behaviour of that particular browser.
|
||||
1. Open your project on [codethemicrobit.com](https://codethemicrobit.com)
|
||||
2. Click **Download**
|
||||
3. When prompted, choose to **save** the compiled file onto your computer. The
|
||||
prompt will be different depending on which browser you are using, or
|
||||
whether you are using a Windows computer or a Mac
|
||||
|
||||
### Windows
|
||||
|
||||
** Chrome**
|
||||
#### Chrome
|
||||
|
||||
Your .hex file appears as a download at the bottom of the browser. Open up your windows file explorer. Your micro:bit appears as a drive called MICROBIT.
|
||||
Your `.hex` file appears as a download at the bottom of the browser. Click on
|
||||
the arrow next to the name of the file and then click **Show in folder**.
|
||||
|
||||
**Right click** on the download and select **show in folder**. Drag and drop the hex file from the download folder onto the MICROBIT drive.
|
||||

|
||||
|
||||
Alternatively, you can drag and drop the downloaded hex file from the bottom of the browser onto the file explorer and onto the MICROBIT drive.
|
||||
Drag and drop the `.hex` file from the download folder onto the `MICROBIT` drive.
|
||||
|
||||

|
||||
#### Firefox
|
||||
|
||||
**Firefox**
|
||||
A window will appear asking whether you want to save or open the `.hex` file.
|
||||
Select **Save File** and then select **OK**.
|
||||
|
||||
A dialogue box will appear, asking whether you would like to open or save your hex file. Select **Save**, then **OK** and the file will appear in your downloads in the top right of your browser. Select the **blue arrow**, select the relevant file and drag and drop it onto your Windows Explorer and onto your MICROBIT drive.
|
||||

|
||||
|
||||

|
||||
The file will then appear in your downloads in the top right of your browser.
|
||||
Click the **folder icon** next to the filename to open it in Windows Explorer.
|
||||
|
||||

|
||||

|
||||
|
||||
**IE10**
|
||||
Drag and drop the `.hex` file from the download folder onto the `MICROBIT` drive.
|
||||
|
||||
Click on **Download**. You will see a message “Do you want to save this .hex file.” Select **Save**.
|
||||
#### Microsoft Edge
|
||||
|
||||
A message will appear at the bottom of the browser asking what you want to do
|
||||
with the file. Click **Save**:
|
||||
|
||||

|
||||
|
||||
Then click **Open folder** and drag and drop the file from your Downloads to
|
||||
your `MICROBIT` drive.
|
||||
|
||||

|
||||
|
||||
#### Internet Explorer
|
||||
|
||||
A message will appear at the bottom of the browser asking what you want to do
|
||||
with the file. Click **Save**:
|
||||
|
||||

|
||||
|
||||
Then click **Open folder** and drag and drop the file from your Downloads to
|
||||
your `MICROBIT` drive.
|
||||
|
||||

|
||||
|
||||
### Mac
|
||||
|
||||
** Safari**
|
||||
#### Safari
|
||||
|
||||
When you select **Download** in Safari on Mac, your file will be downloaded to your downloads folder. Go to your downloads folder and open the file. In Safari the file will appear as unknown.txt rather than a named .hex file. Drag and drop it onto your MICROBIT drive.
|
||||
When you select **Download** in Safari a file called `Unknown` will be
|
||||
downloaded into your Downloads folder. Open your Downloads folder and drag and
|
||||
drop the file onto your `MICROBIT` drive, under Devices:
|
||||
|
||||

|
||||

|
||||
|
||||
**Firefox**
|
||||
#### Firefox
|
||||
|
||||
A dialogue box will appear, asking whether you would like to open or save your hex file. Select **Save** and **OK** and the file will then appear in your downloads in the top right of your browser. Click on **Show in Finder** and the file will appear in your downloads folder. Select the file and drag and drop it onto your MICROBIT drive.
|
||||
A dialogue box will appear, asking whether you would like to open or save your
|
||||
hex file. Select **Save file** and click **OK** and the file will then appear in
|
||||
your downloads in the top right of your browser. Right click on the file and
|
||||
click on **Show in Finder** and the file will appear in your downloads folder.
|
||||
Select the file and drag and drop it onto your `MICROBIT` drive.
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
**Chrome**
|
||||
#### Chrome
|
||||
|
||||
When you select **Download** in Chrome, the file will be downloaded to the bottom of the browser in .hex format. Click on the small arrow and select **Show in Finder**. This will show the file in your download folder. Drag and drop the file onto your MICROBIT drive.
|
||||
When you select **Download** in Chrome, the file will appear at the bottom of
|
||||
the browser. Click on the small arrow and select **Show in Finder**. This will
|
||||
show the file in your download folder. Drag and drop the file onto your
|
||||
`MICROBIT` drive.
|
||||
|
||||

|
||||

|
||||
|
||||
## Step 3: Transfer the file to your micro:bit
|
||||
|
||||
1. The file will transfer onto your micro:bit.
|
||||
|
||||
2. If you're using Windows, you can use **Send to** as described below.
|
||||
|
||||
3. The LED on the back of your micro:bit flashes during the transfer (which should only take a few seconds).
|
||||
|
||||
4. Once transferred, the code will run automatically on your micro:bit. To rerun your program, press the reset button on the back of your micro:bit. The reset button automatically runs the newest file on the micro:bit.
|
||||
* Once you've found the folder containing your `.hex` file, drag and drop it
|
||||
onto your `MICROBIT` drive
|
||||
* If you're using Windows, you can use **Send to** as described below
|
||||
* The LED on the back of your micro:bit flashes during the transfer (which
|
||||
should only take a few seconds).
|
||||
* Once transferred, the code will run automatically on your micro:bit. To rerun
|
||||
your program, press the reset button on the back of your micro:bit. The reset
|
||||
button automatically runs the newest file on the micro:bit.
|
||||
|
||||
**Send to**: If you're using Windows you use *Send to* in File Explorer:
|
||||
|
||||
- In File Explorer, right-click on the hex file (created in Step 2 above), choose **Send to**, and then **MICROBIT**.
|
||||
|
||||

|
||||

|
||||
|
||||
By copying the script onto the 'MICROBIT' drive, you have programmed it into the flash memory on the micro:bit, which means even after you unplug the micro:bit, your script will still run if the micro:bit is powered by battery.
|
||||
By copying the script onto the `MICROBIT` drive, you have programmed it into the
|
||||
flash memory on the micro:bit, which means even after you unplug the micro:bit,
|
||||
your program will still run if the micro:bit is powered by battery.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
You can’t drag and drop more than one hex file at once onto your micro:bit. If you try to drag and drop a second hex file onto your micro:bit before the first file has finished downloading, then the second file may fail in different ways.
|
||||
You can’t drag and drop more than one hex file at once onto your micro:bit. If
|
||||
you try to drag and drop a second hex file onto your micro:bit before the first
|
||||
file has finished downloading, then the second file may fail in different ways.
|
||||
|
||||
When the first program has been written to the micro:bit, the drive will disengage. If you drag and drop a second file at this point it may not find the drive and the second write will fail.
|
||||
When the first program has been written to the micro:bit, the drive will
|
||||
disengage. If you drag and drop a second file at this point it may not find the
|
||||
drive and the second write will fail.
|
||||
|
||||
The errors may look like this:
|
||||
|
||||
**Windows**
|
||||
|
||||

|
||||

|
||||
|
||||
**Mac**
|
||||
|
||||

|
||||

|
||||
|
||||
Or it may appear that there are two hex files on your micro:bit so the micro:bit won’t be able to run multiple files. To rectify this, unplug your micro:bit and plug it in again. Make sure that your micro:bit appears as MICROBIT and not MAINTENANCE.
|
||||
Or it may appear that there are two hex files on your micro:bit so the micro:bit
|
||||
won’t be able to run multiple files. To rectify this, unplug your micro:bit and
|
||||
plug it in again. Make sure that your micro:bit appears as `MICROBIT` and not
|
||||
`MAINTENANCE`.
|
||||
|
||||
### See also
|
||||
|
||||
|
BIN
docs/static/mb/device/pins-0.png
vendored
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 77 KiB |
BIN
docs/static/mb/device/usb-1.jpg
vendored
Before Width: | Height: | Size: 391 KiB |
BIN
docs/static/mb/device/usb-10.png
vendored
Before Width: | Height: | Size: 25 KiB |
BIN
docs/static/mb/device/usb-2.jpg
vendored
Before Width: | Height: | Size: 289 KiB |
BIN
docs/static/mb/device/usb-3.jpg
vendored
Before Width: | Height: | Size: 385 KiB |
BIN
docs/static/mb/device/usb-4.jpg
vendored
Before Width: | Height: | Size: 180 KiB |
BIN
docs/static/mb/device/usb-5.jpg
vendored
Before Width: | Height: | Size: 121 KiB |
BIN
docs/static/mb/device/usb-6.jpg
vendored
Before Width: | Height: | Size: 336 KiB |
BIN
docs/static/mb/device/usb-7.jpg
vendored
Before Width: | Height: | Size: 324 KiB |
BIN
docs/static/mb/device/usb-osx-chrome.png
vendored
Normal file
After Width: | Height: | Size: 186 KiB |
BIN
docs/static/mb/device/usb-osx-copy-file-error.png
vendored
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
docs/static/mb/device/usb-osx-device.png
vendored
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
docs/static/mb/device/usb-osx-dnd.png
vendored
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
docs/static/mb/device/usb-osx-firefox-1.png
vendored
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
docs/static/mb/device/usb-osx-firefox-2.png
vendored
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
docs/static/mb/device/usb-windows-chrome.png
vendored
Normal file
After Width: | Height: | Size: 162 KiB |
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 164 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
BIN
docs/static/mb/device/usb-windows-edge-1.png
vendored
Normal file
After Width: | Height: | Size: 156 KiB |
BIN
docs/static/mb/device/usb-windows-edge-2.png
vendored
Normal file
After Width: | Height: | Size: 135 KiB |
BIN
docs/static/mb/device/usb-windows-firefox-1.png
vendored
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
docs/static/mb/device/usb-windows-firefox-2.png
vendored
Normal file
After Width: | Height: | Size: 120 KiB |
BIN
docs/static/mb/device/usb-windows-ie11-1.png
vendored
Normal file
After Width: | Height: | Size: 164 KiB |
BIN
docs/static/mb/device/usb-windows-ie11-2.png
vendored
Normal file
After Width: | Height: | Size: 159 KiB |
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 160 KiB |
BIN
docs/static/mb/js/basicFuns.png
vendored
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 15 KiB |
BIN
docs/static/mb/js/basicIntell.png
vendored
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 22 KiB |
BIN
docs/static/mb/js/forIntell.png
vendored
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 7.9 KiB |
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pxt-microbit",
|
||||
"version": "0.3.73",
|
||||
"version": "0.3.77",
|
||||
"description": "micro:bit target for PXT",
|
||||
"keywords": [
|
||||
"JavaScript",
|
||||
@ -29,6 +29,6 @@
|
||||
"typescript": "^1.8.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"pxt-core": "0.3.84"
|
||||
"pxt-core": "0.3.90"
|
||||
}
|
||||
}
|
||||
|
170
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") {
|
||||
@ -164,17 +230,25 @@ namespace pxsim {
|
||||
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"];
|
||||
@ -189,30 +263,67 @@ namespace pxsim {
|
||||
}
|
||||
const GROUND_COLOR = "blue";
|
||||
const POWER_COLOR = "red";
|
||||
const wires: WireInst[] = [
|
||||
{start: this.allocateLocation("ground", {nearestBBPin: top}),
|
||||
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: 0},
|
||||
{start: this.allocateLocation("ground", {nearestBBPin: top}),
|
||||
end: {type: "dalboard", pin: boardGround},
|
||||
color: GROUND_COLOR, assemblyStep: 0},
|
||||
{start: this.allocateLocation("threeVolt", {nearestBBPin: top}),
|
||||
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: 1},
|
||||
{start: this.allocateLocation("threeVolt", {nearestBBPin: top}),
|
||||
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: 1},
|
||||
];
|
||||
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,
|
||||
@ -414,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]));
|
||||
|
@ -131,7 +131,8 @@ namespace pxsim.instructions {
|
||||
wireClr?: string,
|
||||
cmpWidth?: number,
|
||||
cmpHeight?: number,
|
||||
cmpScale?: number
|
||||
cmpScale?: number,
|
||||
crocClips?: boolean
|
||||
};
|
||||
function mkBoardImgSvg(def: string | BoardImageDefinition): visuals.SVGElAndSize {
|
||||
let boardView: visuals.BoardView;
|
||||
@ -154,7 +155,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);
|
||||
@ -181,7 +182,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) {
|
||||
@ -287,13 +288,13 @@ namespace pxsim.instructions {
|
||||
let el: visuals.SVGElAndSize;
|
||||
if (cmp == "wire") {
|
||||
//TODO: support non-croc wire parts
|
||||
el = visuals.mkWirePart([0, 0], opts.wireClr || "red", true);
|
||||
el = visuals.mkWirePart([0, 0], opts.wireClr || "red", opts.crocClips);
|
||||
} else if (typeof cmp == "string") {
|
||||
let builtinVis = <string>cmp;
|
||||
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);
|
||||
@ -320,8 +321,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;
|
||||
@ -451,10 +452,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
|
||||
@ -481,7 +482,8 @@ namespace pxsim.instructions {
|
||||
left: QUANT_LBL(quant),
|
||||
leftSize: WIRE_QUANT_LBL_SIZE,
|
||||
wireClr: clr,
|
||||
cmpScale: PARTS_WIRE_SCALE
|
||||
cmpScale: PARTS_WIRE_SCALE,
|
||||
crocClips: props.boardDef.useCrocClips
|
||||
})
|
||||
addClass(cmp, "partslist-wire");
|
||||
panel.appendChild(cmp);
|
||||
@ -526,7 +528,8 @@ namespace pxsim.instructions {
|
||||
bot: mkLabel(w.start),
|
||||
botSize: LOC_LBL_SIZE,
|
||||
wireClr: w.color,
|
||||
cmpHeight: REQ_WIRE_HEIGHT
|
||||
cmpHeight: REQ_WIRE_HEIGHT,
|
||||
crocClips: props.boardDef.useCrocClips
|
||||
})
|
||||
addClass(cmp, "cmp-div");
|
||||
reqsDiv.appendChild(cmp);
|
||||
@ -592,7 +595,7 @@ namespace pxsim.instructions {
|
||||
//we use the docs renderer to decompile the code to blocks and render it
|
||||
//TODO: render the blocks code directly
|
||||
let md =
|
||||
`\`\`\`blocks
|
||||
`\`\`\`blocks
|
||||
${tsCode}
|
||||
\`\`\`
|
||||
\`\`\`package
|
||||
@ -600,9 +603,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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
@ -58,7 +77,7 @@ namespace pxsim.visuals {
|
||||
|
||||
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;
|
||||
@ -161,7 +180,7 @@ namespace pxsim.visuals {
|
||||
height: h,
|
||||
"href": `${opts.image}`
|
||||
});
|
||||
return {el: img, w: w, h: h, x: 0, y: 0};
|
||||
return { el: img, w: w, h: h, x: 0, y: 0 };
|
||||
}
|
||||
|
||||
export type Coord = [number, number];
|
||||
@ -195,8 +214,10 @@ namespace pxsim.visuals {
|
||||
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)
|
||||
}
|
||||
|
||||
|