Merge branch 'newgfx'
This commit is contained in:
		
							
								
								
									
										2
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								TODO.md
									
									
									
									
									
								
							@@ -2,7 +2,7 @@
 | 
			
		||||
* [x] implement serialPoll
 | 
			
		||||
* [x] try some motors
 | 
			
		||||
* [x] add `control.interrupt(ms, () => { ... sync function ... })` - running outside regular JS thread
 | 
			
		||||
* [ ] add `//% whenUsed` on global variable initializers in PXT
 | 
			
		||||
* [x] add `//% whenUsed` on global variable initializers in PXT
 | 
			
		||||
* [ ] fix `@PXT@:` handling for ELF in PXT
 | 
			
		||||
* [x] parse Python field lists into offsets
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,16 @@
 | 
			
		||||
 * Patterns for lights under the buttons.
 | 
			
		||||
 */
 | 
			
		||||
const enum LightsPattern {
 | 
			
		||||
    Off = 0,  // LED_BLACK
 | 
			
		||||
    Green = 1,  // LED_GREEN
 | 
			
		||||
    Red = 2,  // LED_RED
 | 
			
		||||
    Orange = 3,  // LED_ORANGE
 | 
			
		||||
    GreenFlash = 4,  // LED_GREEN_FLASH
 | 
			
		||||
    RedFlash = 5,  // LED_RED_FLASH
 | 
			
		||||
    OrangeFlash = 6,  // LED_ORANGE_FLASH
 | 
			
		||||
    GreenPulse = 7,  // LED_GREEN_PULSE
 | 
			
		||||
    RedPulse = 8,  // LED_RED_PULSE
 | 
			
		||||
    OrangePulse = 9,  // LED_ORANGE_PULSE
 | 
			
		||||
    Off = 0,
 | 
			
		||||
    Green = 1,
 | 
			
		||||
    Red = 2,
 | 
			
		||||
    Orange = 3,
 | 
			
		||||
    GreenFlash = 4,
 | 
			
		||||
    RedFlash = 5,
 | 
			
		||||
    OrangeFlash = 6,
 | 
			
		||||
    GreenPulse = 7,
 | 
			
		||||
    RedPulse = 8,
 | 
			
		||||
    OrangePulse = 9,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								libs/core/enums.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								libs/core/enums.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -6,18 +6,12 @@
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    declare enum Draw {
 | 
			
		||||
    Normal = 0,
 | 
			
		||||
    Clear = (0x0004),  // DRAW_OPT_CLEAR_PIXELS
 | 
			
		||||
    Xor = (0x0018),  // DRAW_OPT_LOGICAL_XOR
 | 
			
		||||
    Fill = (0x0020),  // DRAW_OPT_FILL_SHAPE
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    declare enum ScreenFont {
 | 
			
		||||
    Normal = 0,  // FONTTYPE_NORMAL
 | 
			
		||||
    Small = 1,  // FONTTYPE_SMALL
 | 
			
		||||
    Large = 2,  // FONTTYPE_LARGE
 | 
			
		||||
    Tiny = 3,  // FONTTYPE_TINY
 | 
			
		||||
    Normal = 0x00,
 | 
			
		||||
    Clear = 0x01,
 | 
			
		||||
    Xor = 0x02,
 | 
			
		||||
    Fill = 0x04,
 | 
			
		||||
    Transparent = 0x08,
 | 
			
		||||
    Double = 0x10,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
// Auto-generated. Do not edit. Really.
 | 
			
		||||
 
 | 
			
		||||
@@ -6,18 +6,22 @@
 | 
			
		||||
* Drawing modes
 | 
			
		||||
*/
 | 
			
		||||
enum class Draw {
 | 
			
		||||
    Normal = 0, // set pixels to black, no fill
 | 
			
		||||
    Clear = DRAW_OPT_CLEAR_PIXELS,
 | 
			
		||||
    Xor = DRAW_OPT_LOGICAL_XOR,
 | 
			
		||||
    Fill = DRAW_OPT_FILL_SHAPE,
 | 
			
		||||
    Normal = 0x00, // set pixels to black, no fill
 | 
			
		||||
    Clear = 0x01,
 | 
			
		||||
    Xor = 0x02,
 | 
			
		||||
    Fill = 0x04,
 | 
			
		||||
    Transparent = 0x08,
 | 
			
		||||
    Double = 0x10,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class ScreenFont {
 | 
			
		||||
    Normal = FONTTYPE_NORMAL,
 | 
			
		||||
    Small = FONTTYPE_SMALL,
 | 
			
		||||
    Large = FONTTYPE_LARGE,
 | 
			
		||||
    Tiny = FONTTYPE_TINY,
 | 
			
		||||
};
 | 
			
		||||
inline bool operator&(Draw a, Draw b) {
 | 
			
		||||
    return ((int)a & (int)b) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline Draw operator|(Draw a, Draw b) {
 | 
			
		||||
    return (Draw)((int)a | (int)b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define XX(v) ((uint32_t)(v)&0xffff)
 | 
			
		||||
#define YY(v) ((uint32_t)(v) >> 16)
 | 
			
		||||
@@ -25,63 +29,232 @@ enum class ScreenFont {
 | 
			
		||||
// We only support up to 4 arguments for C++ functions - need to pack them on the TS side
 | 
			
		||||
namespace screen {
 | 
			
		||||
 | 
			
		||||
#define ROW_SIZE 32
 | 
			
		||||
#define FB_SIZE (60 * LCD_HEIGHT)
 | 
			
		||||
 | 
			
		||||
//%
 | 
			
		||||
void _drawLine(uint32_t p0, uint32_t p1, Draw mode) {
 | 
			
		||||
    LineOutEx(XX(p0), YY(p0), XX(p1), YY(p1), (uint32_t)mode);
 | 
			
		||||
static const uint8_t pixmap[] = {0x00, 0xE0, 0x1C, 0xFC, 0x03, 0xE3, 0x1F, 0xFF};
 | 
			
		||||
static uint8_t bitBuffer[ROW_SIZE * LCD_HEIGHT];
 | 
			
		||||
static bool dirty;
 | 
			
		||||
 | 
			
		||||
static void bitBufferToFrameBuffer(uint8_t *bitBuffer, uint8_t *fb) {
 | 
			
		||||
    uint32_t pixels;
 | 
			
		||||
 | 
			
		||||
    for (int line = 0; line < LCD_HEIGHT; line++) {
 | 
			
		||||
        int n = 7;
 | 
			
		||||
        while (n--) {
 | 
			
		||||
            pixels = *bitBuffer++ << 0;
 | 
			
		||||
            pixels |= *bitBuffer++ << 8;
 | 
			
		||||
            pixels |= *bitBuffer++ << 16;
 | 
			
		||||
 | 
			
		||||
            int m = 8;
 | 
			
		||||
            while (m--) {
 | 
			
		||||
                *fb++ = pixmap[pixels & 0x07];
 | 
			
		||||
                pixels >>= 3;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pixels = *bitBuffer++ << 0;
 | 
			
		||||
        pixels |= *bitBuffer++ << 8;
 | 
			
		||||
 | 
			
		||||
        bitBuffer += ROW_SIZE - 23;
 | 
			
		||||
 | 
			
		||||
        int m = 4;
 | 
			
		||||
        while (m--) {
 | 
			
		||||
            *fb++ = pixmap[pixels & 0x07];
 | 
			
		||||
            pixels >>= 3;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define OFF(x, y) (((y) << 5) + ((x) >> 3))
 | 
			
		||||
#define MASK(x, y) (1 << ((x)&7))
 | 
			
		||||
#define PIX2BYTES(x) (((x) + 7) >> 3)
 | 
			
		||||
 | 
			
		||||
static inline void applyMask(int off, int mask, Draw mode) {
 | 
			
		||||
    if (mode & Draw::Clear)
 | 
			
		||||
        bitBuffer[off] &= ~mask;
 | 
			
		||||
    else if (mode & Draw::Xor)
 | 
			
		||||
        bitBuffer[off] ^= mask;
 | 
			
		||||
    else
 | 
			
		||||
        bitBuffer[off] |= mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//%
 | 
			
		||||
void _drawRect(uint32_t p0, uint32_t p1, Draw mode) {
 | 
			
		||||
    RectOutEx(XX(p0), YY(p0), XX(p1), YY(p1), (uint32_t)mode);
 | 
			
		||||
void _setPixel(int x, int y, Draw mode) {
 | 
			
		||||
    applyMask(OFF(x, y), MASK(x, y), mode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void blitLineCore(int x, int y, int w, uint8_t *data, Draw mode) {
 | 
			
		||||
    if (y < 0 || y >= LCD_HEIGHT)
 | 
			
		||||
        return;
 | 
			
		||||
    if (x + w <= 0)
 | 
			
		||||
        return;
 | 
			
		||||
    if (x >= LCD_WIDTH)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    int shift = x & 7;
 | 
			
		||||
    int off = OFF(x, y);
 | 
			
		||||
    int off0 = OFF(0, y);
 | 
			
		||||
    int off1 = OFF(LCD_WIDTH - 1, y);
 | 
			
		||||
    int x1 = x + w + shift;
 | 
			
		||||
    int prev = 0;
 | 
			
		||||
 | 
			
		||||
    while (x < x1 - 8) {
 | 
			
		||||
        int curr = *data++ << shift;
 | 
			
		||||
        if (off0 <= off && off <= off1)
 | 
			
		||||
            applyMask(off, curr | prev, mode);
 | 
			
		||||
        off++;
 | 
			
		||||
        prev = curr >> 8;
 | 
			
		||||
        x += 8;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int left = x1 - x;
 | 
			
		||||
    if (left > 0) {
 | 
			
		||||
        int curr = *data << shift;
 | 
			
		||||
        if (off0 <= off && off <= off1)
 | 
			
		||||
            applyMask(off, (curr | prev) & ((1 << left) - 1), mode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//%
 | 
			
		||||
void _drawEllipse(uint32_t p0, uint32_t p1, Draw mode) {
 | 
			
		||||
    EllipseOutEx(XX(p0), YY(p0), XX(p1), YY(p1), (uint32_t)mode);
 | 
			
		||||
void _blitLine(int xw, int y, Buffer buf, Draw mode) {
 | 
			
		||||
    blitLineCore(XX(xw), y, YY(xw), buf->data, mode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Draw text. */
 | 
			
		||||
//% mode.defl=0
 | 
			
		||||
void drawText(int x, int y, String text, Draw mode) {
 | 
			
		||||
    LcdText((int)mode & (int)Draw::Clear ? 0 : 1, x, y, text->data);
 | 
			
		||||
static uint8_t ones[] = {
 | 
			
		||||
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 | 
			
		||||
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
bool isValidIcon(Buffer buf) {
 | 
			
		||||
    return buf->length >= 3 && buf->data[0] == 0xf0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const uint8_t bitdouble[] = {
 | 
			
		||||
    0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f, 0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Double size of an icon. */
 | 
			
		||||
//%
 | 
			
		||||
Buffer doubleIcon(Buffer buf) {
 | 
			
		||||
    if (!isValidIcon(buf))
 | 
			
		||||
        return NULL;
 | 
			
		||||
    int w = buf->data[1];
 | 
			
		||||
    if (w > 126)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    int bw = PIX2BYTES(w);
 | 
			
		||||
    int h = (buf->length - 2) / bw;
 | 
			
		||||
    int bw2 = PIX2BYTES(w * 2);
 | 
			
		||||
    Buffer out = mkBuffer(NULL, 2 + bw2 * h * 2);
 | 
			
		||||
    out->data[0] = 0xf0;
 | 
			
		||||
    out->data[1] = w * 2;
 | 
			
		||||
    uint8_t *src = buf->data + 2;
 | 
			
		||||
    uint8_t *dst = out->data + 2;
 | 
			
		||||
    for (int i = 0; i < h; ++i) {
 | 
			
		||||
        for (int jj = 0; jj < 2; ++jj) {
 | 
			
		||||
            auto p = src;
 | 
			
		||||
            for (int j = 0; j < bw; ++j) {
 | 
			
		||||
                *dst++ = bitdouble[*p & 0xf];
 | 
			
		||||
                *dst++ = bitdouble[*p >> 4];
 | 
			
		||||
                p++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        src += bw;
 | 
			
		||||
    }
 | 
			
		||||
    return out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Draw an icon on the screen. */
 | 
			
		||||
//%
 | 
			
		||||
void drawIcon(int x, int y, Buffer buf, Draw mode) {
 | 
			
		||||
    if (!isValidIcon(buf))
 | 
			
		||||
        return;
 | 
			
		||||
    if (mode & Draw::Double)
 | 
			
		||||
        buf = doubleIcon(buf);
 | 
			
		||||
 | 
			
		||||
    int pixwidth = buf->data[1];
 | 
			
		||||
    int ptr = 2;
 | 
			
		||||
    int bytewidth = PIX2BYTES(pixwidth);
 | 
			
		||||
    pixwidth = min(pixwidth, LCD_WIDTH);
 | 
			
		||||
    while (ptr + bytewidth <= buf->length) {
 | 
			
		||||
        if (mode & (Draw::Clear | Draw::Xor | Draw::Transparent)) {
 | 
			
		||||
            // no erase of background
 | 
			
		||||
        } else {
 | 
			
		||||
            blitLineCore(x, y, pixwidth, ones, Draw::Clear);
 | 
			
		||||
        }
 | 
			
		||||
        blitLineCore(x, y, pixwidth, &buf->data[ptr], mode);
 | 
			
		||||
        y++;
 | 
			
		||||
        ptr += bytewidth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (mode & Draw::Double)
 | 
			
		||||
        decrRC(buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Clear screen and reset font to normal. */
 | 
			
		||||
//%
 | 
			
		||||
void clear() {
 | 
			
		||||
    LcdClearDisplay();
 | 
			
		||||
    memset(bitBuffer, 0, sizeof(bitBuffer));
 | 
			
		||||
    dirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Scroll screen vertically. */
 | 
			
		||||
//%
 | 
			
		||||
void scroll(int v) {
 | 
			
		||||
    LcdScroll(v);
 | 
			
		||||
void dump() {
 | 
			
		||||
    char buf[LCD_WIDTH + 1];
 | 
			
		||||
    FILE *f = fopen("/tmp/screen.txt", "w");
 | 
			
		||||
    for (int i = 0; i < LCD_HEIGHT; ++i) {
 | 
			
		||||
        for (int j = 0; j < LCD_WIDTH; ++j) {
 | 
			
		||||
            if (bitBuffer[OFF(j, i)] & MASK(j, i))
 | 
			
		||||
                buf[j] = '#';
 | 
			
		||||
            else
 | 
			
		||||
                buf[j] = '.';
 | 
			
		||||
        }
 | 
			
		||||
        buf[LCD_WIDTH] = 0;
 | 
			
		||||
        fprintf(f, "%s\n", buf);
 | 
			
		||||
    }
 | 
			
		||||
    fclose(f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Set font for drawText() */
 | 
			
		||||
static uint8_t *mappedFrameBuffer;
 | 
			
		||||
 | 
			
		||||
//%
 | 
			
		||||
void setFont(ScreenFont font) {
 | 
			
		||||
    LcdSelectFont((uint8_t)font);
 | 
			
		||||
void updateLCD() {
 | 
			
		||||
    if (dirty && mappedFrameBuffer != MAP_FAILED) {
 | 
			
		||||
        dirty = false;
 | 
			
		||||
        bitBufferToFrameBuffer(bitBuffer, mappedFrameBuffer);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace pxt {
 | 
			
		||||
 | 
			
		||||
void *screenRefresh(void *dummy) {
 | 
			
		||||
    while (true) {
 | 
			
		||||
        sleep_core_us(30000);
 | 
			
		||||
        LcdUpdate();
 | 
			
		||||
        updateLCD();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void screen_init() {
 | 
			
		||||
    LcdInitNoAutoRefresh();
 | 
			
		||||
    LcdClean();
 | 
			
		||||
void init() {
 | 
			
		||||
    DMESG("init screen");
 | 
			
		||||
    if (mappedFrameBuffer)
 | 
			
		||||
        return;
 | 
			
		||||
    int fd = open("/dev/fb0", O_RDWR);
 | 
			
		||||
    DMESG("init screen %d", fd);
 | 
			
		||||
    mappedFrameBuffer = (uint8_t *)mmap(NULL, FB_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
 | 
			
		||||
    DMESG("map %p", mappedFrameBuffer);
 | 
			
		||||
    if (mappedFrameBuffer == MAP_FAILED) {
 | 
			
		||||
        target_panic(111);
 | 
			
		||||
    }
 | 
			
		||||
    clear();
 | 
			
		||||
 | 
			
		||||
    pthread_t pid;
 | 
			
		||||
    pthread_create(&pid, NULL, screenRefresh, NULL);
 | 
			
		||||
    pthread_detach(pid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace pxt {
 | 
			
		||||
void screen_init() {
 | 
			
		||||
    screen::init();
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,30 +1,157 @@
 | 
			
		||||
namespace screen {
 | 
			
		||||
    //% shim=screen::_drawLine
 | 
			
		||||
    function _drawLine(p0: uint32, p1: uint32, mode: Draw): void { }
 | 
			
		||||
    //% shim=screen::_setPixel
 | 
			
		||||
    function _setPixel(p0: uint32, p1: uint32, mode: Draw): void { }
 | 
			
		||||
 | 
			
		||||
    //% shim=screen::_drawRect
 | 
			
		||||
    function _drawRect(p0: uint32, p1: uint32, mode: Draw): void { }
 | 
			
		||||
 | 
			
		||||
    //% shim=screen::_drawEllipse
 | 
			
		||||
    function _drawEllipse(p0: uint32, p1: uint32, mode: Draw): void { }
 | 
			
		||||
    //% shim=screen::_blitLine
 | 
			
		||||
    function _blitLine(xw: uint32, y: uint32, buf: Buffer, mode: Draw): void { }
 | 
			
		||||
 | 
			
		||||
    function pack(x: number, y: number) {
 | 
			
		||||
        return Math.clamp(0, 512, x) | (Math.clamp(0, 512, y) << 16)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export function drawLine(x0: number, y0: number, x1: number, y1: number, mode?: Draw) {
 | 
			
		||||
        _drawLine(pack(x0, y0), pack(x1, y1), mode)
 | 
			
		||||
    const ones = hex`ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
 | 
			
		||||
 | 
			
		||||
    function setLineCore(x: number, x1: number, y: number, mode: Draw) {
 | 
			
		||||
        _blitLine(pack(x, x1 - x), y, ones, mode)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export function drawRect(x: number, y: number, w: number, h: number, mode?: Draw) {
 | 
			
		||||
        _drawRect(pack(x, y), pack(w, h), mode)
 | 
			
		||||
    export interface Font {
 | 
			
		||||
        charWidth: number;
 | 
			
		||||
        charHeight: number;
 | 
			
		||||
        firstChar: number;
 | 
			
		||||
        data: Buffer;
 | 
			
		||||
    }
 | 
			
		||||
    let currFont: Font
 | 
			
		||||
 | 
			
		||||
    export function setFont(f: Font) {
 | 
			
		||||
        currFont = f
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export function drawEllipse(x: number, y: number, rx: number, ry: number, mode?: Draw) {
 | 
			
		||||
        _drawEllipse(pack(x, y), pack(rx, ry), mode)
 | 
			
		||||
    export const heart = hex`f007 367f7f3e1c08`
 | 
			
		||||
 | 
			
		||||
    export function defaultFont(): Font {
 | 
			
		||||
        return {
 | 
			
		||||
            charWidth: 8,
 | 
			
		||||
            charHeight: 8,
 | 
			
		||||
            firstChar: 32,
 | 
			
		||||
            // source https://github.com/dhepper/font8x8
 | 
			
		||||
            data: hex`
 | 
			
		||||
0000000000000000 183C3C1818001800 3636000000000000 36367F367F363600 0C3E031E301F0C00 006333180C666300
 | 
			
		||||
1C361C6E3B336E00 0606030000000000 180C0606060C1800 060C1818180C0600 00663CFF3C660000 000C0C3F0C0C0000
 | 
			
		||||
00000000000C0C06 0000003F00000000 00000000000C0C00 6030180C06030100 3E63737B6F673E00 0C0E0C0C0C0C3F00
 | 
			
		||||
1E33301C06333F00 1E33301C30331E00 383C36337F307800 3F031F3030331E00 1C06031F33331E00 3F3330180C0C0C00
 | 
			
		||||
1E33331E33331E00 1E33333E30180E00 000C0C00000C0C00 000C0C00000C0C06 180C0603060C1800 00003F00003F0000
 | 
			
		||||
060C1830180C0600 1E3330180C000C00 3E637B7B7B031E00 0C1E33333F333300 3F66663E66663F00 3C66030303663C00
 | 
			
		||||
1F36666666361F00 7F46161E16467F00 7F46161E16060F00 3C66030373667C00 3333333F33333300 1E0C0C0C0C0C1E00
 | 
			
		||||
7830303033331E00 6766361E36666700 0F06060646667F00 63777F7F6B636300 63676F7B73636300 1C36636363361C00
 | 
			
		||||
3F66663E06060F00 1E3333333B1E3800 3F66663E36666700 1E33070E38331E00 3F2D0C0C0C0C1E00 3333333333333F00
 | 
			
		||||
33333333331E0C00 6363636B7F776300 6363361C1C366300 3333331E0C0C1E00 7F6331184C667F00 1E06060606061E00
 | 
			
		||||
03060C1830604000 1E18181818181E00 081C366300000000 00000000000000FF 0C0C180000000000 00001E303E336E00
 | 
			
		||||
0706063E66663B00 00001E3303331E00 3830303e33336E00 00001E333f031E00 1C36060f06060F00 00006E33333E301F
 | 
			
		||||
0706366E66666700 0C000E0C0C0C1E00 300030303033331E 070666361E366700 0E0C0C0C0C0C1E00 0000337F7F6B6300
 | 
			
		||||
00001F3333333300 00001E3333331E00 00003B66663E060F 00006E33333E3078 00003B6E66060F00 00003E031E301F00
 | 
			
		||||
080C3E0C0C2C1800 0000333333336E00 00003333331E0C00 0000636B7F7F3600 000063361C366300 00003333333E301F
 | 
			
		||||
00003F190C263F00 380C0C070C0C3800 1818180018181800 070C0C380C0C0700 6E3B000000000000 0000000000000000
 | 
			
		||||
`
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export function drawCircle(x: number, y: number, r: number, mode?: Draw) {
 | 
			
		||||
        drawEllipse(x, y, r, r, mode)
 | 
			
		||||
    export function microbitFont() {
 | 
			
		||||
        return {
 | 
			
		||||
            charWidth: 6,
 | 
			
		||||
            charHeight: 5,
 | 
			
		||||
            firstChar: 32,
 | 
			
		||||
            // source https://github.com/lancaster-university/microbit-dal/blob/master/source/core/MicroBitFont.cpp
 | 
			
		||||
            data: hex`
 | 
			
		||||
0000000000 0202020002 0a0a000000 0a1f0a1f0a 0e130e190e 1309041219 0609060916 0202000000 0402020204 
 | 
			
		||||
0204040402 000a040a00 00040e0400 0000000402 00000e0000 0000000200 1008040201 0609090906 040604040e 
 | 
			
		||||
070806010f 0f08040906 0c0a091f08 1f010f100f 08040e110e 1f08040201 0e110e110e 0e110e0402 0002000200 
 | 
			
		||||
0004000402 0804020408 000e000e00 0204080402 0e110c0004 0e11151906 06090f0909 0709070907 0e0101010e 
 | 
			
		||||
0709090907 0f0107010f 0f01070101 0e0119110e 09090f0909 0702020207 1f08080906 0905030509 010101010f 
 | 
			
		||||
111b151111 1113151911 0609090906 0709070101 060909060c 0709070911 0e01060807 1f04040404 0909090906 
 | 
			
		||||
1111110a04 1111151b11 0909060909 110a040404 0f0402010f 0e0202020e 0102040810 0e0808080e 040a000000 
 | 
			
		||||
000000001f 0204000000 000e09091e 0101070907 000e01010e 08080e090e 060907010e 0c02070202 0e090e0806 
 | 
			
		||||
0101070909 0200020202 0800080806 0105030509 020202020c 001b151111 0007090909 0006090906 0007090701 
 | 
			
		||||
000e090e08 000e010101 000c020403 02020e021c 000909091e 0011110a04 001111151b 0009060609 00110a0403 
 | 
			
		||||
000f04020f 0c0406040c 0202020202 0302060203 0000061800
 | 
			
		||||
`
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export function setPixel(x: number, y: number, mode = Draw.Normal) {
 | 
			
		||||
        x |= 0
 | 
			
		||||
        y |= 0
 | 
			
		||||
        if (0 <= x && x < LMS.LCD_WIDTH && 0 <= y && y < LMS.LCD_HEIGHT)
 | 
			
		||||
            _setPixel(x, y, mode)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export function drawText(x: number, y: number, text: string, mode = Draw.Normal) {
 | 
			
		||||
        x |= 0
 | 
			
		||||
        y |= 0
 | 
			
		||||
        if (!currFont) currFont = defaultFont()
 | 
			
		||||
        let x0 = x
 | 
			
		||||
        let cp = 0
 | 
			
		||||
        let byteWidth = (currFont.charWidth + 7) >> 3
 | 
			
		||||
        let charSize = byteWidth * currFont.charHeight
 | 
			
		||||
        let iconBuf = output.createBuffer(2 + charSize)
 | 
			
		||||
        let double = (mode & Draw.Double) ? 2 : 1
 | 
			
		||||
        iconBuf[0] = 0xf0
 | 
			
		||||
        iconBuf[1] = currFont.charWidth
 | 
			
		||||
        while (cp < text.length) {
 | 
			
		||||
            let ch = text.charCodeAt(cp++)
 | 
			
		||||
            if (ch == 10) {
 | 
			
		||||
                y += double * currFont.charHeight + 2
 | 
			
		||||
                x = x0
 | 
			
		||||
            }
 | 
			
		||||
            if (ch < 32) continue
 | 
			
		||||
            let idx = (ch - currFont.firstChar) * charSize
 | 
			
		||||
            if (idx < 0 || idx + iconBuf.length - 1 > currFont.data.length)
 | 
			
		||||
                iconBuf.fill(0, 2)
 | 
			
		||||
            else
 | 
			
		||||
                iconBuf.write(2, currFont.data.slice(idx, charSize))
 | 
			
		||||
            drawIcon(x, y, iconBuf, mode)
 | 
			
		||||
            x += double * currFont.charWidth
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export function drawRect(x: number, y: number, w: number, h: number, mode = Draw.Normal) {
 | 
			
		||||
        x |= 0;
 | 
			
		||||
        y |= 0;
 | 
			
		||||
        w |= 0;
 | 
			
		||||
        h |= 0;
 | 
			
		||||
        if (x < 0) {
 | 
			
		||||
            w += x;
 | 
			
		||||
            x = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (y < 0) {
 | 
			
		||||
            h += y;
 | 
			
		||||
            y = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (w <= 0)
 | 
			
		||||
            return;
 | 
			
		||||
        if (h <= 0)
 | 
			
		||||
            return;
 | 
			
		||||
        let x1 = Math.min(LMS.LCD_WIDTH, x + w);
 | 
			
		||||
        let y1 = Math.min(LMS.LCD_HEIGHT, y + h);
 | 
			
		||||
        if (w == 1) {
 | 
			
		||||
            while (y < y1)
 | 
			
		||||
                _setPixel(x, y++, mode);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        setLineCore(x, x1, y++, mode);
 | 
			
		||||
        while (y < y1 - 1) {
 | 
			
		||||
            if (mode & Draw.Fill) {
 | 
			
		||||
                setLineCore(x, x1, y, mode);
 | 
			
		||||
            } else {
 | 
			
		||||
                _setPixel(x, y, mode);
 | 
			
		||||
                _setPixel(x1 - 1, y, mode);
 | 
			
		||||
            }
 | 
			
		||||
            y++;
 | 
			
		||||
        }
 | 
			
		||||
        if (y < y1)
 | 
			
		||||
            setLineCore(x, x1, y, mode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								libs/core/shims.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								libs/core/shims.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -72,21 +72,17 @@ declare namespace serial {
 | 
			
		||||
}
 | 
			
		||||
declare namespace screen {
 | 
			
		||||
 | 
			
		||||
    /** Draw text. */
 | 
			
		||||
    //% mode.defl=0 shim=screen::drawText
 | 
			
		||||
    function drawText(x: int32, y: int32, text: string, mode?: Draw): void;
 | 
			
		||||
    /** Double size of an icon. */
 | 
			
		||||
    //% shim=screen::doubleIcon
 | 
			
		||||
    function doubleIcon(buf: Buffer): Buffer;
 | 
			
		||||
 | 
			
		||||
    /** Draw an icon on the screen. */
 | 
			
		||||
    //% shim=screen::drawIcon
 | 
			
		||||
    function drawIcon(x: int32, y: int32, buf: Buffer, mode: Draw): void;
 | 
			
		||||
 | 
			
		||||
    /** Clear screen and reset font to normal. */
 | 
			
		||||
    //% shim=screen::clear
 | 
			
		||||
    function clear(): void;
 | 
			
		||||
 | 
			
		||||
    /** Scroll screen vertically. */
 | 
			
		||||
    //% shim=screen::scroll
 | 
			
		||||
    function scroll(v: int32): void;
 | 
			
		||||
 | 
			
		||||
    /** Set font for drawText() */
 | 
			
		||||
    //% shim=screen::setFont
 | 
			
		||||
    function setFont(font: ScreenFont): void;
 | 
			
		||||
}
 | 
			
		||||
declare namespace output {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,29 +1,31 @@
 | 
			
		||||
screen.clear()
 | 
			
		||||
screen.setFont(ScreenFont.Large)
 | 
			
		||||
screen.drawText(10, 30, "Welcome PXT!")
 | 
			
		||||
screen.drawText(10, 30, "Welcome PXT!", Draw.Double)
 | 
			
		||||
 | 
			
		||||
screen.drawEllipse(40, 40, 20, 10, Draw.Fill)
 | 
			
		||||
screen.drawRect(40, 40, 20, 10, Draw.Fill)
 | 
			
		||||
output.setLights(LightsPattern.Orange)
 | 
			
		||||
 | 
			
		||||
screen.drawIcon(100, 50, screen.doubleIcon(screen.heart), Draw.Double|Draw.Transparent)
 | 
			
		||||
 | 
			
		||||
input.buttonEnter.onEvent(ButtonEvent.Click, () => {
 | 
			
		||||
    screen.clear()
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
input.buttonLeft.onEvent(ButtonEvent.Click, () => {
 | 
			
		||||
    screen.drawRect(10, 70, 20, 10, Draw.Fill)
 | 
			
		||||
    output.setLights(LightsPattern.Red)
 | 
			
		||||
    screen.setFont(screen.microbitFont())
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
input.buttonRight.onEvent(ButtonEvent.Click, () => {
 | 
			
		||||
    screen.setFont(ScreenFont.Normal)
 | 
			
		||||
    screen.drawText(10, 60, "Bang!")
 | 
			
		||||
    screen.drawText(10, 60, "Right!")
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
input.buttonDown.onEvent(ButtonEvent.Click, () => {
 | 
			
		||||
    screen.scroll(-10)
 | 
			
		||||
    screen.drawText(10, 60, "Down! ")
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
input.buttonUp.onEvent(ButtonEvent.Click, () => {
 | 
			
		||||
    screen.scroll(10)
 | 
			
		||||
    screen.drawText(10, 60, "Up!  ")
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user