From da3c11dcfc35c3fbe11ffecd224aa6377b66ea91 Mon Sep 17 00:00:00 2001 From: Rahix <rahix@rahix.de> Date: Sun, 28 Jul 2019 01:50:19 +0200 Subject: [PATCH] feat(bootloader): Add a boot-splash Signed-off-by: Rahix <rahix@rahix.de> --- bootloader/bootloader-display.c | 30 +++++++++++- bootloader/main.c | 19 +++++--- bootloader/meson.build | 14 ++++++ bootloader/splash-screen.png | Bin 0 -> 6332 bytes tools/bootloader-image.py | 83 ++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 7 deletions(-) create mode 100644 bootloader/splash-screen.png create mode 100755 tools/bootloader-image.py diff --git a/bootloader/bootloader-display.c b/bootloader/bootloader-display.c index 2c1e34fd..1fe0cae0 100644 --- a/bootloader/bootloader-display.c +++ b/bootloader/bootloader-display.c @@ -1,14 +1,42 @@ #include "bootloader.h" +/* Autogenerated */ +#include "splash-screen.h" #include "GUI_Paint.h" #include "display.h" +/* + * "Decompress" splash-screen image. The algorithm works as follows: + * + * Each byte encodes up to 127 pixels in either white or black. The most + * significant bit determines the color, the remaining 7 bits determine the + * amount. + */ +static void bootloader_display_splash(void) +{ + int idx = 0; + + for (int i = 0; i < sizeof(splash); i++) { + uint16_t color = (splash[i] & 0x80) ? 0xffff : 0x0000; + uint8_t length = splash[i] & 0x7f; + + for (int j = 0; j < length; j++) { + uint16_t x = idx % 160; + uint16_t y = idx / 160; + Paint_SetPixel(x, y, color); + idx++; + } + } + + LCD_Update(); +} + /* * Initialize the display. */ void bootloader_display_init(void) { - ; + bootloader_display_splash(); } /* diff --git a/bootloader/main.c b/bootloader/main.c index 1a5f08e0..d3577542 100644 --- a/bootloader/main.c +++ b/bootloader/main.c @@ -205,10 +205,11 @@ int main(void) */ pmic_set_button_callback(pmic_button); - bootloader_display_header(); + bootloader_display_init(); // If the button is pressed, we go into MSC mode. if (PB_Get(3)) { + bootloader_display_header(); bootloader_display_line(2, "USB activated.", 0xffff); bootloader_display_line(3, "Ready.", 0xffff); run_usbmsc(); @@ -224,36 +225,42 @@ int main(void) int res = check_integrity(); if (res == -ENOENT) { printf("card10.bin not found!\n"); - bootloader_display_line( - 2, "card10.bin not found", 0xffff - ); } else if (res == -EINVAL) { printf("card10.bin CRC is invalid!\n"); + bootloader_display_header(); bootloader_display_line( 2, "Integrity check failed", 0xffff ); + + bootloader_display_line(4, "Trying to boot", 0xffff); } else if (res == 0) { printf("Found valid application image\n"); if (is_update_needed()) { printf("Trying to update firmware from external flash\n"); + bootloader_display_header(); bootloader_display_line( - 4, "Updating ...", 0xffff + 3, "Updating ...", 0xffff ); erase_partition(); flash_partition(); + bootloader_display_line( + 4, "Trying to boot", 0xffff + ); } else { printf("No update needed\n"); } } } else { + bootloader_display_header(); bootloader_display_line( 2, "Failed to mount filesystem", 0xffff ); printf("Failed to mount the external flash\n"); + + bootloader_display_line(4, "Trying to boot", 0xffff); } printf("Trying to boot\n"); - bootloader_display_line(4, "Trying to boot", 0xffff); boot((uintptr_t *)PARTITION_START); diff --git a/bootloader/meson.build b/bootloader/meson.build index 9a863cdf..23c38794 100644 --- a/bootloader/meson.build +++ b/bootloader/meson.build @@ -1,5 +1,18 @@ name = 'bootloader' +splash_screen = custom_target( + 'splash-screen.h', + output: 'splash-screen.h', + input: 'splash-screen.png', + command: [ + python3, + meson.current_source_dir() + '../tools/bootloader-image.py', + '-n', 'splash', + '@INPUT@', + '@OUTPUT@', + ], +) + executable( name + '.elf', 'main.c', @@ -7,6 +20,7 @@ executable( 'bootloader-display.c', 'bootloader-usb.c', 'crc16-ccitt.c', + splash_screen, dependencies: [ libcard10, max32665_startup_boot, diff --git a/bootloader/splash-screen.png b/bootloader/splash-screen.png new file mode 100644 index 0000000000000000000000000000000000000000..02a632049624f5b96e54ac2d4c7d408fd41ae796 GIT binary patch literal 6332 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≀%!?W|LNo$|PHkR!$vMW9|K z$}3txcP7G@PEJ(=ws`lT<Q~0W0Vuuyl_K<fb)jdwww4VqJ=Kx=M%&0iII8=;y(t$V z3$?6ON3~~*G7F<FBdHVUZZStGJM07EzBM57vynYb0#5t19I+h)Bw@4oi*_`Y%CBcb zAK_a4piK0K9~m&{;M^@kmOgnC@CJhv{gaNG`20@DMT7N(2ay&NLk);au>^yFARs_M y5D*|B2nY}m1Ox~O0s;gC0RaMnfB*q;fBpe%Gf~Uvok$V@0000<MNUMnLSTY_wE_tM literal 0 HcmV?d00001 diff --git a/tools/bootloader-image.py b/tools/bootloader-image.py new file mode 100755 index 00000000..f2ce2bf8 --- /dev/null +++ b/tools/bootloader-image.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +import argparse +import os +from PIL import Image + + +def main() -> None: + parser = argparse.ArgumentParser( + description="""\ +\"Compress\" an image for the boot-splash. +The boot-splash is a two-color image.""" + ) + + parser.add_argument("image", help="Boot-splash image") + parser.add_argument("-n", "--name", help="Name of the data-block") + parser.add_argument("output", help="Output file name") + + args = parser.parse_args() + + im = Image.open(args.image) + + assert im.size[0] == 160, "Image must be 160 pixels wide" + assert im.size[1] == 80, "Image must be 80 pixels high)" + + if args.name is not None: + name = args.name + else: + name = os.path.splitext(os.path.basename(args.image))[0].replace("-", "_") + + with open(args.output, "w") as f: + tmp = """\ +#include <stdint.h> + +/* + * This is the splash-screen image, compressed using a very primitive algorithm: + * + * Each byte encodes up to 127 pixels in either white or black. The most + * significant bit determines the color, the remaining 7 bits determine the + * amount. + */ +const uint8_t {name}[] = {{ +""" + f.write(tmp.format(name=name)) + + total = 0 + start = 0 + previous_white = False + for i in range(160 * 80): + x = i % 160 + y = i // 160 + white = im.getpixel((x, y))[0] > 0 + + if white != previous_white or i - start == 127: + length = i - start + assert length < 128, "Internal error" + value = (length & 0x7F) | (0x80 if previous_white else 0x00) + + tmp = """\ + /* {length} pixels in {color} */ + 0x{value:x}, +""" + f.write( + tmp.format( + length=length, + color="white" if previous_white else "black", + value=value, + ) + ) + + previous_white = white + start = i + total += length + + tmp = """\ +}}; +""" + f.write(tmp.format()) + + assert total < (160 * 80), "Internal error" + + +if __name__ == "__main__": + main() -- GitLab