2018-02-27 00:16:17 +01:00
|
|
|
/**
|
|
|
|
* Tagged image literal converter
|
|
|
|
*/
|
|
|
|
//% shim=@f4 helper=image::ofBuffer
|
|
|
|
//% groups=["0.,","1#*"]
|
|
|
|
function img(lits: any, ...args: any[]): Image { return null }
|
|
|
|
|
2018-03-28 18:04:49 +02:00
|
|
|
const screen = image.create(DAL.LCD_WIDTH, DAL.LCD_HEIGHT)
|
2018-02-27 00:16:17 +01:00
|
|
|
|
|
|
|
namespace _screen_internal {
|
|
|
|
//% shim=pxt::updateScreen
|
2018-03-28 17:50:14 +02:00
|
|
|
function updateScreen(img: Image): void { }
|
2018-02-27 06:25:04 +01:00
|
|
|
//% shim=pxt::updateStats
|
2018-03-28 17:50:14 +02:00
|
|
|
function updateStats(msg: string): void { }
|
2018-02-27 00:16:17 +01:00
|
|
|
|
2018-03-28 18:04:49 +02:00
|
|
|
control.__screen.setupUpdate(() => updateScreen(screen))
|
2018-04-03 13:30:23 +02:00
|
|
|
control.EventContext.onStats = function (msg: string) {
|
2018-03-28 18:04:49 +02:00
|
|
|
updateStats(msg);
|
2018-02-27 00:16:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace brick {
|
2018-04-03 13:30:23 +02:00
|
|
|
const textOffset = 4;
|
|
|
|
const lineOffset = 2;
|
2023-05-06 00:46:43 +02:00
|
|
|
|
2018-04-11 17:00:22 +02:00
|
|
|
enum ScreenMode {
|
|
|
|
None,
|
|
|
|
ShowLines,
|
|
|
|
Image,
|
2019-09-28 01:45:57 +02:00
|
|
|
Ports,
|
2018-04-11 17:00:22 +02:00
|
|
|
Custom
|
|
|
|
}
|
2023-05-06 00:46:43 +02:00
|
|
|
|
2023-05-06 00:58:52 +02:00
|
|
|
export enum PrintStyle {
|
|
|
|
//% block="black on white"
|
|
|
|
BlackOnWhite,
|
|
|
|
//% block="white on black"
|
|
|
|
WhiteOnBlack
|
|
|
|
}
|
|
|
|
|
2018-04-11 17:00:22 +02:00
|
|
|
let screenMode = ScreenMode.None;
|
2018-04-03 13:30:23 +02:00
|
|
|
export let font = image.font8;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the text line height
|
|
|
|
*/
|
|
|
|
//%
|
|
|
|
export function lineHeight(): number {
|
|
|
|
return font.charHeight + lineOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Number of lines
|
|
|
|
*/
|
|
|
|
//%
|
|
|
|
export function lineCount(): number {
|
|
|
|
return ((screen.height - textOffset) / lineHeight()) >> 0
|
|
|
|
}
|
2018-02-27 00:16:17 +01:00
|
|
|
|
2023-05-06 00:58:52 +02:00
|
|
|
/**
|
|
|
|
* Number of columns
|
|
|
|
*/
|
|
|
|
//%
|
|
|
|
export function columnCount(): number {
|
|
|
|
return ((screen.width - textOffset) / font.charWidth) >> 0
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Show text on the screen on a specific line and starting at a column and the selected print style.
|
|
|
|
* @param text the text to print on the screen, eg: "Hello world"
|
|
|
|
* @param line the line number to print the text at (starting at 1), eg: 1
|
|
|
|
* @param column the column number to print the text at (starting at 1), eg: 1
|
|
|
|
* @param printStyle print style black on white or white on black
|
|
|
|
*/
|
|
|
|
//% blockId=screenPrintString block="show string $text|at line $line||column $column|style $printStyle"
|
|
|
|
//% weight=98 group="Screen" inlineInputMode="inline" blockGap=8
|
|
|
|
//% expandableArgumentMode="enabled"
|
|
|
|
//% help=brick/show-string
|
|
|
|
//% line.min=1 line.max=12
|
|
|
|
//% column.min=1 column.max=29
|
|
|
|
export function printString(text: string, line: number, column: number = 1, printStyle: PrintStyle = PrintStyle.BlackOnWhite) {
|
|
|
|
if (screenMode != ScreenMode.ShowLines) {
|
|
|
|
screenMode = ScreenMode.ShowLines;
|
|
|
|
screen.fill(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
line = (line - 1) >> 0; // line indexing starts at 1
|
|
|
|
column = (column - 1) >> 0; // column indexing starts at 1
|
|
|
|
const nlines = lineCount();
|
|
|
|
const nColumn = columnCount();
|
|
|
|
if (line < 0 || line > nlines) return; // out of screen by line
|
|
|
|
if (column < 0 || column > nColumn) return; // out of screen by column
|
|
|
|
|
|
|
|
const w = font.charWidth;
|
|
|
|
const h = lineHeight();
|
|
|
|
const x = textOffset + w * column;
|
|
|
|
const y = textOffset + h * line;
|
|
|
|
screen.fillRect(x, y, text.length * font.charWidth, h, (printStyle == PrintStyle.BlackOnWhite ? 0 : 255)); // clear background
|
|
|
|
screen.print(text, x, y, (printStyle == PrintStyle.BlackOnWhite ? 1 : 2), font);
|
|
|
|
}
|
|
|
|
|
2018-02-27 00:16:17 +01:00
|
|
|
/**
|
|
|
|
* Show text on the screen at a specific line.
|
|
|
|
* @param text the text to print on the screen, eg: "Hello world"
|
2018-04-03 13:30:23 +02:00
|
|
|
* @param line the line number to print the text at (starting at 1), eg: 1
|
2018-02-27 00:16:17 +01:00
|
|
|
*/
|
|
|
|
//% blockId=screen_print block="show string %text|at line %line"
|
|
|
|
//% weight=98 group="Screen" inlineInputMode="inline" blockGap=8
|
|
|
|
//% help=brick/show-string
|
2023-05-06 00:58:52 +02:00
|
|
|
//% line.min=1 line.max=12
|
|
|
|
//% deprecated=true
|
2018-02-27 00:16:17 +01:00
|
|
|
export function showString(text: string, line: number) {
|
2018-04-11 17:00:22 +02:00
|
|
|
if (screenMode != ScreenMode.ShowLines) {
|
|
|
|
screenMode = ScreenMode.ShowLines;
|
|
|
|
screen.fill(0);
|
|
|
|
}
|
|
|
|
|
2018-04-03 13:30:23 +02:00
|
|
|
// line indexing starts at 1.
|
|
|
|
line = (line - 1) >> 0;
|
|
|
|
const nlines = lineCount();
|
|
|
|
if (line < 0 || line > nlines) return; // out of screen
|
|
|
|
|
|
|
|
const h = lineHeight();
|
|
|
|
const y = textOffset + h * line;
|
|
|
|
screen.fillRect(0, y, screen.width, h, 0); // clear background
|
|
|
|
screen.print(text, textOffset, y, 1, font);
|
2018-02-27 00:16:17 +01:00
|
|
|
}
|
|
|
|
|
2023-05-06 00:58:52 +02:00
|
|
|
/**
|
|
|
|
* Show a number on the screen on a specific line and starting at a column and the selected print style.
|
|
|
|
* @param value the numeric value
|
|
|
|
* @param line the line number to print the text at, eg: 1
|
|
|
|
* @param column the column number to print the text at (starting at 1), eg: 1
|
|
|
|
* @param printStyle print style black on white or white on black
|
|
|
|
*/
|
|
|
|
//% blockId=screenPrintNumber block="show number $value|at line $line||column $column|style $printStyle"
|
|
|
|
//% weight=97 group="Screen" inlineInputMode="inline" blockGap=8
|
|
|
|
//% expandableArgumentMode="enabled"
|
|
|
|
//% help=brick/show-number
|
|
|
|
//% line.min=1 line.max=12
|
|
|
|
//% column.min=1 column.max=29
|
|
|
|
export function printNumber(value: number, line: number, column: number = 1, printStyle: PrintStyle = PrintStyle.BlackOnWhite) {
|
|
|
|
printString("" + value, line, column, printStyle);
|
|
|
|
}
|
|
|
|
|
2018-02-27 00:16:17 +01:00
|
|
|
/**
|
2018-03-30 01:43:17 +02:00
|
|
|
* Show a number on the screen
|
2018-02-27 00:16:17 +01:00
|
|
|
* @param value the numeric value
|
|
|
|
* @param line the line number to print the text at, eg: 1
|
|
|
|
*/
|
|
|
|
//% blockId=screenShowNumber block="show number %name|at line %line"
|
2023-05-06 00:58:52 +02:00
|
|
|
//% weight=97 group="Screen" inlineInputMode="inline" blockGap=8
|
2018-02-27 00:16:17 +01:00
|
|
|
//% help=brick/show-number
|
2023-05-06 00:58:52 +02:00
|
|
|
//% line.min=1 line.max=12
|
|
|
|
//% deprecated=true
|
2018-02-27 00:16:17 +01:00
|
|
|
export function showNumber(value: number, line: number) {
|
|
|
|
showString("" + value, line);
|
|
|
|
}
|
|
|
|
|
2023-05-06 00:58:52 +02:00
|
|
|
/**
|
|
|
|
* Show a name, value pair on the screen on a specific line and starting at a column and the selected print style.
|
|
|
|
* @param name the value name
|
|
|
|
* @param value the numeric value
|
|
|
|
* @param line the line number to print the text at, eg: 1
|
|
|
|
* @param column the column number to print the text at (starting at 1), eg: 1
|
|
|
|
* @param printStyle print style black on white or white on black
|
|
|
|
*/
|
|
|
|
//% blockId=screenPrintValue block="show value $name|= $value|at line $line||column $column|style $printStyle"
|
|
|
|
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
|
|
|
|
//% expandableArgumentMode="enabled"
|
|
|
|
//% help=brick/show-value
|
|
|
|
//% line.min=1 line.max=12
|
|
|
|
//% column.min=1 column.max=29
|
|
|
|
export function printValue(name: string, value: number, line: number, column: number = 1, printStyle: PrintStyle = PrintStyle.BlackOnWhite) {
|
|
|
|
value = Math.round(value * 1000) / 1000;
|
|
|
|
printString((name ? name + ": " : "") + value, line, column, printStyle);
|
|
|
|
}
|
|
|
|
|
2018-02-27 00:16:17 +01:00
|
|
|
/**
|
2018-03-30 01:43:17 +02:00
|
|
|
* Show a name, value pair on the screen
|
2018-02-27 00:16:17 +01:00
|
|
|
* @param value the numeric value
|
|
|
|
* @param line the line number to print the text at, eg: 1
|
|
|
|
*/
|
|
|
|
//% blockId=screenShowValue block="show value %name|= %text|at line %line"
|
|
|
|
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
|
|
|
|
//% help=brick/show-value
|
2023-05-06 00:58:52 +02:00
|
|
|
//% line.min=1 line.max=12
|
|
|
|
//% deprecated=true
|
2018-02-27 00:16:17 +01:00
|
|
|
export function showValue(name: string, value: number, line: number) {
|
|
|
|
value = Math.round(value * 1000) / 1000;
|
2018-03-28 17:50:14 +02:00
|
|
|
showString((name ? name + ": " : "") + value, line);
|
2018-02-27 00:16:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Show an image on the screen
|
|
|
|
* @param image image to draw
|
2018-04-06 05:42:03 +02:00
|
|
|
* @param duration duration in milliseconds to display the image, eg: 400
|
2018-02-27 00:16:17 +01:00
|
|
|
*/
|
|
|
|
//% blockId=screen_show_image block="show image %image=screen_image_picker"
|
|
|
|
//% weight=100 group="Screen" blockGap=8
|
|
|
|
//% help=brick/show-image
|
2018-04-06 05:42:03 +02:00
|
|
|
export function showImage(image: Image, duration: number = 400) {
|
2018-02-27 00:16:17 +01:00
|
|
|
if (!image) return;
|
2018-04-11 17:00:22 +02:00
|
|
|
screenMode = ScreenMode.Image;
|
2018-04-06 05:42:03 +02:00
|
|
|
screen.fill(0);
|
|
|
|
screen.drawImage(image, 0, 0);
|
|
|
|
if (duration > 0)
|
|
|
|
pause(duration);
|
2018-02-27 00:16:17 +01:00
|
|
|
}
|
|
|
|
|
2018-03-28 17:50:14 +02:00
|
|
|
/**
|
2018-03-30 01:43:17 +02:00
|
|
|
* Display the status of the sensors and motors attached to ports
|
2018-03-28 17:50:14 +02:00
|
|
|
*/
|
|
|
|
//% blockId=brickShowPorts block="show ports"
|
|
|
|
//% help=brick/show-ports blockGap=8
|
2023-05-06 00:58:52 +02:00
|
|
|
//% weight=95 group="Screen"
|
2018-03-28 17:50:14 +02:00
|
|
|
export function showPorts() {
|
2019-09-28 01:45:57 +02:00
|
|
|
if (screenMode == ScreenMode.Ports) return;
|
|
|
|
screenMode = ScreenMode.Ports;
|
2023-05-06 00:46:43 +02:00
|
|
|
|
2019-09-28 01:45:57 +02:00
|
|
|
renderPorts();
|
2019-10-10 18:15:57 +02:00
|
|
|
control.runInParallel(function () {
|
|
|
|
while (screenMode == ScreenMode.Ports) {
|
2019-09-28 01:45:57 +02:00
|
|
|
renderPorts();
|
|
|
|
pause(50);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2018-04-11 17:00:22 +02:00
|
|
|
|
2019-09-28 01:45:57 +02:00
|
|
|
function renderPorts() {
|
2018-03-28 17:50:14 +02:00
|
|
|
const col = 44;
|
2018-04-03 13:30:23 +02:00
|
|
|
const lineHeight8 = image.font8.charHeight + 2;
|
2019-10-10 18:15:57 +02:00
|
|
|
const h = screen.height;
|
|
|
|
|
2018-03-28 17:50:14 +02:00
|
|
|
clearScreen();
|
|
|
|
|
2019-10-10 18:15:57 +02:00
|
|
|
for (let i = 0; i < 4; ++i) {
|
|
|
|
const x = i * col + 2;
|
2023-05-06 00:46:43 +02:00
|
|
|
if (screenMode != ScreenMode.Ports) return;
|
|
|
|
screen.print("ABCD"[i], x, 1 * lineHeight8, 1, image.font8);
|
|
|
|
screen.print((i + 1).toString(), x, h - lineHeight8, 1, image.font8);
|
2019-10-10 18:15:57 +02:00
|
|
|
}
|
2023-05-06 00:46:43 +02:00
|
|
|
|
|
|
|
if (screenMode != ScreenMode.Ports) return;
|
2019-10-10 18:15:57 +02:00
|
|
|
screen.drawLine(0, 5 * lineHeight8, screen.width, 5 * lineHeight8, 1);
|
2023-05-06 00:46:43 +02:00
|
|
|
screen.drawLine(0, h - 5 * lineHeight8, screen.width, h - 5 * lineHeight8, 1);
|
2019-10-10 18:15:57 +02:00
|
|
|
|
2018-03-28 17:50:14 +02:00
|
|
|
function scale(x: number) {
|
2019-09-28 01:45:57 +02:00
|
|
|
if (Math.abs(x) >= 5000) {
|
|
|
|
const k = Math.floor(x / 1000);
|
|
|
|
const r = Math.round((x - 1000 * k) / 100);
|
|
|
|
return `${k}.${r}k`
|
|
|
|
}
|
|
|
|
return ("" + (x || 0));
|
2018-03-28 17:50:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// motors
|
|
|
|
const datas = motors.getAllMotorData();
|
|
|
|
for (let i = 0; i < datas.length; ++i) {
|
|
|
|
const data = datas[i];
|
2019-10-10 18:15:57 +02:00
|
|
|
const x = i * col + 2;
|
2018-03-28 17:50:14 +02:00
|
|
|
if (!data.actualSpeed && !data.count) continue;
|
2023-05-06 00:46:43 +02:00
|
|
|
if (screenMode != ScreenMode.Ports) return;
|
|
|
|
screen.print(`${scale(data.actualSpeed)}%`, x, 3 * lineHeight8, 1, image.font8);
|
|
|
|
screen.print(`${scale(data.count)}>`, x, 4 * lineHeight8, 1, image.font8);
|
2018-03-28 17:50:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// sensors
|
|
|
|
const sis = sensors.internal.getActiveSensors();
|
|
|
|
for (let i = 0; i < sis.length; ++i) {
|
|
|
|
const si = sis[i];
|
2019-10-10 18:15:57 +02:00
|
|
|
const x = (si.port() - 1) * col + 2;
|
2018-03-28 17:50:14 +02:00
|
|
|
const inf = si._info();
|
2023-05-06 00:46:43 +02:00
|
|
|
if (screenMode != ScreenMode.Ports) return;
|
|
|
|
if (inf) screen.print(inf, x, h - 2 * lineHeight8, 1, inf.length > 4 ? image.font5 : image.font8);
|
2018-03-28 17:50:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-10 18:15:57 +02:00
|
|
|
export function showBoot() {
|
|
|
|
// pulse green, play startup sound, turn off light
|
|
|
|
brick.setStatusLight(StatusLight.GreenPulse);
|
2023-05-06 00:46:43 +02:00
|
|
|
// We pause to give time to read sensor values, so they work in on_start block
|
|
|
|
pause(400); // It turns out that this time is not enough for the simulator to display the LED change
|
2019-10-10 18:15:57 +02:00
|
|
|
// and we're ready
|
|
|
|
brick.setStatusLight(StatusLight.Off);
|
|
|
|
// always show port by default if no UI is set
|
|
|
|
control.runInParallel(function () {
|
|
|
|
// show ports if nothing is has been shown
|
|
|
|
if (screenMode != ScreenMode.None) return;
|
|
|
|
showPorts();
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-02-27 00:16:17 +01:00
|
|
|
/**
|
|
|
|
* An image
|
|
|
|
* @param image the image
|
|
|
|
*/
|
|
|
|
//% blockId=screen_image_picker block="%image" shim=TD_ID
|
|
|
|
//% image.fieldEditor="images"
|
|
|
|
//% image.fieldOptions.columns=6
|
|
|
|
//% image.fieldOptions.width=600
|
|
|
|
//% group="Screen" weight=0 blockHidden=1
|
|
|
|
export function __imagePicker(image: Image): Image {
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
2023-05-06 00:58:52 +02:00
|
|
|
/**
|
|
|
|
* Clear on the screen at a specific line.
|
|
|
|
* @param line the line number to clear at (starting at 1), eg: 1
|
|
|
|
*/
|
|
|
|
//% blockId=clearLine block="clear line $line"
|
|
|
|
//% weight=94 group="Screen" inlineInputMode="inline" blockGap=8
|
|
|
|
//% line.min=1 line.max=12
|
|
|
|
export function clearLine(line: number) {
|
|
|
|
if (screenMode != ScreenMode.ShowLines) {
|
|
|
|
screenMode = ScreenMode.ShowLines;
|
|
|
|
screen.fill(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
line = (line - 1) >> 0; // line indexing starts at 1
|
|
|
|
const nlines = lineCount();
|
|
|
|
if (line < 0 || line > nlines) return; // out of screen by line
|
|
|
|
|
|
|
|
const h = lineHeight();
|
|
|
|
const y = textOffset + h * line;
|
|
|
|
screen.fillRect(0, y, screen.width, h, 0); // clear background
|
|
|
|
}
|
|
|
|
|
2018-02-27 00:16:17 +01:00
|
|
|
/**
|
|
|
|
* Clear the screen
|
|
|
|
*/
|
|
|
|
//% blockId=screen_clear_screen block="clear screen"
|
2023-05-06 00:58:52 +02:00
|
|
|
//% weight=93 group="Screen"
|
2018-03-28 17:50:14 +02:00
|
|
|
//% help=brick/clear-screen weight=1
|
2018-02-27 00:16:17 +01:00
|
|
|
export function clearScreen() {
|
|
|
|
screen.fill(0)
|
|
|
|
}
|
|
|
|
}
|