From d25324d6c7f00d877086288e39e4d8eec1305a6d Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 10 Nov 2022 12:27:12 +0000 Subject: [PATCH 01/46] MicroPython: Add Badger2040W firmware build. --- .github/workflows/micropython-badger2040w.yml | 172 ++++++++++++++++++ .../PIMORONI_BADGER2040W/board.json | 17 ++ .../PIMORONI_BADGER2040W/mpconfigboard.cmake | 8 + .../PIMORONI_BADGER2040W/mpconfigboard.h | 23 +++ micropython/_board/badger2040w/fixup.sh | 6 + .../_board/badger2040w/pimoroni_badger2040w.h | 137 ++++++++++++++ .../_board/badger2040w/wakeup_gpio.patch | 143 +++++++++++++++ .../modules/micropython-badger2040w.cmake | 39 ++++ 8 files changed, 545 insertions(+) create mode 100644 .github/workflows/micropython-badger2040w.yml create mode 100644 micropython/_board/badger2040w/PIMORONI_BADGER2040W/board.json create mode 100644 micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.cmake create mode 100644 micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.h create mode 100644 micropython/_board/badger2040w/fixup.sh create mode 100644 micropython/_board/badger2040w/pimoroni_badger2040w.h create mode 100644 micropython/_board/badger2040w/wakeup_gpio.patch create mode 100644 micropython/modules/micropython-badger2040w.cmake diff --git a/.github/workflows/micropython-badger2040w.yml b/.github/workflows/micropython-badger2040w.yml new file mode 100644 index 00000000..8c0c6f94 --- /dev/null +++ b/.github/workflows/micropython-badger2040w.yml @@ -0,0 +1,172 @@ +name: MicroPython for Badger2040W + +on: + push: + pull_request: + release: + types: [created] + +env: + MICROPYTHON_VERSION: eefd946e60aba3ac61c7bfbd0272d07be289e3f3 + BOARD_TYPE: PIMORONI_BADGER2040W + # MicroPython version will be contained in github.event.release.tag_name for releases + RELEASE_FILE: pimoroni-badger2040w-${{github.event.release.tag_name || github.sha}}-micropython + +jobs: + deps: + runs-on: ubuntu-20.04 + name: Dependencies + steps: + - name: Workspace Cache + id: cache + uses: actions/cache@v2 + with: + path: ${{runner.workspace}} + key: workspace-micropython-${{env.MICROPYTHON_VERSION}} + restore-keys: | + workspace-micropython-${{env.MICROPYTHON_VERSION}} + + # Check out MicroPython + - name: Checkout MicroPython + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/checkout@v2 + with: + repository: micropython/micropython + ref: ${{env.MICROPYTHON_VERSION}} + submodules: false # MicroPython submodules are hideously broken + path: micropython + + - name: Fetch base MicroPython submodules + if: steps.cache.outputs.cache-hit != 'true' + shell: bash + working-directory: micropython + run: git submodule update --init + + - name: Fetch Pico SDK submodules + if: steps.cache.outputs.cache-hit != 'true' + shell: bash + working-directory: micropython/lib/pico-sdk + run: git submodule update --init + + - name: Build mpy-cross + if: steps.cache.outputs.cache-hit != 'true' + shell: bash + working-directory: micropython/mpy-cross + run: make + + build: + needs: deps + name: Build Badger 2040W + runs-on: ubuntu-20.04 + + steps: + - name: Compiler Cache + uses: actions/cache@v2 + with: + path: /home/runner/.ccache + key: ccache-micropython-badger2040w-${{github.ref}}-${{github.sha}} + restore-keys: | + ccache-micropython-badger2040w-${{github.ref}} + ccache-micropython-badger2040w- + + - name: Workspace Cache + uses: actions/cache@v2 + with: + path: ${{runner.workspace}} + key: workspace-micropython-${{env.MICROPYTHON_VERSION}} + restore-keys: | + workspace-micropython-${{env.MICROPYTHON_VERSION}} + + - uses: actions/checkout@v2 + with: + submodules: true + path: pimoroni-pico-${{ github.sha }} + + - name: "HACK: MicroPython Board Fixups" + shell: bash + working-directory: micropython/ports/rp2 + run: | + ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board/board-fixup.sh badger2040w ${{env.BOARD_TYPE}} ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board + + # Linux deps + - name: Install Compiler & CCache + if: runner.os == 'Linux' + run: | + sudo apt update && sudo apt install ccache gcc-arm-none-eabi + python3 -m pip install pillow + + # Build without BadgerOS + - name: Configure MicroPython (No BadgerOS) + shell: bash + working-directory: micropython/ports/rp2 + run: | + cmake -S . -B build-${{env.BOARD_TYPE}}-without-badger-os -DBADGER2040_NO_MODULES=1 -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/micropython-badger2040w.cmake -DMICROPY_BOARD=${{env.BOARD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + + - name: Build MicroPython (No BadgerOS) + shell: bash + working-directory: micropython/ports/rp2 + run: | + ccache --zero-stats || true + cmake --build build-${{env.BOARD_TYPE}}-without-badger-os -j 2 + ccache --show-stats || true + + - name: Rename .uf2 for artifact (No BadgerOS) + shell: bash + working-directory: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os + run: | + cp firmware.uf2 ${{env.RELEASE_FILE}}-without-badger-os.uf2 + + - name: Store .uf2 as artifact (No BadgerOS) + uses: actions/upload-artifact@v2 + with: + name: ${{env.RELEASE_FILE}}-without-badger-os.uf2 + path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os/${{env.RELEASE_FILE}}-without-badger-os.uf2 + + - name: Upload .uf2 (No BadgerOS) + if: github.event_name == 'release' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + with: + asset_path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os/${{env.RELEASE_FILE}}-without-badger-os.uf2 + upload_url: ${{github.event.release.upload_url}} + asset_name: ${{env.RELEASE_FILE}}-without-badger-os.uf2 + asset_content_type: application/octet-stream + + # Build with BadgerOS + - name: Configure MicroPython + shell: bash + working-directory: micropython/ports/rp2 + run: | + cmake -S . -B build-${{env.BOARD_TYPE}} -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/micropython-badger2040w.cmake -DMICROPY_BOARD=${{env.BOARD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + + - name: Build MicroPython + shell: bash + working-directory: micropython/ports/rp2 + run: | + ccache --zero-stats || true + cmake --build build-${{env.BOARD_TYPE}} -j 2 + ccache --show-stats || true + + - name: Rename .uf2 for artifact + shell: bash + working-directory: micropython/ports/rp2/build-${{env.BOARD_TYPE}} + run: | + cp firmware.uf2 ${{env.RELEASE_FILE}}.uf2 + + - name: Store .uf2 as artifact + uses: actions/upload-artifact@v2 + with: + name: ${{env.RELEASE_FILE}}.uf2 + path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 + + - name: Upload .uf2 + if: github.event_name == 'release' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + with: + asset_path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 + upload_url: ${{github.event.release.upload_url}} + asset_name: ${{env.RELEASE_FILE}}.uf2 + asset_content_type: application/octet-stream diff --git a/micropython/_board/badger2040w/PIMORONI_BADGER2040W/board.json b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/board.json new file mode 100644 index 00000000..d5d4332e --- /dev/null +++ b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/board.json @@ -0,0 +1,17 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "296*128 e-Ink", + "Buttons" + ], + "images": [ + ], + "mcu": "rp2040", + "product": "Badger2040 W (2MiB)", + "thumbnail": "", + "url": "https://shop.pimoroni.com/products/badger-2040w", + "vendor": "Pimoroni" +} diff --git a/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.cmake b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.cmake new file mode 100644 index 00000000..c16e3204 --- /dev/null +++ b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.cmake @@ -0,0 +1,8 @@ +# cmake file for Pimoroni Badger 2040W +set(MICROPY_BOARD PICO_W) + +set(MICROPY_PY_LWIP ON) +set(MICROPY_PY_NETWORK_CYW43 ON) + +# Board specific version of the frozen manifest +set(MICROPY_FROZEN_MANIFEST ${CMAKE_SOURCE_DIR}/boards/PICO_W/manifest.py) \ No newline at end of file diff --git a/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.h b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.h new file mode 100644 index 00000000..888d1cad --- /dev/null +++ b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.h @@ -0,0 +1,23 @@ +// This is a hack! Need to replace with upstream board definition. +#define MICROPY_HW_BOARD_NAME "Pimoroni Badger2040W 2MB" +#define MICROPY_HW_FLASH_STORAGE_BYTES (848 * 1024) + +// Enable networking. +#define MICROPY_PY_NETWORK 1 + +// CYW43 driver configuration. +#define CYW43_USE_SPI (1) +#define CYW43_LWIP (1) +#define CYW43_GPIO (1) +#define CYW43_SPI_PIO (1) + +// For debugging mbedtls - also set +// Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose +// #define MODUSSL_MBEDTLS_DEBUG_LEVEL 1 + +#define MICROPY_HW_PIN_CYW43_COUNT CYW43_WL_GPIO_COUNT +#ifdef CYW43_WL_GPIO_LED_PIN +#define MICROPY_HW_PIN_CYW43_LED_PIN_NUM CYW43_WL_GPIO_LED_PIN +#endif + +#define MICROPY_HW_PIN_RESERVED(i) ((i) == CYW43_PIN_WL_HOST_WAKE || (i) == CYW43_PIN_WL_REG_ON) \ No newline at end of file diff --git a/micropython/_board/badger2040w/fixup.sh b/micropython/_board/badger2040w/fixup.sh new file mode 100644 index 00000000..6acb551d --- /dev/null +++ b/micropython/_board/badger2040w/fixup.sh @@ -0,0 +1,6 @@ +SRC_DIR=$1 +DST_DIR=$2 + +echo "Applying wakeup_gpio.patch" +cd "$DST_DIR/../../lib/pico-sdk" +git apply "$SRC_DIR/wakeup_gpio.patch" \ No newline at end of file diff --git a/micropython/_board/badger2040w/pimoroni_badger2040w.h b/micropython/_board/badger2040w/pimoroni_badger2040w.h new file mode 100644 index 00000000..88610e7b --- /dev/null +++ b/micropython/_board/badger2040w/pimoroni_badger2040w.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +// ----------------------------------------------------- +// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO +// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES +// ----------------------------------------------------- + +#ifndef _BOARDS_PIMORONI_BADGER2040_H +#define _BOARDS_PIMORONI_BADGER2040_H + +// For board detection +#define RASPBERRYPI_PICO_W +#define PIMORONI_BADGER2040 +#define PIMORONI_BADGER2040W + +// --- BOARD SPECIFIC --- +#define BADGER2040_UART 0 +#define BADGER2040_TX_PIN 0 +#define BADGER2040_RX_PIN 1 + +#define BADGER2040_I2C 0 +#define BADGER2040_INT_PIN 3 +#define BADGER2040_SDA_PIN 4 +#define BADGER2040_SCL_PIN 5 + +#define BADGER2040_3V3_EN_PIN 10 + +#define BADGER2040_SW_DOWN_PIN 11 +#define BADGER2040_SW_A_PIN 12 +#define BADGER2040_SW_B_PIN 13 +#define BADGER2040_SW_C_PIN 14 +#define BADGER2040_SW_UP_PIN 15 + +#define BADGER2040_INKY_SPI 0 +#define BADGER2040_INKY_MISO_PIN 16 +#define BADGER2040_INKY_CSN_PIN 17 +#define BADGER2040_INKY_SCK_PIN 18 +#define BADGER2040_INKY_MOSI_PIN 19 +#define BADGER2040_INKY_DC_PIN 20 +#define BADGER2040_INKY_RESET_PIN 21 +#define BADGER2040_INKY_BUSY_PIN 26 + +#define BADGER2040_USER_SW_PIN 23 +#define BADGER2040_USER_LED_PIN 25 + +#define BADGER2040_VBUS_DETECT_PIN 24 +#define BADGER2040_VREF_POWER_PIN 27 +#define BADGER2040_1V2_REF_PIN 28 +#define BADGER2040_BAT_SENSE_PIN 29 + +// --- UART --- +#ifndef PICO_DEFAULT_UART +#define PICO_DEFAULT_UART BADGER2040_UART +#endif + +#ifndef PICO_DEFAULT_UART_TX_PIN +#define PICO_DEFAULT_UART_TX_PIN BADGER2040_TX_PIN +#endif + +#ifndef PICO_DEFAULT_UART_RX_PIN +#define PICO_DEFAULT_UART_RX_PIN BADGER2040_RX_PIN +#endif + +// --- LED --- +#ifndef PICO_DEFAULT_LED_PIN +#define PICO_DEFAULT_LED_PIN BADGER2040_USER_LED_PIN +#endif +// no PICO_DEFAULT_WS2812_PIN + +// --- I2C --- +#ifndef PICO_DEFAULT_I2C +#define PICO_DEFAULT_I2C BADGER2040_I2C +#endif +#ifndef PICO_DEFAULT_I2C_SDA_PIN +#define PICO_DEFAULT_I2C_SDA_PIN BADGER2040_SDA_PIN +#endif +#ifndef PICO_DEFAULT_I2C_SCL_PIN +#define PICO_DEFAULT_I2C_SCL_PIN BADGER2040_SCL_PIN +#endif + +// --- SPI --- +#ifndef PICO_DEFAULT_SPI +#define PICO_DEFAULT_SPI BADGER2040_INKY_SPI +#endif +#ifndef PICO_DEFAULT_SPI_SCK_PIN +#define PICO_DEFAULT_SPI_SCK_PIN BADGER2040_INKY_SCK_PIN +#endif +#ifndef PICO_DEFAULT_SPI_TX_PIN +#define PICO_DEFAULT_SPI_TX_PIN BADGER2040_INKY_MOSI_PIN +#endif +#ifndef PICO_DEFAULT_SPI_RX_PIN +#define PICO_DEFAULT_SPI_RX_PIN BADGER2040_INKY_MISO_PIN +#endif +#ifndef PICO_DEFAULT_SPI_CSN_PIN +#define PICO_DEFAULT_SPI_CSN_PIN BADGER2040_INKY_CSN_PIN +#endif + +// --- FLASH --- +#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1 + +#ifndef PICO_FLASH_SPI_CLKDIV +#define PICO_FLASH_SPI_CLKDIV 2 +#endif + +#ifndef PICO_FLASH_SIZE_BYTES +#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024) +#endif + +#ifndef PICO_RP2040_B0_SUPPORTED +#define PICO_RP2040_B0_SUPPORTED 0 +#endif + +#ifndef PICO_RP2040_B1_SUPPORTED +#define PICO_RP2040_B1_SUPPORTED 0 +#endif + +#ifndef CYW43_PIN_WL_HOST_WAKE +#define CYW43_PIN_WL_HOST_WAKE 24 +#endif + +#ifndef CYW43_PIN_WL_REG_ON +#define CYW43_PIN_WL_REG_ON 23 +#endif + +#ifndef CYW43_WL_GPIO_COUNT +#define CYW43_WL_GPIO_COUNT 3 +#endif + +#ifndef CYW43_WL_GPIO_LED_PIN +#define CYW43_WL_GPIO_LED_PIN 0 +#endif + +#endif \ No newline at end of file diff --git a/micropython/_board/badger2040w/wakeup_gpio.patch b/micropython/_board/badger2040w/wakeup_gpio.patch new file mode 100644 index 00000000..abaef7f0 --- /dev/null +++ b/micropython/_board/badger2040w/wakeup_gpio.patch @@ -0,0 +1,143 @@ +diff --git a/src/rp2_common/pico_runtime/runtime.c b/src/rp2_common/pico_runtime/runtime.c +index 70dd3bb..b8c1ed0 100644 +--- a/src/rp2_common/pico_runtime/runtime.c ++++ b/src/rp2_common/pico_runtime/runtime.c +@@ -17,6 +17,7 @@ + #include "hardware/clocks.h" + #include "hardware/irq.h" + #include "hardware/resets.h" ++#include "hardware/gpio.h" + + #include "pico/mutex.h" + #include "pico/time.h" +@@ -32,6 +33,21 @@ + #include "pico/bootrom.h" + #endif + ++// Pins to toggle on wakeup ++#ifndef PICO_WAKEUP_PIN_MASK ++#define PICO_WAKEUP_PIN_MASK ((0b1 << 10) | (0b1 << 25)) ++#endif ++ ++// Direction ++#ifndef PICO_WAKEUP_PIN_DIR ++#define PICO_WAKEUP_PIN_DIR ((0b1 << 10) | (0b1 << 25)) ++#endif ++ ++// Value ++#ifndef PICO_WAKEUP_PIN_VALUE ++#define PICO_WAKEUP_PIN_VALUE ((0b1 << 10) | (0b1 << 25)) ++#endif ++ + extern char __StackLimit; /* Set by linker. */ + + uint32_t __attribute__((section(".ram_vector_table"))) ram_vector_table[48]; +@@ -61,11 +77,18 @@ void runtime_install_stack_guard(void *stack_bottom) { + | 0x10000000; // XN = disable instruction fetch; no other bits means no permissions + } + +-void runtime_init(void) { ++void runtime_user_init(void) { ++ gpio_init_mask(PICO_WAKEUP_PIN_MASK); ++ gpio_set_dir_masked(PICO_WAKEUP_PIN_MASK, PICO_WAKEUP_PIN_DIR); ++ gpio_put_masked(PICO_WAKEUP_PIN_MASK, PICO_WAKEUP_PIN_VALUE); ++} ++ ++void runtime_reset_peripherals(void) { + // Reset all peripherals to put system into a known state, + // - except for QSPI pads and the XIP IO bank, as this is fatal if running from flash + // - and the PLLs, as this is fatal if clock muxing has not been reset on this boot + // - and USB, syscfg, as this disturbs USB-to-SWD on core 1 ++ + reset_block(~( + RESETS_RESET_IO_QSPI_BITS | + RESETS_RESET_PADS_QSPI_BITS | +@@ -86,7 +109,9 @@ void runtime_init(void) { + RESETS_RESET_UART1_BITS | + RESETS_RESET_USBCTRL_BITS + )); ++} + ++void runtime_init(void) { + // pre-init runs really early since we need it even for memcpy and divide! + // (basically anything in aeabi that uses bootrom) + +diff --git a/src/rp2_common/pico_standard_link/crt0.S b/src/rp2_common/pico_standard_link/crt0.S +index b2992f6..6091e70 100644 +--- a/src/rp2_common/pico_standard_link/crt0.S ++++ b/src/rp2_common/pico_standard_link/crt0.S +@@ -9,6 +9,8 @@ + #include "hardware/regs/addressmap.h" + #include "hardware/regs/sio.h" + #include "pico/binary_info/defs.h" ++#include "hardware/regs/resets.h" ++#include "hardware/regs/rosc.h" + + #ifdef NDEBUG + #ifndef COLLAPSE_IRQS +@@ -225,6 +227,23 @@ _reset_handler: + cmp r0, #0 + bne hold_non_core0_in_bootrom + ++ // Increase ROSC frequency to ~48MHz (range 14.4 - 96) ++ // Startup drops from ~160ms to ~32ms on Pico W MicroPython ++ ldr r0, =(ROSC_BASE + ROSC_DIV_OFFSET) ++ ldr r1, =0xaa2 ++ str r1, [r0] ++ ++ ldr r1, =runtime_reset_peripherals ++ blx r1 ++ ++ ldr r1, =runtime_user_init ++ blx r1 ++ ++ // Read GPIO state for front buttons and store ++ movs r3, 0xd0 // Load 0xd0 into r3 ++ lsls r3, r3, 24 // Shift left 24 to get 0xd0000000 ++ ldr r6, [r3, 4] // Load GPIO state (0xd0000004) into r6 ++ + // In a NO_FLASH binary, don't perform .data copy, since it's loaded + // in-place by the SRAM load. Still need to clear .bss + #if !PICO_NO_FLASH +@@ -251,6 +270,10 @@ bss_fill_test: + cmp r1, r2 + bne bss_fill_loop + ++ // runtime_wakeup_gpio_state gets zero init above ++ ldr r2, =runtime_wakeup_gpio_state // Load output var addr into r2 ++ str r6, [r2] // Store r6 to r2 ++ + platform_entry: // symbol for stack traces + // Use 32-bit jumps, in case these symbols are moved out of branch range + // (e.g. if main is in SRAM and crt0 in flash) +@@ -314,6 +337,19 @@ data_cpy_table: + runtime_init: + bx lr + ++.weak runtime_user_init ++.type runtime_user_init,%function ++.thumb_func ++runtime_user_init: ++ bx lr ++ ++.weak runtime_reset_peripherals ++.type runtime_reset_peripherals,%function ++.thumb_func ++runtime_reset_peripherals: ++ bx lr ++ ++ + // ---------------------------------------------------------------------------- + // If core 1 somehow gets into crt0 due to a spectacular VTOR mishap, we need to + // catch it and send back to the sleep-and-launch code in the bootrom. Shouldn't +@@ -345,3 +381,9 @@ __get_current_exception: + .align 2 + .equ HeapSize, PICO_HEAP_SIZE + .space HeapSize ++ ++.section .data._reset_handler ++.global runtime_wakeup_gpio_state ++.align 4 ++runtime_wakeup_gpio_state: ++.word 0x00000000 +\ No newline at end of file diff --git a/micropython/modules/micropython-badger2040w.cmake b/micropython/modules/micropython-badger2040w.cmake new file mode 100644 index 00000000..160ea378 --- /dev/null +++ b/micropython/modules/micropython-badger2040w.cmake @@ -0,0 +1,39 @@ +include_directories(${CMAKE_CURRENT_LIST_DIR}/../../) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") + +include(pimoroni_i2c/micropython) +include(pimoroni_bus/micropython) + +include(breakout_dotmatrix/micropython) +include(breakout_encoder/micropython) +include(breakout_ioexpander/micropython) +include(breakout_ltr559/micropython) +include(breakout_as7262/micropython) +include(breakout_rgbmatrix5x5/micropython) +include(breakout_matrix11x7/micropython) +include(breakout_msa301/micropython) +include(breakout_pmw3901/micropython) +include(breakout_mics6814/micropython) +include(breakout_potentiometer/micropython) +include(breakout_rtc/micropython) +include(breakout_trackball/micropython) +include(breakout_sgp30/micropython) +include(breakout_bh1745/micropython) +include(breakout_bme68x/micropython) +include(breakout_bme280/micropython) +include(breakout_bmp280/micropython) +include(breakout_icp10125/micropython) +include(breakout_scd41/micropython) + +include(hershey_fonts/micropython) +include(bitmap_fonts/micropython) + +include(badger2040/micropython) +if(NOT DEFINED BADGER2040_NO_MODULES) +include(micropython/examples/badger2040/micropython-builtins) +endif() +include(plasma/micropython) +include(ulab/code/micropython) +include(qrcode/micropython/micropython) From 6ea105bb0371d2824720cc827b7ae384bca6e8be Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 16 Nov 2022 15:16:56 +0000 Subject: [PATCH 02/46] MicroPython: Switch Badger2040 to m_new_class. --- micropython/modules/badger2040/badger2040.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/micropython/modules/badger2040/badger2040.cpp b/micropython/modules/badger2040/badger2040.cpp index b6577e45..de59c6d2 100644 --- a/micropython/modules/badger2040/badger2040.cpp +++ b/micropython/modules/badger2040/badger2040.cpp @@ -67,7 +67,7 @@ mp_obj_t Badger2040___del__(mp_obj_t self_in) { _Badger2040_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Badger2040_obj_t); // Try to ensure power is cut off when soft reset (IE: "Stop" in Thonny) self->badger2040->power_off(); - delete self->badger2040; + //delete self->badger2040; return mp_const_none; } @@ -101,7 +101,7 @@ mp_obj_t Badger2040_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ badger2040_obj = m_new_obj_with_finaliser(_Badger2040_obj_t); badger2040_obj->base.type = &Badger2040_type; badger2040_obj->buf = buffer; - badger2040_obj->badger2040 = new pimoroni::Badger2040(buffer); + badger2040_obj->badger2040 = m_new_class(pimoroni::Badger2040, buffer); badger2040_obj->badger2040->init(); return MP_OBJ_FROM_PTR(badger2040_obj); From 21b4ff68d76f629eb772946fb273703cc037ee3c Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 23 Nov 2022 11:43:01 +0000 Subject: [PATCH 03/46] Change __bswap16 to __builtin_bswap16. --- drivers/icp10125/icp10125.cpp | 16 ++++++++-------- drivers/vl53l1x/vl53l1x.cpp | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/icp10125/icp10125.cpp b/drivers/icp10125/icp10125.cpp index 6ed4ce6e..bd78089e 100644 --- a/drivers/icp10125/icp10125.cpp +++ b/drivers/icp10125/icp10125.cpp @@ -39,13 +39,13 @@ namespace pimoroni { } void ICP10125::reset() { - uint16_t command = __bswap16(SOFT_RESET); + uint16_t command = __builtin_bswap16(SOFT_RESET); i2c->write_blocking(address, (uint8_t *)&command, 2, false); sleep_ms(10); // Soft reset time is 170us but you can never be too sure... } ICP10125::reading ICP10125::measure(meas_command cmd) { - uint16_t command = __bswap16(cmd); + uint16_t command = __builtin_bswap16(cmd); reading result = {0.0f, 0.0f, OK}; uint16_result results[3]; @@ -74,9 +74,9 @@ namespace pimoroni { if(results[1].crc8 != crc8((uint8_t *)&results[1].data, 2)) {result.status = CRC_FAIL; return result;}; if(results[2].crc8 != crc8((uint8_t *)&results[2].data, 2)) {result.status = CRC_FAIL; return result;}; - int temperature = __bswap16(results[0].data); + int temperature = __builtin_bswap16(results[0].data); // Due to all the byte swapping nonsense I'm not sure if I've discarded the LLSB or LMSB here... - int pressure = ((int32_t)__bswap16(results[1].data) << 8) | (__bswap16(results[2].data >> 8)); // LLSB is discarded + int pressure = ((int32_t)__builtin_bswap16(results[1].data) << 8) | (__builtin_bswap16(results[2].data >> 8)); // LLSB is discarded process_data(pressure, temperature, &result.pressure, &result.temperature); return result; @@ -84,7 +84,7 @@ namespace pimoroni { int ICP10125::chip_id() { uint16_result result; - uint16_t command = __bswap16(READ_ID); + uint16_t command = __builtin_bswap16(READ_ID); i2c->write_blocking(address, (uint8_t *)&command, 2, true); i2c->read_blocking(address, (uint8_t *)&result, 3, false); @@ -93,12 +93,12 @@ namespace pimoroni { return -1; } - return __bswap16(result.data) & 0x3f; + return __builtin_bswap16(result.data) & 0x3f; } bool ICP10125::read_otp() { uint16_result result[4]; - uint16_t command = __bswap16(READ_OTP); + uint16_t command = __builtin_bswap16(READ_OTP); uint8_t move_address_ptr[] = { MOVE_ADDRESS_PTR >> 8, MOVE_ADDRESS_PTR & 0xff, 0x00, @@ -114,7 +114,7 @@ namespace pimoroni { if(result[x].crc8 != crc8((uint8_t *)&result[x].data, 2)) { return false; } - sensor_constants[x] = (float)__bswap16(result[x].data); + sensor_constants[x] = (float)__builtin_bswap16(result[x].data); } return true; diff --git a/drivers/vl53l1x/vl53l1x.cpp b/drivers/vl53l1x/vl53l1x.cpp index 059b406c..3eb2812a 100644 --- a/drivers/vl53l1x/vl53l1x.cpp +++ b/drivers/vl53l1x/vl53l1x.cpp @@ -205,7 +205,7 @@ namespace pimoroni { i2c->read_blocking(address, (uint8_t *)&value, 2, false); // TODO do we need to bswap this return value? - return __bswap16(value); + return __builtin_bswap16(value); } // Read a 32-bit register From c70043922ac121c9d021a3feaca2fdf3a0a31fc1 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 25 Nov 2022 11:03:04 +0000 Subject: [PATCH 04/46] Badger2040W: Switch to PicoGraphics. --- .../modules/micropython-badger2040w.cmake | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/micropython/modules/micropython-badger2040w.cmake b/micropython/modules/micropython-badger2040w.cmake index 160ea378..b3fcf252 100644 --- a/micropython/modules/micropython-badger2040w.cmake +++ b/micropython/modules/micropython-badger2040w.cmake @@ -1,11 +1,23 @@ include_directories(${CMAKE_CURRENT_LIST_DIR}/../../) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +# Essential include(pimoroni_i2c/micropython) include(pimoroni_bus/micropython) +# Pico Graphics Essential +include(hershey_fonts/micropython) +include(bitmap_fonts/micropython) +include(picographics/micropython) + +# Pico Graphics Extra +include(jpegdec/micropython) +include(qrcode/micropython/micropython) + +# Sensors & Breakouts include(breakout_dotmatrix/micropython) include(breakout_encoder/micropython) include(breakout_ioexpander/micropython) @@ -26,14 +38,22 @@ include(breakout_bme280/micropython) include(breakout_bmp280/micropython) include(breakout_icp10125/micropython) include(breakout_scd41/micropython) +include(breakout_vl53l5cx/micropython) +include(pcf85063a/micropython) -include(hershey_fonts/micropython) -include(bitmap_fonts/micropython) +# Utility +include(adcfft/micropython) +include(wakeup/micropython) -include(badger2040/micropython) -if(NOT DEFINED BADGER2040_NO_MODULES) -include(micropython/examples/badger2040/micropython-builtins) -endif() +# LEDs & Matrices include(plasma/micropython) -include(ulab/code/micropython) -include(qrcode/micropython/micropython) + +# Servos & Motors +include(pwm/micropython) +include(servo/micropython) +include(encoder/micropython) +include(motor/micropython) + +# include(micropython-common) + +include(modules_py/modules_py) \ No newline at end of file From ac2da23c961fcd4306bf35e600de88238f94e07d Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 25 Nov 2022 11:32:49 +0000 Subject: [PATCH 05/46] Badger2040W: Append filesystem. --- .github/workflows/micropython-badger2040w.yml | 61 +++++++------------ micropython/examples/badger2040w/main.py | 1 + .../examples/badger2040w/uf2-manifest.txt | 1 + 3 files changed, 23 insertions(+), 40 deletions(-) create mode 100644 micropython/examples/badger2040w/main.py create mode 100644 micropython/examples/badger2040w/uf2-manifest.txt diff --git a/.github/workflows/micropython-badger2040w.yml b/.github/workflows/micropython-badger2040w.yml index 8c0c6f94..52ef1c9e 100644 --- a/.github/workflows/micropython-badger2040w.yml +++ b/.github/workflows/micropython-badger2040w.yml @@ -68,7 +68,7 @@ jobs: restore-keys: | ccache-micropython-badger2040w-${{github.ref}} ccache-micropython-badger2040w- - + - name: Workspace Cache uses: actions/cache@v2 with: @@ -82,6 +82,13 @@ jobs: submodules: true path: pimoroni-pico-${{ github.sha }} + # Check out dir2u2f + - uses: actions/checkout@v2 + with: + repository: gadgetoid/dir2uf2 + ref: v0.0.1 + path: dir2uf2 + - name: "HACK: MicroPython Board Fixups" shell: bash working-directory: micropython/ports/rp2 @@ -95,45 +102,7 @@ jobs: sudo apt update && sudo apt install ccache gcc-arm-none-eabi python3 -m pip install pillow - # Build without BadgerOS - - name: Configure MicroPython (No BadgerOS) - shell: bash - working-directory: micropython/ports/rp2 - run: | - cmake -S . -B build-${{env.BOARD_TYPE}}-without-badger-os -DBADGER2040_NO_MODULES=1 -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/micropython-badger2040w.cmake -DMICROPY_BOARD=${{env.BOARD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - - - name: Build MicroPython (No BadgerOS) - shell: bash - working-directory: micropython/ports/rp2 - run: | - ccache --zero-stats || true - cmake --build build-${{env.BOARD_TYPE}}-without-badger-os -j 2 - ccache --show-stats || true - - - name: Rename .uf2 for artifact (No BadgerOS) - shell: bash - working-directory: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os - run: | - cp firmware.uf2 ${{env.RELEASE_FILE}}-without-badger-os.uf2 - - - name: Store .uf2 as artifact (No BadgerOS) - uses: actions/upload-artifact@v2 - with: - name: ${{env.RELEASE_FILE}}-without-badger-os.uf2 - path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os/${{env.RELEASE_FILE}}-without-badger-os.uf2 - - - name: Upload .uf2 (No BadgerOS) - if: github.event_name == 'release' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - with: - asset_path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os/${{env.RELEASE_FILE}}-without-badger-os.uf2 - upload_url: ${{github.event.release.upload_url}} - asset_name: ${{env.RELEASE_FILE}}-without-badger-os.uf2 - asset_content_type: application/octet-stream - - # Build with BadgerOS + # Build firmware - name: Configure MicroPython shell: bash working-directory: micropython/ports/rp2 @@ -154,12 +123,24 @@ jobs: run: | cp firmware.uf2 ${{env.RELEASE_FILE}}.uf2 + - name: Append Filesystem + shell: bash + run: | + python3 -m pip install littlefs-python + ./dir2uf2/dir2uf2 --append-to micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 --manifest pimoroni-pico-${{ github.sha }}/micropython/examples/badger2040w/uf2-manifest.txt --filename with-examples.uf2 pimoroni-pico-${{ github.sha }}/micropython/examples/badger2040w/ + - name: Store .uf2 as artifact uses: actions/upload-artifact@v2 with: name: ${{env.RELEASE_FILE}}.uf2 path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 + - name: Store .uf2 + examples as artifact + uses: actions/upload-artifact@v2 + with: + name: ${{env.RELEASE_FILE}}-with-examples.uf2 + path: ${{env.RELEASE_FILE}}-with-examples.uf2 + - name: Upload .uf2 if: github.event_name == 'release' uses: actions/upload-release-asset@v1 diff --git a/micropython/examples/badger2040w/main.py b/micropython/examples/badger2040w/main.py new file mode 100644 index 00000000..29658341 --- /dev/null +++ b/micropython/examples/badger2040w/main.py @@ -0,0 +1 @@ +# Hello World diff --git a/micropython/examples/badger2040w/uf2-manifest.txt b/micropython/examples/badger2040w/uf2-manifest.txt new file mode 100644 index 00000000..11a5d8e1 --- /dev/null +++ b/micropython/examples/badger2040w/uf2-manifest.txt @@ -0,0 +1 @@ +main.py \ No newline at end of file From 81d9b2ab81d8eba9a622c36934a33685d1ac0260 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 25 Nov 2022 16:48:03 +0000 Subject: [PATCH 06/46] Badger2040W: Add examples and libs. --- .../examples/badger2040w/WIFI_CONFIG.py | 3 + micropython/examples/badger2040w/clock.py | 160 ++++++++++ micropython/examples/badger2040w/launcher.py | 240 ++++++++++++++ .../examples/badger2040w/launchericons.py | 297 ++++++++++++++++++ .../examples/badger2040w/lib/badger2040w.py | 133 ++++++++ .../examples/badger2040w/lib/badger_os.py | 185 +++++++++++ .../badger2040w/lib/network_manager.py | 107 +++++++ .../badger2040w/lib/urllib/urequest.py | 67 ++++ micropython/examples/badger2040w/main.py | 11 +- .../examples/badger2040w/uf2-manifest.txt | 4 +- 10 files changed, 1205 insertions(+), 2 deletions(-) create mode 100644 micropython/examples/badger2040w/WIFI_CONFIG.py create mode 100644 micropython/examples/badger2040w/clock.py create mode 100644 micropython/examples/badger2040w/launcher.py create mode 100644 micropython/examples/badger2040w/launchericons.py create mode 100644 micropython/examples/badger2040w/lib/badger2040w.py create mode 100644 micropython/examples/badger2040w/lib/badger_os.py create mode 100644 micropython/examples/badger2040w/lib/network_manager.py create mode 100644 micropython/examples/badger2040w/lib/urllib/urequest.py diff --git a/micropython/examples/badger2040w/WIFI_CONFIG.py b/micropython/examples/badger2040w/WIFI_CONFIG.py new file mode 100644 index 00000000..76d4a887 --- /dev/null +++ b/micropython/examples/badger2040w/WIFI_CONFIG.py @@ -0,0 +1,3 @@ +SSID = "" +PSK = "" +COUNTRY = "" diff --git a/micropython/examples/badger2040w/clock.py b/micropython/examples/badger2040w/clock.py new file mode 100644 index 00000000..7d52e4c6 --- /dev/null +++ b/micropython/examples/badger2040w/clock.py @@ -0,0 +1,160 @@ +import time +import machine +import ntptime +import badger2040w + + +display = badger2040w.Badger2040W() + +WIDTH, HEIGHT = display.get_bounds() + +display.connect() + +# We're going to keep the badger on, so slow down the system clock if on battery +display.set_update_speed(3) + +ntptime.settime() +rtc = machine.RTC() + +display.set_font("gothic") + +cursors = ["year", "month", "day", "hour", "minute"] +set_clock = False +cursor = 0 +last = 0 + +# Set up the buttons +button_down = machine.Pin(badger2040w.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN) +button_up = machine.Pin(badger2040w.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN) + +button_a = machine.Pin(badger2040w.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) +button_b = machine.Pin(badger2040w.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN) +button_c = machine.Pin(badger2040w.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) + + +def days_in_month(month, year): + if month == 2 and ((year % 4 == 0 and year % 100 != 0) or year % 400 == 0): + return 29 + return (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[month - 1] + + +# Button handling function +def button(pin): + global last, set_clock, cursor, year, month, day, hour, minute + + time.sleep(0.01) + if not pin.value(): + return + + if button_a.value() and button_c.value(): + machine.reset() + + adjust = 0 + changed = False + + if pin == button_b: + set_clock = not set_clock + changed = True + if not set_clock: + rtc.datetime((year, month, day, 0, hour, minute, second, 0)) + + if set_clock: + if pin == button_c: + cursor += 1 + cursor %= len(cursors) + + if pin == button_a: + cursor -= 1 + cursor %= len(cursors) + + if pin == button_up: + adjust = 1 + + if pin == button_down: + adjust = -1 + + if cursors[cursor] == "year": + year += adjust + year = max(year, 2022) + day = min(day, days_in_month(month, year)) + if cursors[cursor] == "month": + month += adjust + month = min(max(month, 1), 12) + day = min(day, days_in_month(month, year)) + if cursors[cursor] == "day": + day += adjust + day = min(max(day, 1), days_in_month(month, year)) + if cursors[cursor] == "hour": + hour += adjust + hour %= 24 + if cursors[cursor] == "minute": + minute += adjust + minute %= 60 + + if set_clock or changed: + draw_clock() + + +# Register the button handling function with the buttons +button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button) +button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button) +button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) +button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button) +button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button) + + +def draw_clock(): + hms = "{:02}:{:02}:{:02}".format(hour, minute, second) + ymd = "{:04}/{:02}/{:02}".format(year, month, day) + + hms_width = display.measure_text(hms, 1.8) + hms_offset = int((WIDTH / 2) - (hms_width / 2)) + h_width = display.measure_text(hms[0:2], 1.8) + mi_width = display.measure_text(hms[3:5], 1.8) + mi_offset = display.measure_text(hms[0:3], 1.8) + + ymd_width = display.measure_text(ymd, 1.0) + ymd_offset = int((WIDTH / 2) - (ymd_width / 2)) + y_width = display.measure_text(ymd[0:4], 1.0) + m_width = display.measure_text(ymd[5:7], 1.0) + m_offset = display.measure_text(ymd[0:5], 1.0) + d_width = display.measure_text(ymd[8:10], 1.0) + d_offset = display.measure_text(ymd[0:8], 1.0) + + display.set_pen(15) + display.clear() + display.set_pen(0) + + display.text(hms, hms_offset, 40, 0, 1.8) + display.text(ymd, ymd_offset, 100, 0, 1.0) + + if set_clock: + if cursors[cursor] == "year": + display.line(ymd_offset, 120, ymd_offset + y_width, 120) + if cursors[cursor] == "month": + display.line(ymd_offset + m_offset, 120, ymd_offset + m_offset + m_width, 120) + if cursors[cursor] == "day": + display.line(ymd_offset + d_offset, 120, ymd_offset + d_offset + d_width, 120) + + if cursors[cursor] == "hour": + display.line(hms_offset, 70, hms_offset + h_width, 70) + if cursors[cursor] == "minute": + display.line(hms_offset + mi_offset, 70, hms_offset + mi_offset + mi_width, 70) + + display.update() + + +year, month, day, wd, hour, minute, second, _ = rtc.datetime() + +if (year, month, day) == (2021, 1, 1): + rtc.datetime((2022, 2, 28, 0, 12, 0, 0, 0)) + +last_second = second + +while True: + if not set_clock: + year, month, day, wd, hour, minute, second, _ = rtc.datetime() + if second != last_second: + draw_clock() + last_second = second + time.sleep(0.01) diff --git a/micropython/examples/badger2040w/launcher.py b/micropython/examples/badger2040w/launcher.py new file mode 100644 index 00000000..ea28ef02 --- /dev/null +++ b/micropython/examples/badger2040w/launcher.py @@ -0,0 +1,240 @@ +import gc +import time +import math +import badger2040w as badger2040 +import launchericons +import badger_os + +# Reduce clock speed to 48MHz +badger2040.system_speed(badger2040.SYSTEM_NORMAL) + +changed = False +exited_to_launcher = False +woken_by_button = badger2040.woken_by_button() # Must be done before we clear_pressed_to_wake + +if badger2040.pressed_to_wake(badger2040.BUTTON_A) and badger2040.pressed_to_wake(badger2040.BUTTON_C): + # Pressing A and C together at start quits app + exited_to_launcher = badger_os.state_clear_running() +else: + # Otherwise restore previously running app + badger_os.state_launch() + +# for e.g. 2xAAA batteries, try max 3.4 min 3.0 +MAX_BATTERY_VOLTAGE = 4.0 +MIN_BATTERY_VOLTAGE = 3.2 + +display = badger2040.Badger2040W() +display.set_font("bitmap8") +display.led(128) + +state = { + "page": 0, + "font_size": 1, + "inverted": False, + "running": "launcher" +} + +badger_os.state_load("launcher", state) + +display.invert(state["inverted"]) + +icons = bytearray(launchericons.data()) +icons_width = 576 + +examples = [ + ("_clock", 0), + ("_fonts", 1), + ("_ebook", 2), + ("_image", 3), + ("_list", 4), + ("_badge", 5), + ("_qrgen", 8), + ("_info", 6), + ("_help", 7), +] + +font_sizes = (0.5, 0.7, 0.9) + +# Approximate center lines for buttons A, B and C +centers = (41, 147, 253) + +MAX_PAGE = math.ceil(len(examples) / 3) + +WIDTH = 296 + + +def map_value(input, in_min, in_max, out_min, out_max): + return (((input - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min + + +def draw_battery(level, x, y): + # Outline + display.set_pen(15) + display.rectangle(x, y, 19, 10) + # Terminal + display.rectangle(x + 19, y + 3, 2, 4) + display.set_pen(0) + display.rectangle(x + 1, y + 1, 17, 8) + if level < 1: + display.set_pen(0) + display.line(x + 3, y, x + 3 + 10, y + 10) + display.line(x + 3 + 1, y, x + 3 + 11, y + 10) + display.set_pen(15) + display.line(x + 2 + 2, y - 1, x + 4 + 12, y + 11) + display.line(x + 2 + 3, y - 1, x + 4 + 13, y + 11) + return + # Battery Bars + display.set_pen(15) + for i in range(4): + if level / 4 > (1.0 * i) / 4: + display.rectangle(i * 4 + x + 2, y + 2, 3, 6) + + +def draw_disk_usage(x): + _, f_used, _ = badger_os.get_disk_usage() + + display.set_pen(15) + display.image( + bytearray( + ( + 0b00000000, + 0b00111100, + 0b00111100, + 0b00111100, + 0b00111000, + 0b00000000, + 0b00000000, + 0b00000001, + ) + ), + 8, + 8, + x, + 4, + ) + display.rectangle(x + 10, 3, 80, 10) + display.set_pen(0) + display.rectangle(x + 11, 4, 78, 8) + display.set_pen(15) + display.rectangle(x + 12, 5, int(76 / 100.0 * f_used), 6) + display.text("{:.2f}%".format(f_used), x + 91, 4, WIDTH, 1.0) + + +def render(): + display.set_pen(15) + display.clear() + display.set_pen(0) + + max_icons = min(3, len(examples[(state["page"] * 3):])) + + for i in range(max_icons): + x = centers[i] + label, icon = examples[i + (state["page"] * 3)] + label = label[1:].replace("_", " ") + display.set_pen(0) + display.icon(icons, icon, icons_width, 64, x - 32, 24) + w = display.measure_text(label, font_sizes[state["font_size"]]) + display.text(label, int(x - (w / 2)), 16 + 80, WIDTH, font_sizes[state["font_size"]]) + + for i in range(MAX_PAGE): + x = 286 + y = int((128 / 2) - (MAX_PAGE * 10 / 2) + (i * 10)) + display.set_pen(0) + display.rectangle(x, y, 8, 8) + if state["page"] != i: + display.set_pen(15) + display.rectangle(x + 1, y + 1, 6, 6) + + display.set_pen(0) + display.rectangle(0, 0, WIDTH, 16) + draw_disk_usage(90) + vbat = badger_os.get_battery_level() + bat = int(map_value(vbat, MIN_BATTERY_VOLTAGE, MAX_BATTERY_VOLTAGE, 0, 4)) + draw_battery(bat, WIDTH - 22 - 3, 3) + display.set_pen(15) + display.text("badgerOS", 4, 4, WIDTH, 1.0) + + display.update() + + +def wait_for_user_to_release_buttons(): + pr = display.pressed + while pr(badger2040.BUTTON_A) or pr(badger2040.BUTTON_B) or pr(badger2040.BUTTON_C) or pr(badger2040.BUTTON_UP) or pr(badger2040.BUTTON_DOWN): + time.sleep(0.01) + + +def launch_example(index): + wait_for_user_to_release_buttons() + + file = examples[(state["page"] * 3) + index][0] + + for k in locals().keys(): + if k not in ("gc", "file", "badger_os"): + del locals()[k] + + gc.collect() + + badger_os.launch(file) + + +def button(pin): + global changed + changed = True + + if not display.pressed(badger2040.BUTTON_USER): # User button is NOT held down + if pin == badger2040.BUTTON_A: + launch_example(0) + if pin == badger2040.BUTTON_B: + launch_example(1) + if pin == badger2040.BUTTON_C: + launch_example(2) + if pin == badger2040.BUTTON_UP: + if state["page"] > 0: + state["page"] -= 1 + render() + if pin == badger2040.BUTTON_DOWN: + if state["page"] < MAX_PAGE - 1: + state["page"] += 1 + render() + else: # User button IS held down + if pin == badger2040.BUTTON_UP: + state["font_size"] += 1 + if state["font_size"] == len(font_sizes): + state["font_size"] = 0 + render() + if pin == badger2040.BUTTON_DOWN: + state["font_size"] -= 1 + if state["font_size"] < 0: + state["font_size"] = 0 + render() + if pin == badger2040.BUTTON_A: + state["inverted"] = not state["inverted"] + display.invert(state["inverted"]) + render() + + +if exited_to_launcher or not woken_by_button: + wait_for_user_to_release_buttons() + display.set_update_speed(badger2040.UPDATE_MEDIUM) + render() + +display.set_update_speed(badger2040.UPDATE_FAST) + +while True: + if display.pressed(badger2040.BUTTON_A): + button(badger2040.BUTTON_A) + if display.pressed(badger2040.BUTTON_B): + button(badger2040.BUTTON_B) + if display.pressed(badger2040.BUTTON_C): + button(badger2040.BUTTON_C) + + if display.pressed(badger2040.BUTTON_UP): + button(badger2040.BUTTON_UP) + if display.pressed(badger2040.BUTTON_DOWN): + button(badger2040.BUTTON_DOWN) + + if changed: + badger_os.state_save("launcher", state) + changed = False + + display.halt() diff --git a/micropython/examples/badger2040w/launchericons.py b/micropython/examples/badger2040w/launchericons.py new file mode 100644 index 00000000..831e6884 --- /dev/null +++ b/micropython/examples/badger2040w/launchericons.py @@ -0,0 +1,297 @@ +# Code generated by convert.py. + +_data =\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xf0\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x0f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x01\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xfc\x00\x00\x00'\ +b'\x00\x00\x00\x0f\xfc\x00\x00\x00\x00\x00\x00\x1f\xf8\x00\x00\x00'\ +b'\x03\xff\xf8\x61\x98\x1f\xff\xc0\x00\x00\x0f\xff\xff\xc0\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x7f\xfe\x00\x00\x00\x00\x00\x00\x7f\xff\x80\x00\x00'\ +b'\x00\x00\x00\xff\xff\x00\x00\x00\x03\xff\xf8\x61\x98\x1f\xff\xc0'\ +b'\x00\x00\x3f\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xff\xff\xff\xff\x80\x00'\ +b'\x00\x1f\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x7f\xfe\x00\x00\x00'\ +b'\x00\x00\x03\xff\xff\xf0\x00\x00\x00\x00\x07\xff\xff\xe0\x00\x00'\ +b'\x03\x00\x18\x01\xf9\x98\x00\xc0\x00\x00\x7f\xff\xff\xf8\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x3f\xff\xff\xff\xff\xf0\x00\x00\xff\xff\xff\xff\xff\xfc\x00'\ +b'\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x0f\xff\xff\xfc\x00\x00'\ +b'\x00\x00\x1f\xff\xff\xf8\x00\x00\x03\x00\x18\x01\xf9\x98\x00\xc0'\ +b'\x00\x01\xff\xc0\x0f\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xff\xff\xf8\x00'\ +b'\x01\xff\xff\xff\xff\xff\xfe\x00\x00\x00\x00\xfc\x3f\x00\x00\x00'\ +b'\x00\x00\x1f\xff\xff\xfe\x00\x00\x00\x00\x3f\xff\xff\xfc\x00\x00'\ +b'\x03\x3f\x18\x60\x18\x18\xfc\xc0\x00\x03\xfe\x00\x01\xff\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x7f\xff\xff\xff\xff\xf8\x00\x03\xff\xff\xff\xff\xff\xff\x00'\ +b'\x00\x00\x00\xfc\x3f\x00\x00\x00\x00\x00\x7f\xf0\x03\xff\x80\x00'\ +b'\x00\x00\xff\xe0\x07\xff\x00\x00\x03\x3f\x18\x60\x18\x18\xfc\xc0'\ +b'\x00\x07\xf8\x00\x00\x7f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xff\xff\xf8\x00'\ +b'\x03\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xfc\x3f\x00\x00\x00'\ +b'\x00\x00\xff\x80\x00\x7f\xc0\x00\x00\x01\xff\x00\x00\xff\x80\x00'\ +b'\x03\x3f\x19\x98\x61\x98\xfc\xc0\x00\x0f\xf0\x00\x00\x3f\xc0\x00'\ +b'\x00\x00\x03\xff\xff\xff\xfe\x00\x00\x03\xff\x80\x03\xfe\x00\x00'\ +b'\x00\xff\xff\xff\xff\xff\xfc\x00\x03\xff\xff\xff\xff\xff\xff\x00'\ +b'\x00\x00\x00\xfc\x3f\x00\x00\x00\x00\x01\xfe\x00\x00\x1f\xe0\x00'\ +b'\x00\x03\xfc\x00\x00\x3f\xc0\x00\x03\x3f\x19\x98\x61\x98\xfc\xc0'\ +b'\x00\x0f\xc0\x00\x00\x0f\xc0\x00\x00\x00\x03\xff\xff\xff\xfe\x00'\ +b'\x00\x3f\xff\xf0\x1f\xff\xf0\x00\x00\xfc\x00\x00\x00\x00\xfc\x00'\ +b'\x03\xe0\x00\x00\x00\x00\x1f\x00\x00\x00\x00\xfc\x3f\x00\x00\x00'\ +b'\x00\x03\xfc\x00\x00\x0f\xf0\x00\x00\x07\xf8\x00\x00\x1f\xe0\x00'\ +b'\x03\x3f\x19\x87\xe1\x98\xfc\xc0\x00\x1f\x80\x00\x00\x07\xe0\x00'\ +b'\x00\x00\x03\xff\xff\xff\xfe\x00\x00\xff\xff\xfe\x3f\xff\xfc\x00'\ +b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\ +b'\x00\x00\x00\xfc\x3f\x00\x00\x00\x00\x03\xf0\x00\x60\x03\xf0\x00'\ +b'\x00\x07\xe0\x00\x00\x07\xe0\x00\x03\x3f\x19\x87\xe1\x98\xfc\xc0'\ +b'\x00\x3f\x00\x00\x00\x03\xf0\x00\x00\x00\x03\xff\xff\xff\xfe\x00'\ +b'\x03\xff\xff\xff\xff\xff\xff\x00\x00\xfc\x00\x00\x00\x00\xfc\x00'\ +b'\x03\xe0\x00\x00\x00\x00\x1f\x00\x00\x00\x00\xfc\x3f\x00\x00\x00'\ +b'\x00\x07\xe0\x01\xf8\x01\xf8\x00\x00\x0f\xc0\x00\x00\x03\xf0\x00'\ +b'\x03\x00\x18\x79\x98\x18\x00\xc0\x00\x7e\x00\x07\x00\x01\xf8\x00'\ +b'\x00\x00\x03\xff\xff\xff\xfe\x00\x03\xff\xff\xff\xff\xff\xff\x80'\ +b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\ +b'\x00\x0f\xff\xfc\x3f\xff\xf0\x00\x00\x0f\xc0\x01\xf8\x00\xfc\x00'\ +b'\x00\x1f\x80\x0f\xe0\x01\xf8\x00\x03\x00\x18\x79\x98\x18\x00\xc0'\ +b'\x00\x7e\x00\x07\x00\x01\xf8\x00\x00\x00\x03\xff\xff\xff\xfe\x00'\ +b'\x07\xfe\x00\xff\xff\x03\xff\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ +b'\x03\xe3\xff\xc0\x00\x00\x1f\x00\x00\x7f\xff\xfc\x3f\xff\xfe\x00'\ +b'\x00\x1f\x80\x01\xfc\x00\x7e\x00\x00\x3f\x00\x3f\xf0\x00\xfc\x00'\ +b'\x03\x00\x18\x79\x98\x18\x00\xc0\x00\xfc\x00\x07\x00\x00\xfc\x00'\ +b'\x00\x00\x03\xff\xff\xff\xfe\x00\x07\xe0\x00\x1f\xf0\x00\x1f\x80'\ +b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe7\xff\xc0\x00\x00\x1f\x00'\ +b'\x00\xff\xff\xfc\x3f\xff\xff\x00\x00\x1f\x80\x01\xf8\x00\x7e\x00'\ +b'\x00\x3f\x00\x7f\xf8\x00\xfc\x00\x03\xff\xf9\x99\x99\x9f\xff\xc0'\ +b'\x00\xf8\x00\x07\x00\x00\x7c\x00\x00\x00\x00\x00\x3f\xe0\x00\x00'\ +b'\x07\xe0\x00\x0f\xc0\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ +b'\x03\xe7\xff\xc0\x00\x00\x1f\x00\x01\xff\xff\xfc\x3f\xff\xff\x80'\ +b'\x00\x3f\x00\x01\xf8\x00\x3f\x00\x00\x7e\x00\xff\xfc\x00\x7e\x00'\ +b'\x03\xff\xf9\x99\x99\x9f\xff\xc0\x00\xf8\x00\x07\x00\x00\x7c\x00'\ +b'\x00\x00\x00\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ +b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe7\xff\xc0\x00\x00\x1f\x00'\ +b'\x01\xff\xff\xfc\x3f\xff\xff\x80\x00\x3e\x00\x00\xf0\x00\x1f\x00'\ +b'\x00\x7c\x01\xfc\xfe\x00\x3e\x00\x00\x00\x00\x61\x9f\x80\x00\x00'\ +b'\x01\xf0\x00\x07\x00\x00\x3e\x00\x00\x00\x00\x00\x1f\xe0\x00\x00'\ +b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ +b'\x03\xe7\xff\xc0\x00\x00\x1f\x00\x01\xf0\x00\xff\xff\x00\x0f\x80'\ +b'\x00\x3e\x00\x00\x00\x00\x1f\x00\x00\x7c\x03\xf0\x3f\x00\x3e\x00'\ +b'\x00\x00\x00\x61\x9f\x80\x00\x00\x01\xf0\x00\x07\x00\x00\x3e\x00'\ +b'\x00\x00\x00\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ +b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\ +b'\x01\xf0\x00\x7f\xfe\x00\x0f\x80\x00\x7c\x00\x00\x00\x00\x0f\x80'\ +b'\x00\xf8\x03\xe0\x1f\x00\x1f\x00\x03\xc0\xfe\x78\x60\x00\xf0\x00'\ +b'\x01\xf0\x00\x07\x00\x00\x3e\x00\x00\x00\x00\x00\x1f\xe0\x00\x00'\ +b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ +b'\x03\xe0\x00\x00\x00\x06\x1f\x00\x01\xf0\x00\x7f\xfe\x00\x0f\x80'\ +b'\x00\x7c\x00\x3f\x80\x00\x0f\x80\x00\xf8\x03\xc0\x0f\x00\x1f\x00'\ +b'\x03\xc0\xfe\x78\x60\x00\xf0\x00\x01\xe0\x00\x07\x00\x00\x1e\x00'\ +b'\x00\xff\xff\xfc\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ +b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x0f\x1f\x00'\ +b'\x01\xf0\x00\x3f\xfc\x00\x0f\x80\x00\x7c\x00\x7f\xe0\x00\x0f\x80'\ +b'\x00\xf8\x03\xc0\x0f\x80\x1f\x00\x03\xff\x00\x1f\xff\x87\xff\x00'\ +b'\x03\xe0\x00\x07\x00\x00\x1f\x00\x01\xff\xff\xfc\x1f\xe0\x00\x00'\ +b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ +b'\x03\xe0\x00\x00\x00\x1f\x9f\x00\x01\xf0\x00\x1f\xf8\x00\x0f\x80'\ +b'\x00\x78\x00\xff\xf0\x00\x07\x80\x00\xf0\x03\xc0\x0f\x80\x0f\x00'\ +b'\x03\xff\x00\x1f\xff\x87\xff\x00\x03\xe0\x00\x07\x00\x00\x1f\x00'\ +b'\x01\xff\xff\xfc\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ +b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x3f\x9f\x00'\ +b'\x01\xf0\x00\x07\xe0\x00\x0f\x80\x00\xf8\x00\x7f\xf0\x00\x07\xc0'\ +b'\x01\xf0\x03\xc0\x0f\x80\x0f\x80\x03\xcf\xf8\x61\xff\xe7\x33\xc0'\ +b'\x03\xe0\x00\x07\x00\x00\x1f\x00\x01\xff\xff\xfc\x1f\xe0\x00\x00'\ +b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ +b'\x03\xe0\x00\x00\x20\x7f\x1f\x00\x01\xf0\x00\x00\x00\x00\x0f\x80'\ +b'\x00\xf8\x00\x7f\xf0\x00\x07\xc0\x01\xf0\x00\x00\x1f\x00\x0f\x80'\ +b'\x03\xcf\xf8\x61\xff\xe7\x33\xc0\x03\xe0\x00\x07\x00\x00\x1f\x00'\ +b'\x01\xff\xff\xfc\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ +b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe7\xff\xc0\x70\xfe\x1f\x00'\ +b'\x01\xf0\x00\x00\x00\x00\x0f\x80\x00\xf8\x00\x07\xf0\x00\x07\xc0'\ +b'\x01\xf0\x00\x00\x7f\x00\x0f\x80\x00\x33\xe1\x9f\x98\x78\xf0\xc0'\ +b'\x03\xe0\x00\x07\x00\x00\x1f\x00\x01\xff\xff\xfc\x1f\xe0\x00\x00'\ +b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ +b'\x03\xe7\xff\xc0\xf9\xfc\x1f\x00\x01\xf0\x01\xc0\x07\xfe\x0f\x80'\ +b'\x00\xf8\x00\x07\xf0\x00\x07\xc0\x01\xf0\x00\x00\xfe\x00\x0f\x80'\ +b'\x00\x33\xe1\x9f\x98\x78\xf0\xc0\x03\xe0\x00\x07\xc0\x00\x1f\x00'\ +b'\x01\xff\xff\xfc\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ +b'\x00\xfc\x00\x00\x08\x00\xfc\x00\x03\xe7\xff\xc1\xff\xf8\x1f\x00'\ +b'\x01\xf0\x03\xe0\x07\xfe\x0f\x80\x00\xf8\x00\x07\xf0\x00\x07\xc0'\ +b'\x01\xf0\x00\x03\xfe\x00\x0f\x80\x03\x00\x19\xfe\x01\x9f\x00\xc0'\ +b'\x03\xe0\x00\x07\xe0\x00\x1f\x00\x01\xff\xff\xfc\x1f\xe0\x00\x00'\ +b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x1c\x00\xfc\x00'\ +b'\x03\xe7\xff\xc0\xff\xf0\x1f\x00\x01\xf0\x07\xf0\x07\xfe\x0f\x80'\ +b'\x00\xf8\x00\x0f\xe0\x00\x07\xc0\x01\xf0\x00\x03\xf8\x00\x0f\x80'\ +b'\x03\x00\x19\xfe\x01\x9f\x00\xc0\x03\xe0\x00\x03\xf8\x00\x1f\x00'\ +b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ +b'\x00\xfc\x00\x00\x3e\x00\xfc\x00\x03\xe0\x00\x00\x7f\xe0\x1f\x00'\ +b'\x01\xf0\x07\xf0\x07\xfe\x0f\x80\x00\xf8\x00\x0f\xe0\x00\x07\xc0'\ +b'\x01\xf0\x00\x07\xf0\x00\x0f\x80\x03\xcc\x07\x9f\x87\x87\x03\x00'\ +b'\x01\xe0\x00\x00\xfe\x00\x1e\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ +b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x01\x00\x7e\x00\xfc\x00'\ +b'\x03\xe0\x00\x00\x3f\xc0\x1f\x00\x01\xf0\x07\xf0\x00\x00\x0f\x80'\ +b'\x00\xf8\x00\x0f\xe0\x00\x07\xc0\x01\xf0\x00\x07\xc0\x00\x0f\x80'\ +b'\x03\xcc\x07\x9f\x87\x87\x03\x00\x01\xf0\x00\x00\x3f\x00\x3e\x00'\ +b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ +b'\x00\xfc\x03\x80\x7f\x00\xfc\x00\x03\xe0\x00\x00\x1f\x80\x1f\x00'\ +b'\x01\xf0\x07\xf0\x00\x00\x0f\x80\x00\x78\x00\x0f\xe0\x00\x07\x80'\ +b'\x00\xf0\x00\x0f\x80\x00\x0f\x00\x03\x3c\xfe\x19\xe6\x60\x33\xc0'\ +b'\x01\xf0\x00\x00\x1f\xc0\x3e\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ +b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x07\xc0\xff\x80\xfc\x00'\ +b'\x03\xe0\x00\x00\x0f\x00\x1f\x00\x01\xf0\x03\xe0\x00\x00\x0f\x80'\ +b'\x00\x7c\x00\x0f\xe0\x00\x0f\x80\x00\xf8\x00\x0f\x80\x00\x1f\x00'\ +b'\x03\x3c\xfe\x19\xe6\x60\x33\xc0\x01\xf0\x00\x00\x07\xe0\x3e\x00'\ +b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ +b'\x00\xfc\x07\xe1\xff\xc0\xfc\x00\x03\xe0\x00\x00\x06\x00\x1f\x00'\ +b'\x01\xf0\x00\x00\x07\xfe\x0f\x80\x00\x7c\x00\x1f\xe0\x00\x0f\x80'\ +b'\x00\xf8\x00\x0f\x80\x00\x1f\x00\x03\x0f\xe1\x87\x9e\x60\xcc\xc0'\ +b'\x00\xf8\x00\x00\x01\xe0\x7c\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ +b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x0f\xe3\xff\xc0\xfc\x00'\ +b'\x03\xe3\xff\xc0\x00\x00\x1f\x00\x01\xf0\x00\x00\x07\xfe\x0f\x80'\ +b'\x00\x7c\x00\x1f\xc0\x00\x0f\x80\x00\xf8\x00\x07\x00\x00\x1f\x00'\ +b'\x03\x0f\xe1\x87\x9e\x60\xcc\xc0\x00\xf8\x00\x00\x00\xc0\x7c\x00'\ +b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ +b'\x00\xfc\x1f\xf7\xff\xe0\xfc\x00\x03\xe7\xff\xc0\x00\x00\x1f\x00'\ +b'\x01\xf0\x01\xc0\x07\xfe\x0f\x80\x00\x3e\x00\x1f\xc0\x00\x1f\x00'\ +b'\x00\x7c\x00\x00\x00\x00\x3e\x00\x03\x3c\xfe\x00\x79\xff\xcc\x00'\ +b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ +b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x3f\xff\xff\xf0\xfc\x00'\ +b'\x03\xe7\xff\xc0\x00\x00\x1f\x00\x01\xf0\x1f\xfc\x07\xfe\x0f\x80'\ +b'\x00\x3e\x00\x1f\xc0\x00\x1f\x00\x00\x7c\x00\x00\x00\x00\x3e\x00'\ +b'\x03\x3c\xfe\x00\x79\xff\xcc\x00\x00\x7e\x00\x00\x00\x01\xf8\x00'\ +b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ +b'\x00\xfc\x7f\xff\xff\xf8\xfc\x00\x03\xe7\xff\xc0\x00\x00\x1f\x00'\ +b'\x01\xf0\x3f\xfe\x00\x00\x0f\x80\x00\x3f\x00\x1f\xc0\x00\x3f\x00'\ +b'\x00\x7e\x00\x02\x00\x00\x7e\x00\x00\x00\x01\xfe\x01\x80\xcc\x00'\ +b'\x00\x7e\x00\x00\x00\x01\xf8\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ +b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x7f\xff\xff\xf8\xfc\x00'\ +b'\x03\xe7\xff\xc0\x00\x00\x1f\x00\x01\xf0\x7f\xff\x00\x00\x0f\x80'\ +b'\x00\x1f\x80\x1f\xc7\x00\x7e\x00\x00\x3f\x00\x0f\x80\x00\xfc\x00'\ +b'\x00\x00\x01\xfe\x01\x80\xcc\x00\x00\x3f\x00\x00\x00\x03\xf0\x00'\ +b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe3\xff\x0f\x80\x00\x1f\x80'\ +b'\x00\xfc\xff\xff\xff\xfc\xfc\x00\x03\xe3\xff\xc0\x00\x00\x1f\x00'\ +b'\x01\xf0\x7f\xff\x00\x00\x0f\x80\x00\x1f\x80\x1f\xcf\x00\x7e\x00'\ +b'\x00\x3f\x00\x0f\x80\x00\xfc\x00\x03\xff\xf9\xfe\x79\x98\xf0\xc0'\ +b'\x00\x1f\x80\x00\x00\x07\xe0\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ +b'\x07\xff\xff\xff\x83\xff\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ +b'\x03\xe0\x00\x00\x00\x00\x1f\x00\x01\xf0\x7f\xff\x00\x00\x0f\x80'\ +b'\x00\x0f\xc0\x0f\xff\x00\xfc\x00\x00\x1f\x80\x0f\x80\x01\xf8\x00'\ +b'\x03\xff\xf9\xfe\x79\x98\xf0\xc0\x00\x0f\xc0\x00\x00\x0f\xc0\x00'\ +b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xff\xff\xff\x8f\xff\xff\x80'\ +b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\ +b'\x01\xf0\x00\x00\x00\x00\x0f\x80\x00\x07\xe0\x07\xff\x01\xf8\x00'\ +b'\x00\x0f\xc0\x0f\x80\x03\xf0\x00\x03\x00\x19\x80\x1f\x80\xc0\x00'\ +b'\x00\x0f\xf0\x00\x00\x3f\xc0\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ +b'\x07\xff\xff\xff\xbf\xff\xff\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ +b'\x03\xe0\x00\x00\x00\x00\x1f\x00\x01\xf0\x00\x00\x00\x00\x0f\x80'\ +b'\x00\x03\xf0\x03\xfc\x03\xf0\x00\x00\x07\xe0\x07\x00\x07\xe0\x00'\ +b'\x03\x00\x19\x80\x1f\x80\xc0\x00\x00\x07\xf8\x00\x00\x7f\x80\x00'\ +b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xff\xff\xff\xff\xff\xff\x80'\ +b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\ +b'\x01\xf0\x00\x00\x00\x00\x0f\x80\x00\x03\xfc\x00\x70\x0f\xf0\x00'\ +b'\x00\x07\xf8\x00\x00\x1f\xe0\x00\x03\x00\x19\x80\x1f\x80\xc0\x00'\ +b'\x00\x03\xfe\x00\x01\xff\x00\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ +b'\x07\xfe\x01\xff\xff\xff\xff\x80\x00\xff\xff\xff\xff\xff\xfc\x00'\ +b'\x03\xff\xff\xff\xff\xff\xff\x00\x01\xf0\x00\x00\x00\x00\x0f\x80'\ +b'\x00\x01\xfe\x00\x00\x1f\xe0\x00\x00\x03\xfc\x00\x00\x3f\xc0\x00'\ +b'\x03\x3f\x18\x01\xff\xff\xff\x00\x00\x01\xff\xc0\x0f\xfe\x00\x00'\ +b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x03\xf0\x00\x1f\xfe\x01\xff\x80'\ +b'\x00\x7f\xff\xff\xff\xff\xf8\x00\x03\xff\xff\xff\xff\xff\xff\x00'\ +b'\x01\xf0\x00\x00\x00\x00\x0f\x80\x00\x00\xff\x80\x00\x7f\xc0\x00'\ +b'\x00\x01\xff\x00\x00\xff\x80\x00\x03\x3f\x18\x01\xff\xff\xff\x00'\ +b'\x00\x00\x7f\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x01\x80\x00\x07\xf8\x00\x3f\x00\x00\x7f\xff\xff\xff\xff\xf8\x00'\ +b'\x03\xff\xff\xff\xff\xff\xff\x00\x01\xff\xff\xff\xff\xff\xff\x80'\ +b'\x00\x00\x7f\xf0\x03\xff\x80\x00\x00\x00\xff\xe0\x07\xff\x00\x00'\ +b'\x03\x3f\x18\x66\x1e\x7f\x33\xc0\x00\x00\x3f\xff\xff\xf0\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xe0\x00\x06\x00'\ +b'\x00\x7f\xff\xff\xff\xff\xf8\x00\x01\xff\xff\xff\xff\xff\xfe\x00'\ +b'\x01\xff\xff\xff\xff\xff\xff\x80\x00\x00\x1f\xff\xff\xfe\x00\x00'\ +b'\x00\x00\x3f\xff\xff\xfc\x00\x00\x03\x3f\x18\x66\x1e\x7f\x33\xc0'\ +b'\x00\x00\x0f\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x3f\xff\xff\xff\xff\xf0\x00'\ +b'\x00\xff\xff\xff\xff\xff\xfc\x00\x00\xff\xff\xff\xff\xff\xff\x00'\ +b'\x00\x00\x0f\xff\xff\xfc\x00\x00\x00\x00\x1f\xff\xff\xf8\x00\x00'\ +b'\x03\x3f\x18\x18\x19\xe7\x0c\xc0\x00\x00\x01\xff\xfe\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x7f\xff\xff\xff\xff\xfe\x00\x00\x00\x03\xff\xff\xf0\x00\x00'\ +b'\x00\x00\x07\xff\xff\xe0\x00\x00\x03\x3f\x18\x18\x19\xe7\x0c\xc0'\ +b'\x00\x00\x00\x3f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xff\xff\xff\xff\xfc\x00'\ +b'\x00\x00\x00\x7f\xff\x80\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00'\ +b'\x03\x00\x19\xe6\x01\x9f\xc0\xc0\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xfc\x00\x00\x00'\ +b'\x00\x00\x00\x1f\xf8\x00\x00\x00\x03\x00\x19\xe6\x01\x9f\xc0\xc0'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x03\xff\xf9\xe7\x81\xe0\x30\xc0\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x03\xff\xf9\xe7\x81\xe0\x30\xc0'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ + +_mvdata = memoryview(_data) + +def data(): + return _mvdata + diff --git a/micropython/examples/badger2040w/lib/badger2040w.py b/micropython/examples/badger2040w/lib/badger2040w.py new file mode 100644 index 00000000..e19d995c --- /dev/null +++ b/micropython/examples/badger2040w/lib/badger2040w.py @@ -0,0 +1,133 @@ +import machine +from picographics import PicoGraphics, DISPLAY_INKY_PACK +from network_manager import NetworkManager +import WIFI_CONFIG +import uasyncio +import gc +import wakeup + + +BUTTON_UP = 15 +BUTTON_DOWN = 11 +BUTTON_A = 12 +BUTTON_B = 13 +BUTTON_C = 14 +BUTTON_USER = 23 + +BUTTON_MASK = 0b11111 << 11 + +SYSTEM_VERY_SLOW = 0 +SYSTEM_SLOW = 1 +SYSTEM_NORMAL = 2 +SYSTEM_FAST = 3 +SYSTEM_TURBO = 4 + +UPDATE_NORMAL = 0 +UPDATE_MEDIUM = 1 +UPDATE_FAST = 2 +UPDATE_TURBO = 3 + +WIDTH = 296 +HEIGHT = 128 + +SYSTEM_FREQS = [ + 4000000, + 12000000, + 48000000, + 133000000, + 250000000 +] + +WAKEUP_GPIO_STATE = wakeup.get_gpio_state() + +BUTTONS = { + 11: machine.Pin(11), + 12: machine.Pin(12), + 13: machine.Pin(13), + 14: machine.Pin(14), + 15: machine.Pin(15), + 23: machine.Pin(23) +} + + +def woken_by_button(): + return WAKEUP_GPIO_STATE & BUTTON_MASK > 0 + + +def pressed_to_wake(button): + return WAKEUP_GPIO_STATE & (1 << button) > 0 + + +def system_speed(speed): + try: + machine.freq(SYSTEM_FREQS[speed]) + except IndexError: + pass + + +class Badger2040W(): + def __init__(self): + self.display = PicoGraphics(DISPLAY_INKY_PACK) + + def __getattr__(self, item): + # Glue to redirect calls to PicoGraphics + if item in dir(self.display): + return getattr(self.display, item) + elif item in self.__dict__.keys(): + return getattr(self, item) + else: + raise AttributeError(f"No attribute '{item}'") + + def led(self, brightness): + pass + + def invert(self, invert): + pass + + def thickness(self, thickness): + print("Thickness!") + + def halt(self): + pass + + def pressed(self, button): + return BUTTONS[button].value() == 1 + + @micropython.native + def icon(self, data, index, data_w, icon_size, x, y): + s_x = (index * icon_size) % data_w + s_y = int((index * icon_size) / data_w) + + for o_y in range(icon_size): + for o_x in range(icon_size): + o = ((o_y + s_y) * data_w) + (o_x + s_x) + bm = 0b10000000 >> (o & 0b111) + if data[o >> 3] & bm: + self.display.pixel(x + o_x, y + o_y) + + def image(self, data, w, h, x, y): + for oy in range(h): + row = data[oy] + for ox in range(w): + if row & 0b1 == 0: + self.display.pixel(x + ox, y + oy) + row >>= 1 + + + def status_handler(self, mode, status, ip): + print(mode, status, ip) + self.display.set_pen(15) + self.display.clear() + self.display.set_pen(0) + if status: + self.display.text("Connected!", 10, 10, 300, 0.5) + self.display.text(ip, 10, 30, 300, 0.5) + else: + self.display.text("Connecting...", 10, 10, 300, 0.5) + self.display.update() + + def connect(self): + self.display.set_update_speed(2) + network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=self.status_handler) + uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK)) + gc.collect() diff --git a/micropython/examples/badger2040w/lib/badger_os.py b/micropython/examples/badger2040w/lib/badger_os.py new file mode 100644 index 00000000..7effe1cb --- /dev/null +++ b/micropython/examples/badger2040w/lib/badger_os.py @@ -0,0 +1,185 @@ +"""Keep track of app state in persistent flash storage.""" + +import os +import gc +import time +import json +import machine +import badger2040w as badger2040 + + +def get_battery_level(): + return 0 + # Battery measurement + vbat_adc = machine.ADC(badger2040.PIN_BATTERY) + vref_adc = machine.ADC(badger2040.PIN_1V2_REF) + vref_en = machine.Pin(badger2040.PIN_VREF_POWER) + vref_en.init(machine.Pin.OUT) + vref_en.value(0) + + # Enable the onboard voltage reference + vref_en.value(1) + + # Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries + vdd = 1.24 * (65535 / vref_adc.read_u16()) + vbat = ( + (vbat_adc.read_u16() / 65535) * 3 * vdd + ) # 3 in this is a gain, not rounding of 3.3V + + # Disable the onboard voltage reference + vref_en.value(0) + + # Convert the voltage to a level to display onscreen + return vbat + + +def get_disk_usage(): + # f_bfree and f_bavail should be the same? + # f_files, f_ffree, f_favail and f_flag are unsupported. + f_bsize, f_frsize, f_blocks, f_bfree, _, _, _, _, _, f_namemax = os.statvfs("/") + + f_total_size = f_frsize * f_blocks + f_total_free = f_bsize * f_bfree + f_total_used = f_total_size - f_total_free + + f_used = 100 / f_total_size * f_total_used + f_free = 100 / f_total_size * f_total_free + + return f_total_size, f_used, f_free + + +def state_running(): + state = {"running": "launcher"} + state_load("launcher", state) + return state["running"] + + +def state_clear_running(): + running = state_running() + state_modify("launcher", {"running": "launcher"}) + return running != "launcher" + + +def state_set_running(app): + state_modify("launcher", {"running": app}) + + +def state_launch(): + app = state_running() + if app is not None and app != "launcher": + launch("_" + app) + + +def state_delete(app): + try: + os.remove("/state/{}.json".format(app)) + except OSError: + pass + + +def state_save(app, data): + try: + with open("/state/{}.json".format(app), "w") as f: + f.write(json.dumps(data)) + f.flush() + except OSError: + import os + try: + os.stat("/state") + except OSError: + os.mkdir("/state") + state_save(app, data) + + +def state_modify(app, data): + state = {} + state_load(app, state) + state.update(data) + state_save(app, state) + + +def state_load(app, defaults): + try: + data = json.loads(open("/state/{}.json".format(app), "r").read()) + if type(data) is dict: + defaults.update(data) + return True + except (OSError, ValueError): + pass + + state_save(app, defaults) + return False + + +def launch(file): + state_set_running(file[1:]) + + gc.collect() + + button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) + button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) + + def quit_to_launcher(pin): + if button_a.value() and button_c.value(): + machine.reset() + + button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher) + button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher) + + try: + try: + __import__(file[1:]) # Try to import _[file] (drop underscore prefix) + except ImportError: + __import__(file) # Failover to importing [_file] + + except ImportError: + # If the app doesn't exist, notify the user + warning(None, "Could not launch: " + file[1:]) + time.sleep(4.0) + except Exception as e: + # If the app throws an error, catch it and display! + print(e) + warning(None, str(e)) + time.sleep(4.0) + + # If the app exits or errors, do not relaunch! + state_clear_running() + machine.reset() # Exit back to launcher + + +# Draw an overlay box with a given message within it +def warning(display, message, width=badger2040.WIDTH - 40, height=badger2040.HEIGHT - 40, line_spacing=20, text_size=0.6): + print(message) + + if display is None: + display = badger2040.Badger2040W() + display.led(128) + + # Draw a light grey background + display.set_pen(12) + display.rectangle((badger2040.WIDTH - width) // 2, (badger2040.HEIGHT - height) // 2, width, height) + + # Take the provided message and split it up into + # lines that fit within the specified width + words = message.split(" ") + + lines = [] + current_line = "" + for word in words: + if display.measure_text(current_line + word + " ", text_size) < width: + current_line += word + " " + else: + lines.append(current_line.strip()) + current_line = word + " " + lines.append(current_line.strip()) + + display.set_pen(0) + + # Display each line of text from the message, centre-aligned + num_lines = len(lines) + for i in range(num_lines): + length = display.measure_text(lines[i], text_size) + current_line = (i * line_spacing) - ((num_lines - 1) * line_spacing) // 2 + display.text(lines[i], (badger2040.WIDTH - length) // 2, (badger2040.HEIGHT // 2) + current_line, badger2040.WIDTH, text_size) + + display.update() diff --git a/micropython/examples/badger2040w/lib/network_manager.py b/micropython/examples/badger2040w/lib/network_manager.py new file mode 100644 index 00000000..d4d59230 --- /dev/null +++ b/micropython/examples/badger2040w/lib/network_manager.py @@ -0,0 +1,107 @@ +import rp2 +import network +import machine +import uasyncio + + +class NetworkManager: + _ifname = ("Client", "Access Point") + + def __init__(self, country="GB", client_timeout=30, access_point_timeout=5, status_handler=None, error_handler=None): + rp2.country(country) + self._ap_if = network.WLAN(network.AP_IF) + self._sta_if = network.WLAN(network.STA_IF) + + self._mode = network.STA_IF + self._client_timeout = client_timeout + self._access_point_timeout = access_point_timeout + self._status_handler = status_handler + self._error_handler = error_handler + self.UID = ("{:02X}" * 8).format(*machine.unique_id()) + + def isconnected(self): + return self._sta_if.isconnected() or self._ap_if.isconnected() + + def config(self, var): + if self._sta_if.active(): + return self._sta_if.config(var) + else: + if var == "password": + return self.UID + return self._ap_if.config(var) + + def mode(self): + if self._sta_if.isconnected(): + return self._ifname[0] + if self._ap_if.isconnected(): + return self._ifname[1] + return None + + def ifaddress(self): + if self._sta_if.isconnected(): + return self._sta_if.ifconfig()[0] + if self._ap_if.isconnected(): + return self._ap_if.ifconfig()[0] + return '0.0.0.0' + + def disconnect(self): + if self._sta_if.isconnected(): + self._sta_if.disconnect() + if self._ap_if.isconnected(): + self._ap_if.disconnect() + + async def wait(self, mode): + while not self.isconnected(): + self._handle_status(mode, None) + await uasyncio.sleep_ms(1000) + + def _handle_status(self, mode, status): + if callable(self._status_handler): + self._status_handler(self._ifname[mode], status, self.ifaddress()) + + def _handle_error(self, mode, msg): + if callable(self._error_handler): + if self._error_handler(self._ifname[mode], msg): + return + raise RuntimeError(msg) + + async def client(self, ssid, psk): + if self._sta_if.isconnected(): + self._handle_status(network.STA_IF, True) + return + + self._ap_if.disconnect() + self._ap_if.active(False) + + self._sta_if.active(True) + self._sta_if.connect(ssid, psk) + + try: + await uasyncio.wait_for(self.wait(network.STA_IF), self._client_timeout) + self._handle_status(network.STA_IF, True) + + except uasyncio.TimeoutError: + self._sta_if.active(False) + self._handle_status(network.STA_IF, False) + self._handle_error(network.STA_IF, "WIFI Client Failed") + + async def access_point(self): + if self._ap_if.isconnected(): + self._handle_status(network.AP_IF, True) + return + + self._sta_if.disconnect() + self._sta_if.active(False) + + self._ap_if.ifconfig(("10.10.1.1", "255.255.255.0", "10.10.1.1", "10.10.1.1")) + self._ap_if.config(password=self.UID) + self._ap_if.active(True) + + try: + await uasyncio.wait_for(self.wait(network.AP_IF), self._access_point_timeout) + self._handle_status(network.AP_IF, True) + + except uasyncio.TimeoutError: + self._sta_if.active(False) + self._handle_status(network.AP_IF, False) + self._handle_error(network.AP_IF, "WIFI Client Failed") diff --git a/micropython/examples/badger2040w/lib/urllib/urequest.py b/micropython/examples/badger2040w/lib/urllib/urequest.py new file mode 100644 index 00000000..4c654d45 --- /dev/null +++ b/micropython/examples/badger2040w/lib/urllib/urequest.py @@ -0,0 +1,67 @@ +import usocket + + +def urlopen(url, data=None, method="GET"): + if data is not None and method == "GET": + method = "POST" + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import ussl + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = usocket.getaddrinfo(host, port, 0, usocket.SOCK_STREAM) + ai = ai[0] + + s = usocket.socket(ai[0], ai[1], ai[2]) + try: + s.connect(ai[-1]) + if proto == "https:": + s = ussl.wrap_socket(s, server_hostname=host) + + s.write(method) + s.write(b" /") + s.write(path) + s.write(b" HTTP/1.0\r\nHost: ") + s.write(host) + s.write(b"\r\n") + + if data: + s.write(b"Content-Length: ") + s.write(str(len(data))) + s.write(b"\r\n") + s.write(b"\r\n") + if data: + s.write(data) + + l = s.readline() + l = l.split(None, 2) + # print(l) + status = int(l[1]) + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + l) + elif l.startswith(b"Location:"): + raise NotImplementedError("Redirects not yet supported") + except OSError: + s.close() + raise + + return s diff --git a/micropython/examples/badger2040w/main.py b/micropython/examples/badger2040w/main.py index 29658341..39fcdade 100644 --- a/micropython/examples/badger2040w/main.py +++ b/micropython/examples/badger2040w/main.py @@ -1 +1,10 @@ -# Hello World +import WIFI_CONFIG + +if WIFI_CONFIG.SSID == "": + import badger2040w + badger2040w.init() + badger2040w.screen.set_pen(15) + badger2040w.screen.clear() + badger2040w.screen.set_pen(0) + badger2040w.screen.text("Please configure your WiFi in WIFI_CONFIG.py") + badger2040w.screen.update() diff --git a/micropython/examples/badger2040w/uf2-manifest.txt b/micropython/examples/badger2040w/uf2-manifest.txt index 11a5d8e1..02acc631 100644 --- a/micropython/examples/badger2040w/uf2-manifest.txt +++ b/micropython/examples/badger2040w/uf2-manifest.txt @@ -1 +1,3 @@ -main.py \ No newline at end of file +*.py +lib/*.py +lib/urllib/*.py \ No newline at end of file From 9bd29e0ef28eae7dfbc8aba105bc3942fe2ea76b Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 13 Jan 2023 10:38:08 +0000 Subject: [PATCH 07/46] JPEGDEC: Fix iWidthUsed skip not advancing pixel pointer. --- micropython/modules/jpegdec/jpegdec.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp index 6153368e..fb0ba23c 100644 --- a/micropython/modules/jpegdec/jpegdec.cpp +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -95,9 +95,10 @@ MICROPY_EVENT_POLL_HOOK uint8_t *pixel = (uint8_t *)pDraw->pPixels; for(int y = 0; y < pDraw->iHeight; y++) { for(int x = 0; x < pDraw->iWidth; x++) { - if(x >= pDraw->iWidthUsed) break; // Clip to the used width - current_graphics->set_pen((uint8_t)(*pixel >> 4)); - current_graphics->set_pixel({pDraw->x + x, pDraw->y + y}); + if(x < pDraw->iWidthUsed) { // Clip to the used width + current_graphics->set_pen((uint8_t)(*pixel >> 4)); + current_graphics->pixel({pDraw->x + x, pDraw->y + y}); + } pixel++; } } From 984dbd5185aedac53ea49199a9c4407fb2793c47 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 13 Jan 2023 13:55:33 +0000 Subject: [PATCH 08/46] Badger2040W: Switch launcher to jpegdec, reorganise files. --- .../examples/badger2040w/examples/badge.py | 0 .../badger2040w/{ => examples}/clock.py | 0 .../examples/badger2040w/examples/ebook.py | 0 .../examples/badger2040w/examples/fonts.py | 0 .../examples/badger2040w/examples/help.py | 0 .../badger2040w/examples/icon-badge.jpg | Bin 0 -> 1856 bytes .../badger2040w/examples/icon-clock.jpg | Bin 0 -> 1880 bytes .../badger2040w/examples/icon-ebook.jpg | Bin 0 -> 1767 bytes .../badger2040w/examples/icon-fonts.jpg | Bin 0 -> 1424 bytes .../badger2040w/examples/icon-help.jpg | Bin 0 -> 2057 bytes .../badger2040w/examples/icon-image.jpg | Bin 0 -> 1377 bytes .../badger2040w/examples/icon-info.jpg | Bin 0 -> 2005 bytes .../badger2040w/examples/icon-list.jpg | Bin 0 -> 1654 bytes .../badger2040w/examples/icon-qrgen.jpg | Bin 0 -> 2832 bytes .../examples/badger2040w/examples/image.py | 0 .../examples/badger2040w/examples/info.py | 0 .../examples/badger2040w/examples/list.py | 0 .../examples/badger2040w/examples/qrgen.py | 0 micropython/examples/badger2040w/launcher.py | 33 +- .../examples/badger2040w/launchericons.py | 297 ------------------ .../examples/badger2040w/lib/badger_os.py | 7 +- micropython/examples/badger2040w/main.py | 10 - .../examples/badger2040w/uf2-manifest.txt | 4 +- 23 files changed, 19 insertions(+), 332 deletions(-) create mode 100644 micropython/examples/badger2040w/examples/badge.py rename micropython/examples/badger2040w/{ => examples}/clock.py (100%) create mode 100644 micropython/examples/badger2040w/examples/ebook.py create mode 100644 micropython/examples/badger2040w/examples/fonts.py create mode 100644 micropython/examples/badger2040w/examples/help.py create mode 100644 micropython/examples/badger2040w/examples/icon-badge.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-clock.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-ebook.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-fonts.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-help.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-image.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-info.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-list.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-qrgen.jpg create mode 100644 micropython/examples/badger2040w/examples/image.py create mode 100644 micropython/examples/badger2040w/examples/info.py create mode 100644 micropython/examples/badger2040w/examples/list.py create mode 100644 micropython/examples/badger2040w/examples/qrgen.py delete mode 100644 micropython/examples/badger2040w/launchericons.py delete mode 100644 micropython/examples/badger2040w/main.py diff --git a/micropython/examples/badger2040w/examples/badge.py b/micropython/examples/badger2040w/examples/badge.py new file mode 100644 index 00000000..e69de29b diff --git a/micropython/examples/badger2040w/clock.py b/micropython/examples/badger2040w/examples/clock.py similarity index 100% rename from micropython/examples/badger2040w/clock.py rename to micropython/examples/badger2040w/examples/clock.py diff --git a/micropython/examples/badger2040w/examples/ebook.py b/micropython/examples/badger2040w/examples/ebook.py new file mode 100644 index 00000000..e69de29b diff --git a/micropython/examples/badger2040w/examples/fonts.py b/micropython/examples/badger2040w/examples/fonts.py new file mode 100644 index 00000000..e69de29b diff --git a/micropython/examples/badger2040w/examples/help.py b/micropython/examples/badger2040w/examples/help.py new file mode 100644 index 00000000..e69de29b diff --git a/micropython/examples/badger2040w/examples/icon-badge.jpg b/micropython/examples/badger2040w/examples/icon-badge.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c732ee168946ca712ea7a891b91cc23e9e6955b4 GIT binary patch literal 1856 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 literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/icon-ebook.jpg b/micropython/examples/badger2040w/examples/icon-ebook.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7c1b73cb4346e250a3aa49237d02021e646f02cf GIT binary patch literal 1767 zcmbW#YdF+d7y$6|pZgdSlOZuTwq zz2AoK{Wk`Ogl^xlbJy;ueftkYb7Nu;CmcykI(jTQGwbJ**{4qbawfmv{I3@-Ub=kc zX34G6-^$8wSJa4W@7GBl)HghBX?@lvecs+7>+0_Ly|?e}yZ+&ipGHQ<#uXEjvn~iA zzpzy67uY{sB$W$+LLpJuSr>$eR!t-cg*LLq%ysd_21RHYv*K~&6({m;RO9J(>*U(o zBAeB881^!g;aS>e*}sDc{+H}8*x#-WppJx8pNAv?HW;5|7O~ru_6mL1Pc2h{gX5Zm zGmjFs2TVv_WgTsT>L>1yq{(1J%|ZeLSwSTY2F|adl+!C=APFm$58bC>xw(yLl8pk3 ziyx~>?=1f|=S@C%KBv9A$Es;bPYAL&zg(m<&5>U`Y;97~8Xj`WCsq5=$!noKVgnY} z&2ggm;T)TvQa;KLHE$uF>0%07{Nt%Lw{C8#TMx0hgBfS%R3Z*S=QK9w-{x!Z+~n!W zMMPnGVf8mp-Vv_W4ppE|He@U6!!PObj)rp5Tsf)5Z>&E=Ywi`NopzFjPkHd` zomyZpU_nzRXQ#JIl%BnLFbMKzk8n896MjvmA_fL4#+6<#`NIwJ$H!qny!9qYs<&oW z^r@(7US{H&!fOv6Y{+N;hDns*6az2rWYazV%mq=e9}LPwGX>7-a*rya!v^`Y?858) z{p?hd9=0npeqo;j0Puw`xc_*V{>*1;c zp?wz(M@M@r(h;gm<n@eHfW(8F8K`IOwpS)pEe2qV8zLC9yHeq@uY34`>44Qp?zph?oL6vA; zxD#4tao0fXDd_4CD~UX1*KlCLdh+EI;EjuUxpXQL8okR?y||YDun-2}{3-WhwyNEN zX4_3eIlXqa-EtK z`w}V%=XQ-!qy#M!WS z4oxs)`7?q773Zc@q|j1&_9co2w8LPKpM7t$qNF>(K_WCSeP&;7EfZKU%0esL{4A+2 z=wUW>l<3i-OVjw-`iKL^)Jj!XtZ~+H@|LA8yx&3Ta4*8)@!Ib_#d+xjr#{;o`!p+5klxYax)e>cE_jHB!e`rQAJty>n>)mfMdpp zWQOjiqcpjOX|`MVT_S-}bJ*(k;xXH|A zcc`+Wd#oCA@(F&n2pw7TN_Xa@O;r&J(U%s@J8!G+#X5-KC%q=#F3ZNsucyp)W!5cY zHpkH^tT@h;05=$5LWa60B?E)9u=lmOYb)=y1heuo(Lv@hTZ2v#cny;4y_Q(EnJ%); j(sIwpqoo}+O>FD7Hbx@(rB|yDB1Py0sJrizA-Meyf0i2L literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/icon-fonts.jpg b/micropython/examples/badger2040w/examples/icon-fonts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1eac916c8f07df9bf7bebd891650c7f2d55a6733 GIT binary patch literal 1424 zcmbW#X;70#7y#h?a(xK|Lxdn;Xu{P*L6jr{9vA`z!P?qz7@-P95fCgE5ye)GfPm6s zJZl?U=l40>1q%gBJv_aZE%*DtKVWrW z(3+6Yu=SD+;SpP6w#LTAZ%atomAZRR+TJfS4`pTN96pj;P*`;Q#JAs_EG|EDw&I6# z=PQ4_bh)Os?#k8rYb~v9H`_ZpyX4(Hy?5^^?koESAFGF+Jbm{3#Y^4jnEv&fal^#q ztP277cPwmt2m6PMj=69I0-k`*x)9tRtmEkfqP;t5u1JhVCtEo1(#e*-`DGWIDUSSL zEo1Y}J0@06fyDD#Ut3~;pspK#wWSu2Tfd9H&;1b*2;3+ zUf(i2E4ZhK)u)S6>hF>ec53v)MwQWaMKc6?GlfvoCY;`V&^sen2Z148gFR7OU! zy;qlh>B}M@-e7dSakXdV{HiEr*OP&W7vmPbQ=-0C^BG<%ndZwC9W3oBL#r|SdI|(2 zzEl^AyoMmJ(H#Pc?9k#GTHSuxNMw{|x|*M)WEg)BNV#J7l|lwVD-VL+0SJmz#{NhV zmaY0m_&iY|)Nb*FfU&8gg=Upj7-Fb66Rt93hBed{{-&aiUkc1S?Buxc<2hthTRLam zV^;c8EqX)}bYgNvZ^3|@!^th&H3he_HY&5B_ zUp~e8zQn;}SQDjDTaQGrYW7SQc?*rrVhElq6PspAq(i3@SZ^4G5cvE1*i6nF*3BGw zY{y>@!J%`%PMJNBtdhJrFfhgRcrcM;)6UO~9Q3zDm|DNo9gD8FiGLxS4-OpqME){> z%+`vSo3Bc3(-ybX-5~1BZZ>7t#K(QTwmxm>Xp3`9w1v6I^qA<`(uWeEx@m%Q+8KhM z!W72b1Yj6z{=zR+T}}J+fj{&1hn4+K`JH9Qd*!7WGy=WdWw?PwG3;2|cyzS2buz4? zcdt@lC2oIpOw@|x9}ApLRLgMEE#!q2rIQ{J8VKT8 z6P)6lnXDKH?uaGG)M{)^4+O&umND-{0|d$rW6;ww2%^J<`p{5h*i!5d7?H+yRY*_O z_Qj54i;~LIVn1q23Lq@$9E!2%z99BtdgrvzaNCOWYG+PoVbvlp^o1a?WF(bc*}QMI zT#~V;x@9OFRAuekbiPAcwJj>~+EIIxraosGnZk~?o^wIE{I*t=RkMTqqI*O9ZfQ(y cK?t8yJi4_Ll+<&|W%4?1DK3{=N`uNj0AaUi`~Uy| literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/icon-help.jpg b/micropython/examples/badger2040w/examples/icon-help.jpg new file mode 100644 index 0000000000000000000000000000000000000000..572d5b418243c90e75c4ca88061b89f21c8b35e9 GIT binary patch literal 2057 zcmbW$cT^Kd9tZGAfmDQ0gkTVXP$WnPiKI|Yinw$HWL>35vCyOo0#W3!1&o5!tP~M+ z5d@{I4TCh5A{d%THwFcR0!oow+`V`A-u-pE-+43t%= zh_D4Hi~1CU{1Nc)K%g+Vm^cE7LSsY)_oM(60)s)}FflPWTvVMT+6Qo)n6!$4rMQfX zFG4j!)-W~eI#SK5rdiIlS3orKi)5hCo8=Yois~AgTHCdaO-y&1k#|}DW4Dd1o&6p+ zcaMFZUf%ot0}clU1&16t5fvR18yBB&`b^r{^nYfYyUef+|%HtOK}LEZzpW=IGNUJH&e0?EcB82 zv!rJF7B|sY_%qZ#;JX7uf4iMNG2vuv(?O2LG4Qh)lB(IZMi7SHh~|9I0hVZ>ZKX zd(_imz=Ra?mC+qlvFmE{xb~TCJOZy~s)+JsLl^O6&VM5zEY^)3@F#^;u4ZSSd|O{b69<$w19|%f|qdMRrE?_PQ|i>}pw4Yu}LfPZ5gk zDA)G16titpYW<#PPrcl1`uPY=^>Of*XsomKmU+51Ig+D9HYlH&4~7kWs;bjVKZUtG z?(>~x*QW~cO~q`r1Csj!eLE=G9n_!Vc30Ib*iO#ZP`T;xG*&5xq?2yqT0vI;`RK7si19LgC_N;hc>iKzZakU`16C8zXy1(HR8M8M1S&F-%&EOZZ1&2 zk(+$W;`p)HPY>Brn%yM*F0a(*sRQiR6pH`TWZVNc!Pqm2UlXm?qVDHx2?z;2Y}66f zaLDcwCX9JO4nBUGdCjoCC!y-9e^p4VVqp1krI&?Ik7aAV=d3U`A=NT1)Zm^k*mCP( zK?~+ByEIr6&%LMDD0h80IxV)#8R}6U!>AR{X;+NYsZgsa_Kn4Sa^0L_Yv<&=L&x0Q z)H#P-qozO)(Ac3#ys$(~$O9`Z&Yj9c!Z*%VW_*01>7>_0Ll%>T70^)zZ;)Fs(su7X z24YYqOVq@LHHX2GwwvE#zWYDx?{&g58`j&?&=;b{+l7E#edmOLTV`52aX`(z!Haux zL@Si&)r`jX7{G`H0jqhS=2l4chg~MiIpME#Y46QcAXT{9SmK)(O}_9x&Q*w> zPh7o^VCf@0sHrK#3zhGGJF`}t>5Jcy?q};VQ$(dP@8r?+;@sQ?$`@tY6y>^y=054J zKZ_gTF=kSAk$$nHiIKi+SI{~xS@xlQgEkzO?<(LHmcQR0Jvvh`fE_6A#gA!2F7B!5 zu!@z*v~eLL@E<7>3y9qd+#JHPQJcg!t5D;wnRs6{P!JvP9BZaP#y7VU##(*G2!lg> z={OU;JR{Qg+uj!HNl!{_vlt_%JiBOay?2ptnEymQXH>5_L8-LEcjjp9=B)E8)2tUs zymtX`rR&y&#D_6e4!FE|65VQ}R|w9W+`BO#1exq1)wQ5e(I=`7TYIecw%d_Pl5C?( zMID6lBb|~cCk|c_A9Jz?*?y6bHjlj(&$CibUnqb=rr33k<=<~jj>>Sj&fkk?xf*^d z$LC+|?c7XF2{6UkDLGv;TUwR0@AK`gJF28RS{khL+f@C<(rq>F&c7A_qty2#p3@nc z>}yK=l{m`cZA469S^ zJ$2?tX+AxnZEtma>7W_eQx`guZua3)QWRyUfYkCxl}qeTj6F$xa6C(M)wMg;01Yh^ z0>iYgL^ewSFlfx;lteVu{JUDLV&*%0GO@^>SithsDo&vbhyDfq Cn3kdd literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/icon-image.jpg b/micropython/examples/badger2040w/examples/icon-image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0c34c1c815202f0271ddbfc68a2da81891ab7cf3 GIT binary patch literal 1377 zcmex=^(PF6}rMnOeST|r4lSw=>~TvNxu(8R<c1}I=;VrF4wW9Q)H;sz?% zD!{d!pzFb!U9xX3zTPI5o8roG<0MW4oqZMDikqloVbuf*=gfJ(V&YTRE(2~ znmD<{#3dx9RMpfqG__1j&CD$#!}nhr>-$XCW*^xvQj=Mnm{?j{&HMDuq#K!^ z{WdOAYSaESjbn{6yZU~cNtF!0<+^?{{}Y*h#QvA~{!eB1|1j_@{~2T!@UMTdewH0` z#qAI|lkUU6+LqRqCYNShjCNF+m*n)Z_jK>^CjniLxvy(aJfQrtiUDX~Q~am!E&9JJ z{xe*v)PDWzC-Z~pf2O|W{&&y*%RDcJU;nx^7BF@7oaefuy4zb~?!~#vI_5?z89QV> zSf>czF8I1qgPDLCzy39Fp_=;Z-#&*Qs{a{OtDXKcZ14Z8KB>X>{-f_l`hPfXG1+!G zt>N|dIZpkbC6u2Viyq_SIKbQBZ*LGLD&Mxx=*6!7!!Q51uh~)-F6O7OYin<_$)t%> zKTWq({7^V=cDy=Q)Xu%d-|F^!m8wO8+~)qd=!qF1H$EXk>{fvtjp>->L) zw$%R&D|i2A(A@ubTZ7H!pdZa^{dU@RL5X#`yfb_3OA}m{u(2;x_;AMJTn6(IJI?x(aToT# zef*!n^U3=4uQ7s?LHoJCP~G{cukSlcwfD;XcI)=vv7<7f^YoFVFzao(Aqh;+GY-CB zJn+JDbAKU-3Y_b3SpTYb;gVf@GlE;t9e-XOypW*$V`+u_b%_mx!P5wjw wgLl0T#;MMaytc07c6)TO=%(nl35yM-=ND_eRdkGFJW=+f{F|4?0{;Iu0nO=G-v9sr literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/icon-info.jpg b/micropython/examples/badger2040w/examples/icon-info.jpg new file mode 100644 index 0000000000000000000000000000000000000000..73bcd3e3758b4c23044398b2328b601429753d8e GIT binary patch literal 2005 zcmbW&cTm%58VB%S@=JvPMv8$X1PCnX0+K@Wkbo%l3`!9M6=@2h5{eL5k}qlD6k0}5Rr1YdviB)GdHt)-*?{kpZA$}p3l7R%)2$T zH4f~sx3;qeAP@k6Y!6^-1h4{72m}%VM)QjSvNDTzVmje4wgT(Wy_QN%IMfM@uQ~!YQk0eWR_jdk@{v$k@bm zpVh%b);6|w_RcP@$K2eHd-(eKpE(;4crGmbQbZ&>Dmo!C>FTxX$u}}?XJ%#R-1*_| zy`tih`@9FG4}Yw#sjaJj+|bz8-qHE|r>^c7{R3|Y-~D~){qV#ug2}0A;mqtu@#4}y zmRD9KpVz*+AOQF~YkU12_FpdSwhIb_fiUD(7X%u)JwYrCu1-Phv^G0IO>{u25aiktdJ!d|(PJHBa7naaZtd1}J*Ak1RKj0) z0q>bOlN8DU^m9B>u8e#`JT>9Jk5B#8BlJ1)K78B59A%b0; zgn*beJvchhAmn+>t8wvV>`J|9YtM~xp}2Y`&J-}?ChF>Z%gTL7j-!*kuTcQUhmC5HLt+^M#LIe2w#Z~nxEidIvcn(*rWPC#+V zrt^cRi+HS4Iu<@li^{I+FGdqWgHw5As{I#B@@XGlWp5h$rPSJ~7C#9|Lvl-?%B%2d zCk?-T@_I4KKg&1UPSHJ%o9h>nz-=j_Lw?=Fik{p`Xf_Ni8nVG*)oAvmHE;A0v-pfq z+u7T39200cJLhojaZx3|WTYl&|9s{*L`>UCj7-#m-Lxbd$y&wm%4~WlvbIsZhQZpV*tstu0lnou>|$E> zX;#ESTWW(@Y0qd8iyzKKU96a@e|*EVAWO=Qa6|c|Z7WO_MNV-`-t6(1E-eilo=RF? zUp1;@oKY&JEi76g;V#?*6T75)eL2*y1qH|=FFE{!!#KZF$B?L3y!rZXuSA;uS^o8V zmqus?r)>eudWSzLAtlBUCi>vn84|1;X1NEMW;;Y}O#j}Ju*1fbkKZUhe_>K|@%ELz z>5oLK?$lLMma4HXW#G2Tl~dDAj){$#!~C|Vaz8Vx%1RpQArSC9vv2n#H=;m$Z2!I^ z$UraZWtxEmFBsfRqKDeR-h}Y1v_`HE>5q#kU67lJ7L=6FoU~^f#$Jqdw#abm{ynpp zVuz`yQ%9P2tJ{&&ZQZAx^H+CC$D@#WRRGDtttY>xt_0KA6Ib%ETR1ZEk~L>Be9YSQ zh-pul{Mj@CKiEd%EoK}Rb5nx?BO?jsYRNF?kryv2Sgm$cYXk^Yr~)oGr})CeTYzc{ zDad1fo|jB#Yqsq0tSElRvi5MrzfX8Tc=U3dLp6{iYgrgG&gSB8I$r(pu-SLyrng#m z!N5-7pI$9pRQ7k^TzH1#=)Uy06xyTK zNndWzGc!uj$9%lG*2y51T!DRUmgeKM<6%?J-0#c}TpZ}a7-M4PNp~h%cm>d+|MkRN zGLInNaA^``3~%&)*|qz7`kX|)Q zu~R8}4~LD-y)aG(znxw_QKiR~jp|;zas&9Bu(|7Lhs<}IT8+$npZbB=G9x7?2V)Xt zxV%RW5bj~WVb=QENo)l9#82txM(K^*cY`a<87E$;M5NZ6cL|iS<9QcO7e=yp@Sxdf r9gx(nitAq|7q%A%?ua@jUVQa)b7gcBcaFtS+x{_(bnbB&Tkrn~lNoFH literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/icon-list.jpg b/micropython/examples/badger2040w/examples/icon-list.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dcc97c4c6a34e142f9a59d6e123596c7afb2ae1d GIT binary patch literal 1654 zcmbu7c{tQt7{||VX3WA^#!?1jW{f4t?pm^zBGMHlQcP&MRGyOchM|<|S}G!?A|-Xp zaChlbPuiUgra z5ZnN$$UViNF9LrGLZLBYSR9@pE`b=zWB>|6qfr>Nm>33wxMPrWfFX&=(hWCY<=p&m zYRBb`;xFam85>L33ho@9y0L%ADT4T_)rw>#4Na{z+G|a|Gc_}}SZ}{+vxDOnC+8hI zJ$89|?e-4Xf8gMu9|D6;gocGjL`MC1I^oRO#B=8_Tuw{Bl972e>)P$SJ9qQ%72JRD z%j43r@`}nQPwSsIG`?tRZfWi8di~}tx4WlzXn16FYbJT1kNn>kJ_#0=R=6O5 z{)&afuVCMBkq|Bv27|`nR=6Nk1hUa2j2PVzE4#rB=XYFA%_tr(zwuIT37fz$cIPSh zhj7GKshbRG%&nk(A^T@wr~VV!UtoW8^#URqLOu^o0=D4Ol1`c+vuGfaIW%7MFfdu^ zz1^jU-+!p2M=6*Entlq{-kR06GSQYVO>&Efd{XR_k0UEa3stHH6 ziLtQZLkm6%^Ejcl{y7$3pEWvN3j>urk$h%@?b7Pn`S1Z4q-@7=`JT;G-klmc41TSK zL0UNsgdwQ{ccu&sCVgSh(#H~6*io4rri#XFN-XI^MtNtObwajpOnl*{VwXqh8XU#@ z?e&%hb+l7ZQOP8_Lu86%(YdT?q=7S|Xbn%VX!r(oFs8qTRCY7QnJJ@ql^qnUYA#Ih zXCHI)@MytAzprGx`6kUuux-T0td51BDcj~Q@gyhH=VaKPoxAqEz#O^pDo@dVpfk<@ z217=I2^iQsoe<$OVUWaqCbX>PhDoCWD||Jax;$BC)2K*{o}tc}R$w@PX1c?B2+7H- zqQb!L-3gJ<9tKT^Iab!g)n*N`a)}KW$-1G7vW~hDWyGMQ*2dy3=rJveDLdtK&+C)5 z%2kw~-v@EFo?O5m3E{Pc&Hq#xN8V3~IArb;%)k(5Jmw`&Hr~`0G>u%hwtRly`qACe zny_rY)+l9HVRY+D&e_Np;iGHEQoK-2(-atJNV~$IcqePg)O#tm#%no;URg1hkt{jJ z?VZWv(3}dbN~qU{o$PHm^`oPMp=~j)cB-to3Xzl4GZ+NJV9AXV1%rB>0f|5u;Pq#! z_Gakk=a=_w9!2fjZ_t2!&DJR1lhdr6>cY*5J_>`&_JuI$s}-d?`Udj4>UaVe3^vZB z>GCsNRiAQ6E+vUjf?**!#K`n~ zc>3|7wa}!0eO*+AtY2Z_yJMfEEN^WloBQ_6IB6B!jsQ=4$@XBYi4{ZV~fFPjKL5P4zf?%kEiXz29LCDw$ zjzcFzX%WFFAVI0pi6BK2lOTo`@@<^ivwP0|wY$$f_x^L=^Pc;=@4e3pegLO{O$YYj z_5lzG06@e807rp6fV7kpTuM?J4u{LgNXyErBIM=du6))U}}lB_>lx6BO@a(C$E7(Xjp93-fHnb3w!}6Ndvop zT~Nq2Ktc%uRf2%+08)HTNyuLU{watA6ecMJmzI&069-T?0TK`>R00N-l!U>=(TU=H z0H!3Vyw%)UO6BMo__ioji{za9(t5kATh)%e=jmIXjZTq~-K?&mxy4{RYR67Pw3Ri+ z#@24n-e2~)?8hB&JAT65!}FwE4=Qhwpwr4xZ{x;V+PP^QdG8&VbHLcnDP^8SQAzb1(*+hsm`3MSGZPr{s zs@wj{%{K*?BC?6!Zd&%GUIV@wJGeazi@!llFP^&_8%rsr$P!&K-sTWL{nG(Ct#c!_ zLL6V^Ws6e3f7OtcUyToL(_J_AVn@DyQuH;K6WH5CQtA>}wxxI)sWBgqFSzfuu-xDs z+LA!wl-&=sBv!<^H2>TfwfLP$s7QSo<2{z(_HMS8x^D1ii6o5>A#6kCUx_s=$~H+( z&KpvNRD*yVjWxF+k6ks00s+RCs`pmS_U-WwTk7+o1lKi}iP7wUaq6`a4GCLVw9yNv z&B9~+f=rR#f}LympBoPtB>T75*;S>Ssz!wq5bY#_)dC2>=rgzG{RDgvc&z-ZRK_b4 zqjfxsQBFy0VYD$9Nxk^l#rua2-S}p$V40;DZKTTpfsZAWV4Y9tlWpsbCoOA2^c!-t zV5wKMwKuu2ypgJPl^lA;mil7Bx|X7S2MFNkMV;y97MQmmY?wbgzNyq`;bF5KY*`(~ zOO9^s;jxeWIk!f}Tumwxh9sTZ%YJWphs(2RWm@jiDaj}c^YFEM&X)v%YfW(LC#E+? ze98DTWtK*70~K{Yp`s*f6#7c;s3kv`KR+Jsgr!$C+>AKpgFIT(k7oT8Iw7pGaBMmq zY5l3H%zL&6=1xxLVrTT8t~_kLtlEpMDK}_2Xq0HiUMu)oUv*dc$ZGI%(z)z={(5Si zgp77O#9*z{lfalKUWDt%Y5t{^Y2$hxCq3(M#MGuS_1AY)ORi@X0+Y3aRwmGsz0|{I zd-|!NoCGa}+^)cozH;hXJ=ZYtk*eXYvFBqJHnR;Kb$DGrLdJf6>8(PY<|PsG3UhJD zO@&gRhb^4imX)OpN9o;iiC^r-ydbMYL~5$EW8x2~yStohXe<=WN-N#D@x_w!;+}%1 zZks;eyTI3&zn#jOci2k&D2+x$cAhBF2?`%JiJ;1%kL>gb)~_qq%biM6OPMQs1zcPU zYUCrmzmaNU{W8==t`0plr%oNLwPjq)%bNPWWYwQw&l{ghOOPp@k6Uy$7^p02o;v&M z*V|*KZz=B6dCG7w;!S&se{b4Dk&jIE{Djk87Xizo2KpDMd)v!k?9Rtc32 z0t!ML@gr9vwBeKRyi08CEO)RIgUPwl5 zY!M-?)!)9MTg(J&zFC%d4gzemOb{4Fj)1_hp8~cH1m>36%erynqs#opulym3Dr64H z%MVAYpt<#7mEy1IPH*I6?~2XAvK188~2p9c|e9y^X#^d8`6 zO;02lhB@sRw3<{5@s%6EQ`X~(@TTRlk2^tNe(hqLY8Qcx!{z4&$XhGOEIk!ettc`? zy5#+QUFu^`(wWZ)%ED09xU*XKt9v`^w=q}8%Aa2~l*qLJ{t(&oJ%n2)w(?DLp3d88 z`;FS282Z4yaNUt+GG}j?c>hDzT&P(Ru~oC8ul2HAUt}F#@zg0oc$-RS^t^kIey*pH zPxJc|`nevVyPM{?k-y6~A7OaCzHxz2$5FEk0P1fi1T4H>wACS(G{98BZ0wf1p#9WsG0TfrKF-|xc z7a22&hP)O=fI#k^3h^VLi}GE3&+rej@L5eRe5Ct8U9lEtv*oJODSB8sCL&#x$CRE? zdQ(XnTsr*2Lf2f&@nQ=Vtmfdw7MiMXJjE8^g=d36x&iN-D4i=T7PqzOe2A}TZSv5{ zmlzTeRS+INwOklH;@a<>>p2yD9V z&AMJh-5HG=Auys^E7}gMcu$S1aOlG$m^{H3oN)!Vw={y+f-y6Vx~H&Du^GvGnxG}V z)MWu&fDs;a8WK$Eaok81!?hPV>n&UjrehhjOBl!tckL7IF)gQrl7o26yN|WLWHt#% z)NZX>w5C}zW*;yCf$GRq?%<;`%9pzB99`W-%!dBQ>h5;d@}uYUB_9?rnF`Xw)TBs@ za5jm3*j}W>Wh;uS*GNIJ>sOlYC)Df;<8g#^J zrt22OHu}gf$lCycE;KY#SSi@Ryv!jsY!@fd9l5fgzK-f((c|>4kh^08=d|n=jryH7 ze~Hh|6lsUr)t8Gq*Mg91;d8C1{_SU*Ux6vei;9%Ky?uYi-f(fRrwu1QA^L?ETtZrQ u`8;X0(SU11N|r(jw->XzbrC2WZQU_TtLYi7mNWJ$+ZgANOGHD!;eP-*!eT7| literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/image.py b/micropython/examples/badger2040w/examples/image.py new file mode 100644 index 00000000..e69de29b diff --git a/micropython/examples/badger2040w/examples/info.py b/micropython/examples/badger2040w/examples/info.py new file mode 100644 index 00000000..e69de29b diff --git a/micropython/examples/badger2040w/examples/list.py b/micropython/examples/badger2040w/examples/list.py new file mode 100644 index 00000000..e69de29b diff --git a/micropython/examples/badger2040w/examples/qrgen.py b/micropython/examples/badger2040w/examples/qrgen.py new file mode 100644 index 00000000..e69de29b diff --git a/micropython/examples/badger2040w/launcher.py b/micropython/examples/badger2040w/launcher.py index ea28ef02..24d95a7c 100644 --- a/micropython/examples/badger2040w/launcher.py +++ b/micropython/examples/badger2040w/launcher.py @@ -1,9 +1,12 @@ import gc +import os import time import math import badger2040w as badger2040 -import launchericons import badger_os +import jpegdec + +APP_DIR = "/examples" # Reduce clock speed to 48MHz badger2040.system_speed(badger2040.SYSTEM_NORMAL) @@ -27,6 +30,8 @@ display = badger2040.Badger2040W() display.set_font("bitmap8") display.led(128) +jpeg = jpegdec.JPEG(display.display) + state = { "page": 0, "font_size": 1, @@ -38,20 +43,7 @@ badger_os.state_load("launcher", state) display.invert(state["inverted"]) -icons = bytearray(launchericons.data()) -icons_width = 576 - -examples = [ - ("_clock", 0), - ("_fonts", 1), - ("_ebook", 2), - ("_image", 3), - ("_list", 4), - ("_badge", 5), - ("_qrgen", 8), - ("_info", 6), - ("_help", 7), -] +examples = [x[:-3] for x in os.listdir("/examples") if x.endswith(".py")] font_sizes = (0.5, 0.7, 0.9) @@ -129,10 +121,12 @@ def render(): for i in range(max_icons): x = centers[i] - label, icon = examples[i + (state["page"] * 3)] - label = label[1:].replace("_", " ") + label = examples[i + (state["page"] * 3)] + icon = f"{APP_DIR}/icon-{label}.jpg" + label = label.replace("_", " ") + jpeg.open_file(icon) + jpeg.decode(x - 32, 24) display.set_pen(0) - display.icon(icons, icon, icons_width, 64, x - 32, 24) w = display.measure_text(label, font_sizes[state["font_size"]]) display.text(label, int(x - (w / 2)), 16 + 80, WIDTH, font_sizes[state["font_size"]]) @@ -166,7 +160,8 @@ def wait_for_user_to_release_buttons(): def launch_example(index): wait_for_user_to_release_buttons() - file = examples[(state["page"] * 3) + index][0] + file = examples[(state["page"] * 3) + index] + file = f"{APP_DIR}/{file}" for k in locals().keys(): if k not in ("gc", "file", "badger_os"): diff --git a/micropython/examples/badger2040w/launchericons.py b/micropython/examples/badger2040w/launchericons.py deleted file mode 100644 index 831e6884..00000000 --- a/micropython/examples/badger2040w/launchericons.py +++ /dev/null @@ -1,297 +0,0 @@ -# Code generated by convert.py. - -_data =\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xf0\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x0f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x01\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xfc\x00\x00\x00'\ -b'\x00\x00\x00\x0f\xfc\x00\x00\x00\x00\x00\x00\x1f\xf8\x00\x00\x00'\ -b'\x03\xff\xf8\x61\x98\x1f\xff\xc0\x00\x00\x0f\xff\xff\xc0\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x7f\xfe\x00\x00\x00\x00\x00\x00\x7f\xff\x80\x00\x00'\ -b'\x00\x00\x00\xff\xff\x00\x00\x00\x03\xff\xf8\x61\x98\x1f\xff\xc0'\ -b'\x00\x00\x3f\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xff\xff\xff\xff\x80\x00'\ -b'\x00\x1f\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x7f\xfe\x00\x00\x00'\ -b'\x00\x00\x03\xff\xff\xf0\x00\x00\x00\x00\x07\xff\xff\xe0\x00\x00'\ -b'\x03\x00\x18\x01\xf9\x98\x00\xc0\x00\x00\x7f\xff\xff\xf8\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x3f\xff\xff\xff\xff\xf0\x00\x00\xff\xff\xff\xff\xff\xfc\x00'\ -b'\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x0f\xff\xff\xfc\x00\x00'\ -b'\x00\x00\x1f\xff\xff\xf8\x00\x00\x03\x00\x18\x01\xf9\x98\x00\xc0'\ -b'\x00\x01\xff\xc0\x0f\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xff\xff\xf8\x00'\ -b'\x01\xff\xff\xff\xff\xff\xfe\x00\x00\x00\x00\xfc\x3f\x00\x00\x00'\ -b'\x00\x00\x1f\xff\xff\xfe\x00\x00\x00\x00\x3f\xff\xff\xfc\x00\x00'\ -b'\x03\x3f\x18\x60\x18\x18\xfc\xc0\x00\x03\xfe\x00\x01\xff\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x7f\xff\xff\xff\xff\xf8\x00\x03\xff\xff\xff\xff\xff\xff\x00'\ -b'\x00\x00\x00\xfc\x3f\x00\x00\x00\x00\x00\x7f\xf0\x03\xff\x80\x00'\ -b'\x00\x00\xff\xe0\x07\xff\x00\x00\x03\x3f\x18\x60\x18\x18\xfc\xc0'\ -b'\x00\x07\xf8\x00\x00\x7f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xff\xff\xf8\x00'\ -b'\x03\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xfc\x3f\x00\x00\x00'\ -b'\x00\x00\xff\x80\x00\x7f\xc0\x00\x00\x01\xff\x00\x00\xff\x80\x00'\ -b'\x03\x3f\x19\x98\x61\x98\xfc\xc0\x00\x0f\xf0\x00\x00\x3f\xc0\x00'\ -b'\x00\x00\x03\xff\xff\xff\xfe\x00\x00\x03\xff\x80\x03\xfe\x00\x00'\ -b'\x00\xff\xff\xff\xff\xff\xfc\x00\x03\xff\xff\xff\xff\xff\xff\x00'\ -b'\x00\x00\x00\xfc\x3f\x00\x00\x00\x00\x01\xfe\x00\x00\x1f\xe0\x00'\ -b'\x00\x03\xfc\x00\x00\x3f\xc0\x00\x03\x3f\x19\x98\x61\x98\xfc\xc0'\ -b'\x00\x0f\xc0\x00\x00\x0f\xc0\x00\x00\x00\x03\xff\xff\xff\xfe\x00'\ -b'\x00\x3f\xff\xf0\x1f\xff\xf0\x00\x00\xfc\x00\x00\x00\x00\xfc\x00'\ -b'\x03\xe0\x00\x00\x00\x00\x1f\x00\x00\x00\x00\xfc\x3f\x00\x00\x00'\ -b'\x00\x03\xfc\x00\x00\x0f\xf0\x00\x00\x07\xf8\x00\x00\x1f\xe0\x00'\ -b'\x03\x3f\x19\x87\xe1\x98\xfc\xc0\x00\x1f\x80\x00\x00\x07\xe0\x00'\ -b'\x00\x00\x03\xff\xff\xff\xfe\x00\x00\xff\xff\xfe\x3f\xff\xfc\x00'\ -b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\ -b'\x00\x00\x00\xfc\x3f\x00\x00\x00\x00\x03\xf0\x00\x60\x03\xf0\x00'\ -b'\x00\x07\xe0\x00\x00\x07\xe0\x00\x03\x3f\x19\x87\xe1\x98\xfc\xc0'\ -b'\x00\x3f\x00\x00\x00\x03\xf0\x00\x00\x00\x03\xff\xff\xff\xfe\x00'\ -b'\x03\xff\xff\xff\xff\xff\xff\x00\x00\xfc\x00\x00\x00\x00\xfc\x00'\ -b'\x03\xe0\x00\x00\x00\x00\x1f\x00\x00\x00\x00\xfc\x3f\x00\x00\x00'\ -b'\x00\x07\xe0\x01\xf8\x01\xf8\x00\x00\x0f\xc0\x00\x00\x03\xf0\x00'\ -b'\x03\x00\x18\x79\x98\x18\x00\xc0\x00\x7e\x00\x07\x00\x01\xf8\x00'\ -b'\x00\x00\x03\xff\xff\xff\xfe\x00\x03\xff\xff\xff\xff\xff\xff\x80'\ -b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\ -b'\x00\x0f\xff\xfc\x3f\xff\xf0\x00\x00\x0f\xc0\x01\xf8\x00\xfc\x00'\ -b'\x00\x1f\x80\x0f\xe0\x01\xf8\x00\x03\x00\x18\x79\x98\x18\x00\xc0'\ -b'\x00\x7e\x00\x07\x00\x01\xf8\x00\x00\x00\x03\xff\xff\xff\xfe\x00'\ -b'\x07\xfe\x00\xff\xff\x03\xff\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ -b'\x03\xe3\xff\xc0\x00\x00\x1f\x00\x00\x7f\xff\xfc\x3f\xff\xfe\x00'\ -b'\x00\x1f\x80\x01\xfc\x00\x7e\x00\x00\x3f\x00\x3f\xf0\x00\xfc\x00'\ -b'\x03\x00\x18\x79\x98\x18\x00\xc0\x00\xfc\x00\x07\x00\x00\xfc\x00'\ -b'\x00\x00\x03\xff\xff\xff\xfe\x00\x07\xe0\x00\x1f\xf0\x00\x1f\x80'\ -b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe7\xff\xc0\x00\x00\x1f\x00'\ -b'\x00\xff\xff\xfc\x3f\xff\xff\x00\x00\x1f\x80\x01\xf8\x00\x7e\x00'\ -b'\x00\x3f\x00\x7f\xf8\x00\xfc\x00\x03\xff\xf9\x99\x99\x9f\xff\xc0'\ -b'\x00\xf8\x00\x07\x00\x00\x7c\x00\x00\x00\x00\x00\x3f\xe0\x00\x00'\ -b'\x07\xe0\x00\x0f\xc0\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ -b'\x03\xe7\xff\xc0\x00\x00\x1f\x00\x01\xff\xff\xfc\x3f\xff\xff\x80'\ -b'\x00\x3f\x00\x01\xf8\x00\x3f\x00\x00\x7e\x00\xff\xfc\x00\x7e\x00'\ -b'\x03\xff\xf9\x99\x99\x9f\xff\xc0\x00\xf8\x00\x07\x00\x00\x7c\x00'\ -b'\x00\x00\x00\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ -b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe7\xff\xc0\x00\x00\x1f\x00'\ -b'\x01\xff\xff\xfc\x3f\xff\xff\x80\x00\x3e\x00\x00\xf0\x00\x1f\x00'\ -b'\x00\x7c\x01\xfc\xfe\x00\x3e\x00\x00\x00\x00\x61\x9f\x80\x00\x00'\ -b'\x01\xf0\x00\x07\x00\x00\x3e\x00\x00\x00\x00\x00\x1f\xe0\x00\x00'\ -b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ -b'\x03\xe7\xff\xc0\x00\x00\x1f\x00\x01\xf0\x00\xff\xff\x00\x0f\x80'\ -b'\x00\x3e\x00\x00\x00\x00\x1f\x00\x00\x7c\x03\xf0\x3f\x00\x3e\x00'\ -b'\x00\x00\x00\x61\x9f\x80\x00\x00\x01\xf0\x00\x07\x00\x00\x3e\x00'\ -b'\x00\x00\x00\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ -b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\ -b'\x01\xf0\x00\x7f\xfe\x00\x0f\x80\x00\x7c\x00\x00\x00\x00\x0f\x80'\ -b'\x00\xf8\x03\xe0\x1f\x00\x1f\x00\x03\xc0\xfe\x78\x60\x00\xf0\x00'\ -b'\x01\xf0\x00\x07\x00\x00\x3e\x00\x00\x00\x00\x00\x1f\xe0\x00\x00'\ -b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ -b'\x03\xe0\x00\x00\x00\x06\x1f\x00\x01\xf0\x00\x7f\xfe\x00\x0f\x80'\ -b'\x00\x7c\x00\x3f\x80\x00\x0f\x80\x00\xf8\x03\xc0\x0f\x00\x1f\x00'\ -b'\x03\xc0\xfe\x78\x60\x00\xf0\x00\x01\xe0\x00\x07\x00\x00\x1e\x00'\ -b'\x00\xff\xff\xfc\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ -b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x0f\x1f\x00'\ -b'\x01\xf0\x00\x3f\xfc\x00\x0f\x80\x00\x7c\x00\x7f\xe0\x00\x0f\x80'\ -b'\x00\xf8\x03\xc0\x0f\x80\x1f\x00\x03\xff\x00\x1f\xff\x87\xff\x00'\ -b'\x03\xe0\x00\x07\x00\x00\x1f\x00\x01\xff\xff\xfc\x1f\xe0\x00\x00'\ -b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ -b'\x03\xe0\x00\x00\x00\x1f\x9f\x00\x01\xf0\x00\x1f\xf8\x00\x0f\x80'\ -b'\x00\x78\x00\xff\xf0\x00\x07\x80\x00\xf0\x03\xc0\x0f\x80\x0f\x00'\ -b'\x03\xff\x00\x1f\xff\x87\xff\x00\x03\xe0\x00\x07\x00\x00\x1f\x00'\ -b'\x01\xff\xff\xfc\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ -b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x3f\x9f\x00'\ -b'\x01\xf0\x00\x07\xe0\x00\x0f\x80\x00\xf8\x00\x7f\xf0\x00\x07\xc0'\ -b'\x01\xf0\x03\xc0\x0f\x80\x0f\x80\x03\xcf\xf8\x61\xff\xe7\x33\xc0'\ -b'\x03\xe0\x00\x07\x00\x00\x1f\x00\x01\xff\xff\xfc\x1f\xe0\x00\x00'\ -b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ -b'\x03\xe0\x00\x00\x20\x7f\x1f\x00\x01\xf0\x00\x00\x00\x00\x0f\x80'\ -b'\x00\xf8\x00\x7f\xf0\x00\x07\xc0\x01\xf0\x00\x00\x1f\x00\x0f\x80'\ -b'\x03\xcf\xf8\x61\xff\xe7\x33\xc0\x03\xe0\x00\x07\x00\x00\x1f\x00'\ -b'\x01\xff\xff\xfc\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ -b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe7\xff\xc0\x70\xfe\x1f\x00'\ -b'\x01\xf0\x00\x00\x00\x00\x0f\x80\x00\xf8\x00\x07\xf0\x00\x07\xc0'\ -b'\x01\xf0\x00\x00\x7f\x00\x0f\x80\x00\x33\xe1\x9f\x98\x78\xf0\xc0'\ -b'\x03\xe0\x00\x07\x00\x00\x1f\x00\x01\xff\xff\xfc\x1f\xe0\x00\x00'\ -b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ -b'\x03\xe7\xff\xc0\xf9\xfc\x1f\x00\x01\xf0\x01\xc0\x07\xfe\x0f\x80'\ -b'\x00\xf8\x00\x07\xf0\x00\x07\xc0\x01\xf0\x00\x00\xfe\x00\x0f\x80'\ -b'\x00\x33\xe1\x9f\x98\x78\xf0\xc0\x03\xe0\x00\x07\xc0\x00\x1f\x00'\ -b'\x01\xff\xff\xfc\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ -b'\x00\xfc\x00\x00\x08\x00\xfc\x00\x03\xe7\xff\xc1\xff\xf8\x1f\x00'\ -b'\x01\xf0\x03\xe0\x07\xfe\x0f\x80\x00\xf8\x00\x07\xf0\x00\x07\xc0'\ -b'\x01\xf0\x00\x03\xfe\x00\x0f\x80\x03\x00\x19\xfe\x01\x9f\x00\xc0'\ -b'\x03\xe0\x00\x07\xe0\x00\x1f\x00\x01\xff\xff\xfc\x1f\xe0\x00\x00'\ -b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x1c\x00\xfc\x00'\ -b'\x03\xe7\xff\xc0\xff\xf0\x1f\x00\x01\xf0\x07\xf0\x07\xfe\x0f\x80'\ -b'\x00\xf8\x00\x0f\xe0\x00\x07\xc0\x01\xf0\x00\x03\xf8\x00\x0f\x80'\ -b'\x03\x00\x19\xfe\x01\x9f\x00\xc0\x03\xe0\x00\x03\xf8\x00\x1f\x00'\ -b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ -b'\x00\xfc\x00\x00\x3e\x00\xfc\x00\x03\xe0\x00\x00\x7f\xe0\x1f\x00'\ -b'\x01\xf0\x07\xf0\x07\xfe\x0f\x80\x00\xf8\x00\x0f\xe0\x00\x07\xc0'\ -b'\x01\xf0\x00\x07\xf0\x00\x0f\x80\x03\xcc\x07\x9f\x87\x87\x03\x00'\ -b'\x01\xe0\x00\x00\xfe\x00\x1e\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ -b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x01\x00\x7e\x00\xfc\x00'\ -b'\x03\xe0\x00\x00\x3f\xc0\x1f\x00\x01\xf0\x07\xf0\x00\x00\x0f\x80'\ -b'\x00\xf8\x00\x0f\xe0\x00\x07\xc0\x01\xf0\x00\x07\xc0\x00\x0f\x80'\ -b'\x03\xcc\x07\x9f\x87\x87\x03\x00\x01\xf0\x00\x00\x3f\x00\x3e\x00'\ -b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ -b'\x00\xfc\x03\x80\x7f\x00\xfc\x00\x03\xe0\x00\x00\x1f\x80\x1f\x00'\ -b'\x01\xf0\x07\xf0\x00\x00\x0f\x80\x00\x78\x00\x0f\xe0\x00\x07\x80'\ -b'\x00\xf0\x00\x0f\x80\x00\x0f\x00\x03\x3c\xfe\x19\xe6\x60\x33\xc0'\ -b'\x01\xf0\x00\x00\x1f\xc0\x3e\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ -b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x07\xc0\xff\x80\xfc\x00'\ -b'\x03\xe0\x00\x00\x0f\x00\x1f\x00\x01\xf0\x03\xe0\x00\x00\x0f\x80'\ -b'\x00\x7c\x00\x0f\xe0\x00\x0f\x80\x00\xf8\x00\x0f\x80\x00\x1f\x00'\ -b'\x03\x3c\xfe\x19\xe6\x60\x33\xc0\x01\xf0\x00\x00\x07\xe0\x3e\x00'\ -b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ -b'\x00\xfc\x07\xe1\xff\xc0\xfc\x00\x03\xe0\x00\x00\x06\x00\x1f\x00'\ -b'\x01\xf0\x00\x00\x07\xfe\x0f\x80\x00\x7c\x00\x1f\xe0\x00\x0f\x80'\ -b'\x00\xf8\x00\x0f\x80\x00\x1f\x00\x03\x0f\xe1\x87\x9e\x60\xcc\xc0'\ -b'\x00\xf8\x00\x00\x01\xe0\x7c\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ -b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x0f\xe3\xff\xc0\xfc\x00'\ -b'\x03\xe3\xff\xc0\x00\x00\x1f\x00\x01\xf0\x00\x00\x07\xfe\x0f\x80'\ -b'\x00\x7c\x00\x1f\xc0\x00\x0f\x80\x00\xf8\x00\x07\x00\x00\x1f\x00'\ -b'\x03\x0f\xe1\x87\x9e\x60\xcc\xc0\x00\xf8\x00\x00\x00\xc0\x7c\x00'\ -b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ -b'\x00\xfc\x1f\xf7\xff\xe0\xfc\x00\x03\xe7\xff\xc0\x00\x00\x1f\x00'\ -b'\x01\xf0\x01\xc0\x07\xfe\x0f\x80\x00\x3e\x00\x1f\xc0\x00\x1f\x00'\ -b'\x00\x7c\x00\x00\x00\x00\x3e\x00\x03\x3c\xfe\x00\x79\xff\xcc\x00'\ -b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ -b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x3f\xff\xff\xf0\xfc\x00'\ -b'\x03\xe7\xff\xc0\x00\x00\x1f\x00\x01\xf0\x1f\xfc\x07\xfe\x0f\x80'\ -b'\x00\x3e\x00\x1f\xc0\x00\x1f\x00\x00\x7c\x00\x00\x00\x00\x3e\x00'\ -b'\x03\x3c\xfe\x00\x79\xff\xcc\x00\x00\x7e\x00\x00\x00\x01\xf8\x00'\ -b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\ -b'\x00\xfc\x7f\xff\xff\xf8\xfc\x00\x03\xe7\xff\xc0\x00\x00\x1f\x00'\ -b'\x01\xf0\x3f\xfe\x00\x00\x0f\x80\x00\x3f\x00\x1f\xc0\x00\x3f\x00'\ -b'\x00\x7e\x00\x02\x00\x00\x7e\x00\x00\x00\x01\xfe\x01\x80\xcc\x00'\ -b'\x00\x7e\x00\x00\x00\x01\xf8\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ -b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x7f\xff\xff\xf8\xfc\x00'\ -b'\x03\xe7\xff\xc0\x00\x00\x1f\x00\x01\xf0\x7f\xff\x00\x00\x0f\x80'\ -b'\x00\x1f\x80\x1f\xc7\x00\x7e\x00\x00\x3f\x00\x0f\x80\x00\xfc\x00'\ -b'\x00\x00\x01\xfe\x01\x80\xcc\x00\x00\x3f\x00\x00\x00\x03\xf0\x00'\ -b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe3\xff\x0f\x80\x00\x1f\x80'\ -b'\x00\xfc\xff\xff\xff\xfc\xfc\x00\x03\xe3\xff\xc0\x00\x00\x1f\x00'\ -b'\x01\xf0\x7f\xff\x00\x00\x0f\x80\x00\x1f\x80\x1f\xcf\x00\x7e\x00'\ -b'\x00\x3f\x00\x0f\x80\x00\xfc\x00\x03\xff\xf9\xfe\x79\x98\xf0\xc0'\ -b'\x00\x1f\x80\x00\x00\x07\xe0\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ -b'\x07\xff\xff\xff\x83\xff\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ -b'\x03\xe0\x00\x00\x00\x00\x1f\x00\x01\xf0\x7f\xff\x00\x00\x0f\x80'\ -b'\x00\x0f\xc0\x0f\xff\x00\xfc\x00\x00\x1f\x80\x0f\x80\x01\xf8\x00'\ -b'\x03\xff\xf9\xfe\x79\x98\xf0\xc0\x00\x0f\xc0\x00\x00\x0f\xc0\x00'\ -b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xff\xff\xff\x8f\xff\xff\x80'\ -b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\ -b'\x01\xf0\x00\x00\x00\x00\x0f\x80\x00\x07\xe0\x07\xff\x01\xf8\x00'\ -b'\x00\x0f\xc0\x0f\x80\x03\xf0\x00\x03\x00\x19\x80\x1f\x80\xc0\x00'\ -b'\x00\x0f\xf0\x00\x00\x3f\xc0\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ -b'\x07\xff\xff\xff\xbf\xff\xff\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\ -b'\x03\xe0\x00\x00\x00\x00\x1f\x00\x01\xf0\x00\x00\x00\x00\x0f\x80'\ -b'\x00\x03\xf0\x03\xfc\x03\xf0\x00\x00\x07\xe0\x07\x00\x07\xe0\x00'\ -b'\x03\x00\x19\x80\x1f\x80\xc0\x00\x00\x07\xf8\x00\x00\x7f\x80\x00'\ -b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xff\xff\xff\xff\xff\xff\x80'\ -b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\ -b'\x01\xf0\x00\x00\x00\x00\x0f\x80\x00\x03\xfc\x00\x70\x0f\xf0\x00'\ -b'\x00\x07\xf8\x00\x00\x1f\xe0\x00\x03\x00\x19\x80\x1f\x80\xc0\x00'\ -b'\x00\x03\xfe\x00\x01\xff\x00\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\ -b'\x07\xfe\x01\xff\xff\xff\xff\x80\x00\xff\xff\xff\xff\xff\xfc\x00'\ -b'\x03\xff\xff\xff\xff\xff\xff\x00\x01\xf0\x00\x00\x00\x00\x0f\x80'\ -b'\x00\x01\xfe\x00\x00\x1f\xe0\x00\x00\x03\xfc\x00\x00\x3f\xc0\x00'\ -b'\x03\x3f\x18\x01\xff\xff\xff\x00\x00\x01\xff\xc0\x0f\xfe\x00\x00'\ -b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x03\xf0\x00\x1f\xfe\x01\xff\x80'\ -b'\x00\x7f\xff\xff\xff\xff\xf8\x00\x03\xff\xff\xff\xff\xff\xff\x00'\ -b'\x01\xf0\x00\x00\x00\x00\x0f\x80\x00\x00\xff\x80\x00\x7f\xc0\x00'\ -b'\x00\x01\xff\x00\x00\xff\x80\x00\x03\x3f\x18\x01\xff\xff\xff\x00'\ -b'\x00\x00\x7f\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x01\x80\x00\x07\xf8\x00\x3f\x00\x00\x7f\xff\xff\xff\xff\xf8\x00'\ -b'\x03\xff\xff\xff\xff\xff\xff\x00\x01\xff\xff\xff\xff\xff\xff\x80'\ -b'\x00\x00\x7f\xf0\x03\xff\x80\x00\x00\x00\xff\xe0\x07\xff\x00\x00'\ -b'\x03\x3f\x18\x66\x1e\x7f\x33\xc0\x00\x00\x3f\xff\xff\xf0\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xe0\x00\x06\x00'\ -b'\x00\x7f\xff\xff\xff\xff\xf8\x00\x01\xff\xff\xff\xff\xff\xfe\x00'\ -b'\x01\xff\xff\xff\xff\xff\xff\x80\x00\x00\x1f\xff\xff\xfe\x00\x00'\ -b'\x00\x00\x3f\xff\xff\xfc\x00\x00\x03\x3f\x18\x66\x1e\x7f\x33\xc0'\ -b'\x00\x00\x0f\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x3f\xff\xff\xff\xff\xf0\x00'\ -b'\x00\xff\xff\xff\xff\xff\xfc\x00\x00\xff\xff\xff\xff\xff\xff\x00'\ -b'\x00\x00\x0f\xff\xff\xfc\x00\x00\x00\x00\x1f\xff\xff\xf8\x00\x00'\ -b'\x03\x3f\x18\x18\x19\xe7\x0c\xc0\x00\x00\x01\xff\xfe\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x7f\xff\xff\xff\xff\xfe\x00\x00\x00\x03\xff\xff\xf0\x00\x00'\ -b'\x00\x00\x07\xff\xff\xe0\x00\x00\x03\x3f\x18\x18\x19\xe7\x0c\xc0'\ -b'\x00\x00\x00\x3f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xff\xff\xff\xff\xfc\x00'\ -b'\x00\x00\x00\x7f\xff\x80\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00'\ -b'\x03\x00\x19\xe6\x01\x9f\xc0\xc0\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xfc\x00\x00\x00'\ -b'\x00\x00\x00\x1f\xf8\x00\x00\x00\x03\x00\x19\xe6\x01\x9f\xc0\xc0'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x03\xff\xf9\xe7\x81\xe0\x30\xc0\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x03\xff\xf9\xe7\x81\xe0\x30\xc0'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ - -_mvdata = memoryview(_data) - -def data(): - return _mvdata - diff --git a/micropython/examples/badger2040w/lib/badger_os.py b/micropython/examples/badger2040w/lib/badger_os.py index 7effe1cb..97c20e03 100644 --- a/micropython/examples/badger2040w/lib/badger_os.py +++ b/micropython/examples/badger2040w/lib/badger_os.py @@ -67,7 +67,7 @@ def state_set_running(app): def state_launch(): app = state_running() if app is not None and app != "launcher": - launch("_" + app) + launch(app) def state_delete(app): @@ -127,10 +127,7 @@ def launch(file): button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher) try: - try: - __import__(file[1:]) # Try to import _[file] (drop underscore prefix) - except ImportError: - __import__(file) # Failover to importing [_file] + __import__(file) except ImportError: # If the app doesn't exist, notify the user diff --git a/micropython/examples/badger2040w/main.py b/micropython/examples/badger2040w/main.py deleted file mode 100644 index 39fcdade..00000000 --- a/micropython/examples/badger2040w/main.py +++ /dev/null @@ -1,10 +0,0 @@ -import WIFI_CONFIG - -if WIFI_CONFIG.SSID == "": - import badger2040w - badger2040w.init() - badger2040w.screen.set_pen(15) - badger2040w.screen.clear() - badger2040w.screen.set_pen(0) - badger2040w.screen.text("Please configure your WiFi in WIFI_CONFIG.py") - badger2040w.screen.update() diff --git a/micropython/examples/badger2040w/uf2-manifest.txt b/micropython/examples/badger2040w/uf2-manifest.txt index 02acc631..8fc02b69 100644 --- a/micropython/examples/badger2040w/uf2-manifest.txt +++ b/micropython/examples/badger2040w/uf2-manifest.txt @@ -1,3 +1,5 @@ *.py lib/*.py -lib/urllib/*.py \ No newline at end of file +lib/urllib/*.py +examples/*.jpg +examples/*.py From 2b3b1e4676f9364b96c03a54edb599226192fd30 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 16 Jan 2023 11:06:54 +0000 Subject: [PATCH 09/46] Badger2040W: Fix (blank line in) .uf2 manifest. --- micropython/examples/badger2040w/uf2-manifest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/examples/badger2040w/uf2-manifest.txt b/micropython/examples/badger2040w/uf2-manifest.txt index 8fc02b69..7f9adde8 100644 --- a/micropython/examples/badger2040w/uf2-manifest.txt +++ b/micropython/examples/badger2040w/uf2-manifest.txt @@ -2,4 +2,4 @@ lib/*.py lib/urllib/*.py examples/*.jpg -examples/*.py +examples/*.py \ No newline at end of file From e859b39e11c8ce4afad1b1c2a616a56bea1596a4 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 16 Jan 2023 11:23:45 +0000 Subject: [PATCH 10/46] Badger2040W: Fix linting, use micropython-lib urllib. --- .../PIMORONI_BADGER2040W/manifest.py | 7 ++ .../examples/badger2040w/lib/badger2040w.py | 10 +-- .../examples/badger2040w/lib/badger_os.py | 2 +- .../badger2040w/lib/urllib/urequest.py | 67 ------------------- .../examples/badger2040w/uf2-manifest.txt | 1 - 5 files changed, 13 insertions(+), 74 deletions(-) create mode 100644 micropython/_board/badger2040w/PIMORONI_BADGER2040W/manifest.py delete mode 100644 micropython/examples/badger2040w/lib/urllib/urequest.py diff --git a/micropython/_board/badger2040w/PIMORONI_BADGER2040W/manifest.py b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/manifest.py new file mode 100644 index 00000000..b446b0a0 --- /dev/null +++ b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/manifest.py @@ -0,0 +1,7 @@ +include("../manifest.py") + +require("mip") +require("ntptime") +require("urequests") +require("urllib.urequest") +require("umqtt.simple") \ No newline at end of file diff --git a/micropython/examples/badger2040w/lib/badger2040w.py b/micropython/examples/badger2040w/lib/badger2040w.py index e19d995c..aab47f6b 100644 --- a/micropython/examples/badger2040w/lib/badger2040w.py +++ b/micropython/examples/badger2040w/lib/badger2040w.py @@ -1,4 +1,5 @@ import machine +import micropython from picographics import PicoGraphics, DISPLAY_INKY_PACK from network_manager import NetworkManager import WIFI_CONFIG @@ -86,10 +87,10 @@ class Badger2040W(): def thickness(self, thickness): print("Thickness!") - + def halt(self): pass - + def pressed(self, button): return BUTTONS[button].value() == 1 @@ -97,14 +98,14 @@ class Badger2040W(): def icon(self, data, index, data_w, icon_size, x, y): s_x = (index * icon_size) % data_w s_y = int((index * icon_size) / data_w) - + for o_y in range(icon_size): for o_x in range(icon_size): o = ((o_y + s_y) * data_w) + (o_x + s_x) bm = 0b10000000 >> (o & 0b111) if data[o >> 3] & bm: self.display.pixel(x + o_x, y + o_y) - + def image(self, data, w, h, x, y): for oy in range(h): row = data[oy] @@ -112,7 +113,6 @@ class Badger2040W(): if row & 0b1 == 0: self.display.pixel(x + ox, y + oy) row >>= 1 - def status_handler(self, mode, status, ip): print(mode, status, ip) diff --git a/micropython/examples/badger2040w/lib/badger_os.py b/micropython/examples/badger2040w/lib/badger_os.py index 97c20e03..a8bcb19a 100644 --- a/micropython/examples/badger2040w/lib/badger_os.py +++ b/micropython/examples/badger2040w/lib/badger_os.py @@ -127,7 +127,7 @@ def launch(file): button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher) try: - __import__(file) + __import__(file) except ImportError: # If the app doesn't exist, notify the user diff --git a/micropython/examples/badger2040w/lib/urllib/urequest.py b/micropython/examples/badger2040w/lib/urllib/urequest.py deleted file mode 100644 index 4c654d45..00000000 --- a/micropython/examples/badger2040w/lib/urllib/urequest.py +++ /dev/null @@ -1,67 +0,0 @@ -import usocket - - -def urlopen(url, data=None, method="GET"): - if data is not None and method == "GET": - method = "POST" - try: - proto, dummy, host, path = url.split("/", 3) - except ValueError: - proto, dummy, host = url.split("/", 2) - path = "" - if proto == "http:": - port = 80 - elif proto == "https:": - import ussl - - port = 443 - else: - raise ValueError("Unsupported protocol: " + proto) - - if ":" in host: - host, port = host.split(":", 1) - port = int(port) - - ai = usocket.getaddrinfo(host, port, 0, usocket.SOCK_STREAM) - ai = ai[0] - - s = usocket.socket(ai[0], ai[1], ai[2]) - try: - s.connect(ai[-1]) - if proto == "https:": - s = ussl.wrap_socket(s, server_hostname=host) - - s.write(method) - s.write(b" /") - s.write(path) - s.write(b" HTTP/1.0\r\nHost: ") - s.write(host) - s.write(b"\r\n") - - if data: - s.write(b"Content-Length: ") - s.write(str(len(data))) - s.write(b"\r\n") - s.write(b"\r\n") - if data: - s.write(data) - - l = s.readline() - l = l.split(None, 2) - # print(l) - status = int(l[1]) - while True: - l = s.readline() - if not l or l == b"\r\n": - break - # print(l) - if l.startswith(b"Transfer-Encoding:"): - if b"chunked" in l: - raise ValueError("Unsupported " + l) - elif l.startswith(b"Location:"): - raise NotImplementedError("Redirects not yet supported") - except OSError: - s.close() - raise - - return s diff --git a/micropython/examples/badger2040w/uf2-manifest.txt b/micropython/examples/badger2040w/uf2-manifest.txt index 7f9adde8..a0ebfcfb 100644 --- a/micropython/examples/badger2040w/uf2-manifest.txt +++ b/micropython/examples/badger2040w/uf2-manifest.txt @@ -1,5 +1,4 @@ *.py lib/*.py -lib/urllib/*.py examples/*.jpg examples/*.py \ No newline at end of file From d1646e5d769d5e0c9ff0db62cbca9bb16788369b Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 16 Jan 2023 11:31:27 +0000 Subject: [PATCH 11/46] CI: Badger2040W: Fix deprecation warnings. --- .github/workflows/micropython-badger2040w.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/micropython-badger2040w.yml b/.github/workflows/micropython-badger2040w.yml index 52ef1c9e..bf57db08 100644 --- a/.github/workflows/micropython-badger2040w.yml +++ b/.github/workflows/micropython-badger2040w.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Workspace Cache id: cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{runner.workspace}} key: workspace-micropython-${{env.MICROPYTHON_VERSION}} @@ -29,7 +29,7 @@ jobs: # Check out MicroPython - name: Checkout MicroPython if: steps.cache.outputs.cache-hit != 'true' - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: micropython/micropython ref: ${{env.MICROPYTHON_VERSION}} @@ -61,7 +61,7 @@ jobs: steps: - name: Compiler Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: /home/runner/.ccache key: ccache-micropython-badger2040w-${{github.ref}}-${{github.sha}} @@ -70,20 +70,20 @@ jobs: ccache-micropython-badger2040w- - name: Workspace Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{runner.workspace}} key: workspace-micropython-${{env.MICROPYTHON_VERSION}} restore-keys: | workspace-micropython-${{env.MICROPYTHON_VERSION}} - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: true path: pimoroni-pico-${{ github.sha }} # Check out dir2u2f - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: repository: gadgetoid/dir2uf2 ref: v0.0.1 @@ -130,13 +130,13 @@ jobs: ./dir2uf2/dir2uf2 --append-to micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 --manifest pimoroni-pico-${{ github.sha }}/micropython/examples/badger2040w/uf2-manifest.txt --filename with-examples.uf2 pimoroni-pico-${{ github.sha }}/micropython/examples/badger2040w/ - name: Store .uf2 as artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ${{env.RELEASE_FILE}}.uf2 path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 - name: Store .uf2 + examples as artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ${{env.RELEASE_FILE}}-with-examples.uf2 path: ${{env.RELEASE_FILE}}-with-examples.uf2 From 03d5224e3e2476491b2d3a407e128788ad5db1fa Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 16 Jan 2023 11:41:07 +0000 Subject: [PATCH 12/46] Badger2040W: Use correct MicroPython manifest.py. --- .../_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.cmake b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.cmake index c16e3204..d0b32b91 100644 --- a/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.cmake +++ b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.cmake @@ -5,4 +5,4 @@ set(MICROPY_PY_LWIP ON) set(MICROPY_PY_NETWORK_CYW43 ON) # Board specific version of the frozen manifest -set(MICROPY_FROZEN_MANIFEST ${CMAKE_SOURCE_DIR}/boards/PICO_W/manifest.py) \ No newline at end of file +set(MICROPY_FROZEN_MANIFEST ${CMAKE_SOURCE_DIR}/boards/PIMORONI_BADGER2040W/manifest.py) \ No newline at end of file From 1dbc9921809722ab18f1ddeaf768d5842d81193c Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 16 Jan 2023 14:27:16 +0000 Subject: [PATCH 13/46] Badger2040W: Fixes to launcher and badger libs. --- micropython/examples/badger2040w/launcher.py | 2 +- micropython/examples/badger2040w/lib/badger_os.py | 4 ++-- micropython/examples/badger2040w/lib/network_manager.py | 1 + micropython/examples/badger2040w/main.py | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 micropython/examples/badger2040w/main.py diff --git a/micropython/examples/badger2040w/launcher.py b/micropython/examples/badger2040w/launcher.py index 24d95a7c..438536ff 100644 --- a/micropython/examples/badger2040w/launcher.py +++ b/micropython/examples/badger2040w/launcher.py @@ -9,7 +9,7 @@ import jpegdec APP_DIR = "/examples" # Reduce clock speed to 48MHz -badger2040.system_speed(badger2040.SYSTEM_NORMAL) +badger2040.system_speed(badger2040.SYSTEM_TURBO) changed = False exited_to_launcher = False diff --git a/micropython/examples/badger2040w/lib/badger_os.py b/micropython/examples/badger2040w/lib/badger_os.py index a8bcb19a..98a14fa3 100644 --- a/micropython/examples/badger2040w/lib/badger_os.py +++ b/micropython/examples/badger2040w/lib/badger_os.py @@ -112,7 +112,7 @@ def state_load(app, defaults): def launch(file): - state_set_running(file[1:]) + state_set_running(file) gc.collect() @@ -131,7 +131,7 @@ def launch(file): except ImportError: # If the app doesn't exist, notify the user - warning(None, "Could not launch: " + file[1:]) + warning(None, f"Could not launch: {file}") time.sleep(4.0) except Exception as e: # If the app throws an error, catch it and display! diff --git a/micropython/examples/badger2040w/lib/network_manager.py b/micropython/examples/badger2040w/lib/network_manager.py index d4d59230..78b53f56 100644 --- a/micropython/examples/badger2040w/lib/network_manager.py +++ b/micropython/examples/badger2040w/lib/network_manager.py @@ -75,6 +75,7 @@ class NetworkManager: self._sta_if.active(True) self._sta_if.connect(ssid, psk) + self._sta_if.config(pm=0xa11140) try: await uasyncio.wait_for(self.wait(network.STA_IF), self._client_timeout) diff --git a/micropython/examples/badger2040w/main.py b/micropython/examples/badger2040w/main.py new file mode 100644 index 00000000..967457fd --- /dev/null +++ b/micropython/examples/badger2040w/main.py @@ -0,0 +1 @@ +import launcher # noqa F401 From f82e21018f36956934f20508fbefa021a961d4cd Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 17 Jan 2023 11:11:44 +0000 Subject: [PATCH 14/46] Badger2040W: Remove font sizes from launcher.py. --- micropython/examples/badger2040w/launcher.py | 25 +++++--------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/micropython/examples/badger2040w/launcher.py b/micropython/examples/badger2040w/launcher.py index 438536ff..cf55e707 100644 --- a/micropython/examples/badger2040w/launcher.py +++ b/micropython/examples/badger2040w/launcher.py @@ -7,6 +7,7 @@ import badger_os import jpegdec APP_DIR = "/examples" +FONT_SIZE = 2 # Reduce clock speed to 48MHz badger2040.system_speed(badger2040.SYSTEM_TURBO) @@ -34,19 +35,13 @@ jpeg = jpegdec.JPEG(display.display) state = { "page": 0, - "font_size": 1, - "inverted": False, "running": "launcher" } badger_os.state_load("launcher", state) -display.invert(state["inverted"]) - examples = [x[:-3] for x in os.listdir("/examples") if x.endswith(".py")] -font_sizes = (0.5, 0.7, 0.9) - # Approximate center lines for buttons A, B and C centers = (41, 147, 253) @@ -127,8 +122,8 @@ def render(): jpeg.open_file(icon) jpeg.decode(x - 32, 24) display.set_pen(0) - w = display.measure_text(label, font_sizes[state["font_size"]]) - display.text(label, int(x - (w / 2)), 16 + 80, WIDTH, font_sizes[state["font_size"]]) + w = display.measure_text(label, FONT_SIZE) + display.text(label, int(x - (w / 2)), 16 + 80, WIDTH, FONT_SIZE) for i in range(MAX_PAGE): x = 286 @@ -193,19 +188,11 @@ def button(pin): render() else: # User button IS held down if pin == badger2040.BUTTON_UP: - state["font_size"] += 1 - if state["font_size"] == len(font_sizes): - state["font_size"] = 0 - render() + pass if pin == badger2040.BUTTON_DOWN: - state["font_size"] -= 1 - if state["font_size"] < 0: - state["font_size"] = 0 - render() + pass if pin == badger2040.BUTTON_A: - state["inverted"] = not state["inverted"] - display.invert(state["inverted"]) - render() + pass if exited_to_launcher or not woken_by_button: From a02834be9e70e07111107514324dde2e0555a1f6 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 17 Jan 2023 12:43:45 +0000 Subject: [PATCH 15/46] Badger2040: Port more examples. --- .../examples/badger2040w/examples/clock.py | 12 +- .../examples/badger2040w/examples/fonts.py | 129 ++++++++ .../examples/badger2040w/examples/help.py | 40 +++ .../examples/badger2040w/examples/image.py | 119 +++++++ .../examples/badger2040w/examples/info.py | 45 +++ .../examples/badger2040w/examples/list.py | 311 ++++++++++++++++++ .../examples/badger2040w/examples/qrgen.py | 138 ++++++++ .../examples/badger2040w/images/README.txt | 3 + .../badger2040w/images/badgerpunk.jpg | Bin 0 -> 9264 bytes .../examples/badger2040w/uf2-manifest.txt | 4 +- 10 files changed, 795 insertions(+), 6 deletions(-) create mode 100644 micropython/examples/badger2040w/images/README.txt create mode 100644 micropython/examples/badger2040w/images/badgerpunk.jpg diff --git a/micropython/examples/badger2040w/examples/clock.py b/micropython/examples/badger2040w/examples/clock.py index 7d52e4c6..48297997 100644 --- a/micropython/examples/badger2040w/examples/clock.py +++ b/micropython/examples/badger2040w/examples/clock.py @@ -5,15 +5,17 @@ import badger2040w display = badger2040w.Badger2040W() +display.set_update_speed(3) WIDTH, HEIGHT = display.get_bounds() -display.connect() +try: + display.connect() + if display.isconnected(): + ntptime.settime() +except RuntimeError: + pass # no WiFI -# We're going to keep the badger on, so slow down the system clock if on battery -display.set_update_speed(3) - -ntptime.settime() rtc = machine.RTC() display.set_font("gothic") diff --git a/micropython/examples/badger2040w/examples/fonts.py b/micropython/examples/badger2040w/examples/fonts.py index e69de29b..30699ad8 100644 --- a/micropython/examples/badger2040w/examples/fonts.py +++ b/micropython/examples/badger2040w/examples/fonts.py @@ -0,0 +1,129 @@ +import badger2040w +import badger_os + +# Global Constants +FONT_NAMES = ( + ("sans", 0.7, 2), + ("gothic", 0.7, 2), + ("cursive", 0.7, 2), + ("serif", 0.7, 2), + ("serif_italic", 0.7, 2), + ("bitmap6", 3, 1), + ("bitmap8", 2, 1), + ("bitmap14_outline", 1, 1) +) + +WIDTH = badger2040w.WIDTH +HEIGHT = badger2040w.HEIGHT + +MENU_TEXT_SIZE = 0.5 +MENU_SPACING = 16 +MENU_WIDTH = 84 +MENU_PADDING = 5 + +TEXT_INDENT = MENU_WIDTH + 10 + +ARROW_THICKNESS = 3 +ARROW_WIDTH = 18 +ARROW_HEIGHT = 14 +ARROW_PADDING = 2 + + +# ------------------------------ +# Drawing functions +# ------------------------------ + +# Draw a upward arrow +def draw_up(x, y, width, height, thickness, padding): + border = (thickness // 4) + padding + display.line(x + border, y + height - border, + x + (width // 2), y + border) + display.line(x + (width // 2), y + border, + x + width - border, y + height - border) + + +# Draw a downward arrow +def draw_down(x, y, width, height, thickness, padding): + border = (thickness // 2) + padding + display.line(x + border, y + border, + x + (width // 2), y + height - border) + display.line(x + (width // 2), y + height - border, + x + width - border, y + border) + + +# Draw the frame of the reader +def draw_frame(): + display.set_pen(15) + display.clear() + display.set_pen(12) + display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT) + display.set_pen(0) + draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2), + ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) + draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2), + ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) + + +# Draw the fonts and menu +def draw_fonts(): + display.set_font("bitmap8") + for i in range(len(FONT_NAMES)): + name, size, thickness = FONT_NAMES[i] + display.set_pen(0) + if i == state["selected_font"]: + display.rectangle(0, i * MENU_SPACING, MENU_WIDTH, MENU_SPACING) + display.set_pen(15) + + display.text(name, MENU_PADDING, (i * MENU_SPACING) + int((MENU_SPACING - 8) / 2), WIDTH, MENU_TEXT_SIZE) + + name, size, thickness = FONT_NAMES[state["selected_font"]] + display.set_font(name) + + y = 0 if name.startswith("bitmap") else 10 + + display.set_pen(0) + for line in ("The quick", "brown fox", "jumps over", "the lazy dog.", "0123456789", "!\"£$%^&*()"): + display.text(line, TEXT_INDENT, y, WIDTH, size) + y += 22 + + display.update() + + +# ------------------------------ +# Program setup +# ------------------------------ + +# Global variables +state = {"selected_font": 0} +badger_os.state_load("fonts", state) + +# Create a new Badger and set it to update FAST +display = badger2040w.Badger2040W() +display.led(128) +display.set_update_speed(badger2040w.UPDATE_FAST) + +changed = not badger2040w.woken_by_button() + +# ------------------------------ +# Main program loop +# ------------------------------ + +while True: + if display.pressed(badger2040w.BUTTON_UP): + state["selected_font"] -= 1 + if state["selected_font"] < 0: + state["selected_font"] = len(FONT_NAMES) - 1 + changed = True + if display.pressed(badger2040w.BUTTON_DOWN): + state["selected_font"] += 1 + if state["selected_font"] >= len(FONT_NAMES): + state["selected_font"] = 0 + changed = True + + if changed: + draw_frame() + draw_fonts() + badger_os.state_save("fonts", state) + changed = False + + display.halt() diff --git a/micropython/examples/badger2040w/examples/help.py b/micropython/examples/badger2040w/examples/help.py index e69de29b..8e08a8c8 100644 --- a/micropython/examples/badger2040w/examples/help.py +++ b/micropython/examples/badger2040w/examples/help.py @@ -0,0 +1,40 @@ +import badger2040w +from badger2040w import WIDTH + +TEXT_SIZE = 0.45 +LINE_HEIGHT = 20 + +display = badger2040w.Badger2040W() +display.led(128) + +# Clear to white +display.set_pen(15) +display.clear() + +display.set_font("bitmap8") +display.set_pen(0) +display.rectangle(0, 0, WIDTH, 16) +display.set_pen(15) +display.text("badgerOS", 3, 4, WIDTH, 1) +display.text("help", WIDTH - display.measure_text("help", 0.4) - 4, 4, WIDTH, 1) + +display.set_font("sans") +display.set_pen(0) + +TEXT_SIZE = 0.62 +y = 20 + int(LINE_HEIGHT / 2) + +display.set_font("sans") +display.text("Up/Down - Change page", 0, y, WIDTH, TEXT_SIZE) +y += LINE_HEIGHT +display.text("a, b or c - Launch app", 0, y, WIDTH, TEXT_SIZE) +y += LINE_HEIGHT +display.text("a & c - Exit app", 0, y, WIDTH, TEXT_SIZE) +y += LINE_HEIGHT + +display.update() + +# Call halt in a loop, on battery this switches off power. +# On USB, the app will exit when A+C is pressed because the launcher picks that up. +while True: + display.halt() diff --git a/micropython/examples/badger2040w/examples/image.py b/micropython/examples/badger2040w/examples/image.py index e69de29b..f44478d4 100644 --- a/micropython/examples/badger2040w/examples/image.py +++ b/micropython/examples/badger2040w/examples/image.py @@ -0,0 +1,119 @@ +import os +import sys +import time +import badger2040w +from badger2040w import HEIGHT, WIDTH +import badger_os +import jpegdec + + +REAMDE = """ +Images must be 296x128 pixel JPEGs + +Create a new "images" directory via Thonny, and upload your .jpg files there. +""" + +OVERLAY_BORDER = 40 +OVERLAY_SPACING = 20 +OVERLAY_TEXT_SIZE = 0.5 + +TOTAL_IMAGES = 0 + + +# Turn the act LED on as soon as possible +display = badger2040w.Badger2040W() +display.led(128) + +jpeg = jpegdec.JPEG(display.display) + +# Try to preload BadgerPunk image +try: + os.mkdir("/images") + with open("/images/readme.txt", "w") as f: + f.write(REAMDE) + f.flush() +except (OSError, ImportError): + pass + +# Load images +try: + IMAGES = [f for f in os.listdir("/images") if f.endswith(".jpg")] + TOTAL_IMAGES = len(IMAGES) +except OSError: + pass + + +state = { + "current_image": 0, + "show_info": True +} + + +def show_image(n): + file = IMAGES[n] + name = file.split(".")[0] + jpeg.open_file("/images/{}".format(file)) + jpeg.decode() + + if state["show_info"]: + name_length = display.measure_text(name, 0.5) + display.set_pen(0) + display.rectangle(0, HEIGHT - 21, name_length + 11, 21) + display.set_pen(15) + display.rectangle(0, HEIGHT - 20, name_length + 10, 20) + display.set_pen(0) + display.text(name, 5, HEIGHT - 10, WIDTH, 0.5) + + for i in range(TOTAL_IMAGES): + x = 286 + y = int((128 / 2) - (TOTAL_IMAGES * 10 / 2) + (i * 10)) + display.set_pen(0) + display.rectangle(x, y, 8, 8) + if state["current_image"] != i: + display.set_pen(15) + display.rectangle(x + 1, y + 1, 6, 6) + + display.update() + + +if TOTAL_IMAGES == 0: + display.set_pen(15) + display.clear() + badger_os.warning(display, "To run this demo, create an /images directory on your device and upload some 1bit 296x128 pixel images.") + time.sleep(4.0) + sys.exit() + + +badger_os.state_load("image", state) + +changed = not badger2040w.woken_by_button() + + +while True: + if display.pressed(badger2040w.BUTTON_UP): + if state["current_image"] > 0: + state["current_image"] -= 1 + changed = True + if display.pressed(badger2040w.BUTTON_DOWN): + if state["current_image"] < TOTAL_IMAGES - 1: + state["current_image"] += 1 + changed = True + if display.pressed(badger2040w.BUTTON_A): + state["show_info"] = not state["show_info"] + changed = True + if display.pressed(badger2040w.BUTTON_B) or display.pressed(badger2040w.BUTTON_C): + display.set_pen(15) + display.clear() + badger_os.warning(display, "To add images connect Badger2040 to a PC, load up Thonny, and see readme.txt in images/") + display.update() + print(state["current_image"]) + time.sleep(4) + changed = True + + if changed: + badger_os.state_save("image", state) + show_image(state["current_image"]) + changed = False + + # Halt the Badger to save power, it will wake up if any of the front buttons are pressed + display.halt() diff --git a/micropython/examples/badger2040w/examples/info.py b/micropython/examples/badger2040w/examples/info.py index e69de29b..7cfff345 100644 --- a/micropython/examples/badger2040w/examples/info.py +++ b/micropython/examples/badger2040w/examples/info.py @@ -0,0 +1,45 @@ +import badger2040w +from badger2040w import WIDTH + +TEXT_SIZE = 0.45 +LINE_HEIGHT = 16 + +display = badger2040w.Badger2040W() +display.led(128) + +# Clear to white +display.set_pen(15) +display.clear() + +display.set_font("bitmap8") +display.set_pen(0) +display.rectangle(0, 0, WIDTH, 16) +display.set_pen(15) +display.text("badgerOS", 3, 4, WIDTH, 1) +display.text("info", WIDTH - display.measure_text("help", 0.4) - 4, 4, WIDTH, 1) + +display.set_font("sans") +display.set_pen(0) + +y = 16 + int(LINE_HEIGHT / 2) + +display.text("Made by Pimoroni, powered by MicroPython", 0, y, WIDTH, TEXT_SIZE) +y += LINE_HEIGHT +display.text("Dual-core RP2040, 133MHz, 264KB RAM", 0, y, WIDTH, TEXT_SIZE) +y += LINE_HEIGHT +display.text("2MB Flash (1MB OS, 1MB Storage)", 0, y, WIDTH, TEXT_SIZE) +y += LINE_HEIGHT +display.text("296x128 pixel Black/White e-Ink", 0, y, WIDTH, TEXT_SIZE) +y += LINE_HEIGHT +y += LINE_HEIGHT + +display.text("For more info:", 0, y, WIDTH, TEXT_SIZE) +y += LINE_HEIGHT +display.text("https://pimoroni.com/badger2040w", 0, y, WIDTH, TEXT_SIZE) + +display.update() + +# Call halt in a loop, on battery this switches off power. +# On USB, the app will exit when A+C is pressed because the launcher picks that up. +while True: + display.halt() diff --git a/micropython/examples/badger2040w/examples/list.py b/micropython/examples/badger2040w/examples/list.py index e69de29b..f74298ad 100644 --- a/micropython/examples/badger2040w/examples/list.py +++ b/micropython/examples/badger2040w/examples/list.py @@ -0,0 +1,311 @@ +import binascii + +import badger2040w +import badger_os + +# **** Put your list title here ***** +list_title = "Checklist" +list_file = "checklist.txt" + + +# Global Constantsu +WIDTH = badger2040w.WIDTH +HEIGHT = badger2040w.HEIGHT + +ARROW_THICKNESS = 3 +ARROW_WIDTH = 18 +ARROW_HEIGHT = 14 +ARROW_PADDING = 2 + +MAX_ITEM_CHARS = 26 +TITLE_TEXT_SIZE = 0.7 +ITEM_TEXT_SIZE = 0.6 +ITEM_SPACING = 20 + +LIST_START = 40 +LIST_PADDING = 2 +LIST_WIDTH = WIDTH - LIST_PADDING - LIST_PADDING - ARROW_WIDTH +LIST_HEIGHT = HEIGHT - LIST_START - LIST_PADDING - ARROW_HEIGHT + + +# Default list items - change the list items by editing checklist.txt +list_items = ["Badger", "Badger", "Badger", "Badger", "Badger", "Mushroom", "Mushroom", "Snake"] +save_checklist = False + +try: + with open("checklist.txt", "r") as f: + raw_list_items = f.read() + + if raw_list_items.find(" X\n") != -1: + # Have old style checklist, preserve state and note we should resave the list to remove the Xs + list_items = [] + state = { + "current_item": 0, + "checked": [] + } + for item in raw_list_items.strip().split("\n"): + if item.endswith(" X"): + state["checked"].append(True) + item = item[:-2] + else: + state["checked"].append(False) + list_items.append(item) + state["items_hash"] = binascii.crc32("\n".join(list_items)) + + badger_os.state_save("list", state) + save_checklist = True + else: + list_items = [item.strip() for item in raw_list_items.strip().split("\n")] + +except OSError: + save_checklist = True + +if save_checklist: + with open("checklist.txt", "w") as f: + for item in list_items: + f.write(item + "\n") + + +# ------------------------------ +# Drawing functions +# ------------------------------ + +# Draw the list of items +def draw_list(items, item_states, start_item, highlighted_item, x, y, width, height, item_height, columns): + item_x = 0 + item_y = 0 + current_col = 0 + for i in range(start_item, len(items)): + if i == highlighted_item: + display.set_pen(12) + display.rectangle(item_x, item_y + y - (item_height // 2), width // columns, item_height) + display.set_pen(0) + display.text(items[i], item_x + x + item_height, item_y + y, WIDTH, ITEM_TEXT_SIZE) + draw_checkbox(item_x, item_y + y - (item_height // 2), item_height, 15, 0, 2, item_states[i], 2) + item_y += item_height + if item_y >= height - (item_height // 2): + item_x += width // columns + item_y = 0 + current_col += 1 + if current_col >= columns: + return + + +# Draw a upward arrow +def draw_up(x, y, width, height, thickness, padding): + border = (thickness // 4) + padding + display.line(x + border, y + height - border, + x + (width // 2), y + border) + display.line(x + (width // 2), y + border, + x + width - border, y + height - border) + + +# Draw a downward arrow +def draw_down(x, y, width, height, thickness, padding): + border = (thickness // 2) + padding + display.line(x + border, y + border, + x + (width // 2), y + height - border) + display.line(x + (width // 2), y + height - border, + x + width - border, y + border) + + +# Draw a left arrow +def draw_left(x, y, width, height, thickness, padding): + border = (thickness // 2) + padding + display.line(x + width - border, y + border, + x + border, y + (height // 2)) + display.line(x + border, y + (height // 2), + x + width - border, y + height - border) + + +# Draw a right arrow +def draw_right(x, y, width, height, thickness, padding): + border = (thickness // 2) + padding + display.line(x + border, y + border, + x + width - border, y + (height // 2)) + display.line(x + width - border, y + (height // 2), + x + border, y + height - border) + + +# Draw a tick +def draw_tick(x, y, width, height, thickness, padding): + border = (thickness // 2) + padding + display.line(x + border, y + ((height * 2) // 3), + x + (width // 2), y + height - border) + display.line(x + (width // 2), y + height - border, + x + width - border, y + border) + + +# Draw a cross +def draw_cross(x, y, width, height, thickness, padding): + border = (thickness // 2) + padding + display.line(x + border, y + border, x + width - border, y + height - border) + display.line(x + width - border, y + border, x + border, y + height - border) + + +# Draw a checkbox with or without a tick +def draw_checkbox(x, y, size, background, foreground, thickness, tick, padding): + border = (thickness // 2) + padding + display.set_pen(background) + display.rectangle(x + border, y + border, size - (border * 2), size - (border * 2)) + display.set_pen(foreground) + display.line(x + border, y + border, x + size - border, y + border) + display.line(x + border, y + border, x + border, y + size - border) + display.line(x + size - border, y + border, x + size - border, y + size - border) + display.line(x + border, y + size - border, x + size - border, y + size - border) + if tick: + draw_tick(x, y, size, size, thickness, 2 + border) + + +# ------------------------------ +# Program setup +# ------------------------------ + +changed = not badger2040w.woken_by_button() +state = { + "current_item": 0, +} +badger_os.state_load("list", state) +items_hash = binascii.crc32("\n".join(list_items)) +if "items_hash" not in state or state["items_hash"] != items_hash: + # Item list changed, or not yet written reset the list + state["current_item"] = 0 + state["items_hash"] = items_hash + state["checked"] = [False] * len(list_items) + changed = True + +# Global variables +items_per_page = 0 + +# Create a new Badger and set it to update FAST +display = badger2040w.Badger2040W() +display.led(128) +display.set_font("sans") +if changed: + display.set_update_speed(badger2040w.UPDATE_FAST) +else: + display.set_update_speed(badger2040w.UPDATE_TURBO) + +# Find out what the longest item is +longest_item = 0 +for i in range(len(list_items)): + while True: + item = list_items[i] + item_length = display.measure_text(item, ITEM_TEXT_SIZE) + if item_length > 0 and item_length > LIST_WIDTH - ITEM_SPACING: + list_items[i] = item[:-1] + else: + break + longest_item = max(longest_item, display.measure_text(list_items[i], ITEM_TEXT_SIZE)) + + +# And use that to calculate the number of columns we can fit onscreen and how many items that would give +list_columns = 1 +while longest_item + ITEM_SPACING < (LIST_WIDTH // (list_columns + 1)): + list_columns += 1 + +items_per_page = ((LIST_HEIGHT // ITEM_SPACING) + 1) * list_columns + + +# ------------------------------ +# Main program loop +# ------------------------------ + +while True: + if len(list_items) > 0: + if display.pressed(badger2040w.BUTTON_A): + if state["current_item"] > 0: + page = state["current_item"] // items_per_page + state["current_item"] = max(state["current_item"] - (items_per_page) // list_columns, 0) + if page != state["current_item"] // items_per_page: + display.update_speed(badger2040w.UPDATE_FAST) + changed = True + if display.pressed(badger2040w.BUTTON_B): + state["checked"][state["current_item"]] = not state["checked"][state["current_item"]] + changed = True + if display.pressed(badger2040w.BUTTON_C): + if state["current_item"] < len(list_items) - 1: + page = state["current_item"] // items_per_page + state["current_item"] = min(state["current_item"] + (items_per_page) // list_columns, len(list_items) - 1) + if page != state["current_item"] // items_per_page: + display.update_speed(badger2040w.UPDATE_FAST) + changed = True + if display.pressed(badger2040w.BUTTON_UP): + if state["current_item"] > 0: + state["current_item"] -= 1 + changed = True + if display.pressed(badger2040w.BUTTON_DOWN): + if state["current_item"] < len(list_items) - 1: + state["current_item"] += 1 + changed = True + + if changed: + badger_os.state_save("list", state) + + display.set_pen(15) + display.clear() + + display.set_pen(12) + display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT) + display.rectangle(0, HEIGHT - ARROW_HEIGHT, WIDTH, ARROW_HEIGHT) + + y = LIST_PADDING + 12 + display.set_pen(0) + display.text(list_title, LIST_PADDING, y, WIDTH, TITLE_TEXT_SIZE) + + y += 12 + display.set_pen(0) + display.line(LIST_PADDING, y, WIDTH - LIST_PADDING - ARROW_WIDTH, y) + + if len(list_items) > 0: + page_item = 0 + if items_per_page > 0: + page_item = (state["current_item"] // items_per_page) * items_per_page + + # Draw the list + display.set_pen(0) + draw_list(list_items, state["checked"], page_item, state["current_item"], LIST_PADDING, LIST_START, + LIST_WIDTH, LIST_HEIGHT, ITEM_SPACING, list_columns) + + # Draw the interaction button icons + display.set_pen(0) + + # Previous item + if state["current_item"] > 0: + draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2), + ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) + + # Next item + if state["current_item"] < (len(list_items) - 1): + draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2), + ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) + + # Previous column + if state["current_item"] > 0: + draw_left((WIDTH // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT, + ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) + + # Next column + if state["current_item"] < (len(list_items) - 1): + draw_right(((WIDTH * 6) // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT, + ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) + + if state["checked"][state["current_item"]]: + # Tick off item + draw_cross((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT, + ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) + else: + # Untick item + draw_tick((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT, + ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) + else: + # Say that the list is empty + empty_text = "Nothing Here" + text_length = display.measure_text(empty_text, ITEM_TEXT_SIZE) + display.text(empty_text, ((LIST_PADDING + LIST_WIDTH) - text_length) // 2, (LIST_HEIGHT // 2) + LIST_START - (ITEM_SPACING // 4), WIDTH, ITEM_TEXT_SIZE) + + display.update() + display.set_update_speed(badger2040w.UPDATE_TURBO) + changed = False + + display.halt() diff --git a/micropython/examples/badger2040w/examples/qrgen.py b/micropython/examples/badger2040w/examples/qrgen.py index e69de29b..451e430d 100644 --- a/micropython/examples/badger2040w/examples/qrgen.py +++ b/micropython/examples/badger2040w/examples/qrgen.py @@ -0,0 +1,138 @@ +import badger2040w +import qrcode +import time +import os +import badger_os + +# Check that the qrcodes directory exists, if not, make it +try: + os.mkdir("/qrcodes") +except OSError: + pass + +# Check that there is a qrcode.txt, if not preload +try: + text = open("/qrcodes/qrcode.txt", "r") +except OSError: + text = open("/qrcodes/qrcode.txt", "w") + text.write("""https://pimoroni.com/badger2040 +Badger 2040 +* 296x128 1-bit e-ink +* six user buttons +* user LED +* 2MB QSPI flash + +Scan this code to learn +more about Badger 2040. +""") + text.flush() + text.seek(0) + +# Load all available QR Code Files +try: + CODES = [f for f in os.listdir("/qrcodes") if f.endswith(".txt")] + TOTAL_CODES = len(CODES) +except OSError: + pass + + +print(f'There are {TOTAL_CODES} QR Codes available:') +for codename in CODES: + print(f'File: {codename}') + +display = badger2040w.Badger2040W() + +code = qrcode.QRCode() + +state = { + "current_qr": 0 +} + + +def measure_qr_code(size, code): + w, h = code.get_size() + module_size = int(size / w) + return module_size * w, module_size + + +def draw_qr_code(ox, oy, size, code): + size, module_size = measure_qr_code(size, code) + display.set_pen(15) + display.rectangle(ox, oy, size, size) + display.set_pen(0) + for x in range(size): + for y in range(size): + if code.get_module(x, y): + display.rectangle(ox + x * module_size, oy + y * module_size, module_size, module_size) + + +def draw_qr_file(n): + display.led(128) + file = CODES[n] + codetext = open("/qrcodes/{}".format(file), "r") + + lines = codetext.read().strip().split("\n") + code_text = lines.pop(0) + title_text = lines.pop(0) + detail_text = lines + + # Clear the Display + display.set_pen(15) # Change this to 0 if a white background is used + display.clear() + display.set_pen(0) + + code.set_text(code_text) + size, _ = measure_qr_code(128, code) + left = top = int((badger2040w.HEIGHT / 2) - (size / 2)) + draw_qr_code(left, top, 128, code) + + left = 128 + 5 + + display.text(title_text, left, 20, badger2040w.WIDTH, 2) + + top = 40 + for line in detail_text: + display.text(line, left, top, badger2040w.WIDTH, 1) + top += 10 + + if TOTAL_CODES > 1: + for i in range(TOTAL_CODES): + x = 286 + y = int((128 / 2) - (TOTAL_CODES * 10 / 2) + (i * 10)) + display.set_pen(0) + display.rectangle(x, y, 8, 8) + if state["current_qr"] != i: + display.set_pen(15) + display.rectangle(x + 1, y + 1, 6, 6) + display.update() + + +badger_os.state_load("qrcodes", state) +changed = not badger2040w.woken_by_button() + +while True: + if TOTAL_CODES > 1: + if display.pressed(badger2040w.BUTTON_UP): + if state["current_qr"] > 0: + state["current_qr"] -= 1 + changed = True + + if display.pressed(badger2040w.BUTTON_DOWN): + if state["current_qr"] < TOTAL_CODES - 1: + state["current_qr"] += 1 + changed = True + + if display.pressed(badger2040w.BUTTON_B) or display.pressed(badger2040w.BUTTON_C): + display.set_pen(15) + display.clear() + badger_os.warning(display, "To add QR codes, connect Badger2040W to a PC, load up Thonny, and see qrgen.py.") + time.sleep(4) + changed = True + + if changed: + draw_qr_file(state["current_qr"]) + badger_os.state_save("qrcodes", state) + changed = False + + # Halt the Badger to save power, it will wake up if any of the front buttons are pressed + display.halt() diff --git a/micropython/examples/badger2040w/images/README.txt b/micropython/examples/badger2040w/images/README.txt new file mode 100644 index 00000000..c9a6e267 --- /dev/null +++ b/micropython/examples/badger2040w/images/README.txt @@ -0,0 +1,3 @@ +Images must be 296x128 pixel JPEGs + +Create a new "images" directory via Thonny, and upload your .jpg files there. diff --git a/micropython/examples/badger2040w/images/badgerpunk.jpg b/micropython/examples/badger2040w/images/badgerpunk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..73f32be9525032d80bfb9bcb2b967daa1f496c36 GIT binary patch literal 9264 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 Date: Wed, 18 Jan 2023 10:06:30 +0000 Subject: [PATCH 16/46] Badger2040W: Fix very slow and very wrong __getattr__. --- micropython/examples/badger2040w/lib/badger2040w.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/micropython/examples/badger2040w/lib/badger2040w.py b/micropython/examples/badger2040w/lib/badger2040w.py index aab47f6b..ca5475b4 100644 --- a/micropython/examples/badger2040w/lib/badger2040w.py +++ b/micropython/examples/badger2040w/lib/badger2040w.py @@ -72,12 +72,7 @@ class Badger2040W(): def __getattr__(self, item): # Glue to redirect calls to PicoGraphics - if item in dir(self.display): - return getattr(self.display, item) - elif item in self.__dict__.keys(): - return getattr(self, item) - else: - raise AttributeError(f"No attribute '{item}'") + return getattr(self.display, item) def led(self, brightness): pass From 652678777289ef74b41a7f186a695020e3567ba2 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 18 Jan 2023 10:10:51 +0000 Subject: [PATCH 17/46] Badger2040W: Drop turbo clock from launcher. --- micropython/examples/badger2040w/launcher.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/micropython/examples/badger2040w/launcher.py b/micropython/examples/badger2040w/launcher.py index cf55e707..da3d16f2 100644 --- a/micropython/examples/badger2040w/launcher.py +++ b/micropython/examples/badger2040w/launcher.py @@ -9,9 +9,6 @@ import jpegdec APP_DIR = "/examples" FONT_SIZE = 2 -# Reduce clock speed to 48MHz -badger2040.system_speed(badger2040.SYSTEM_TURBO) - changed = False exited_to_launcher = False woken_by_button = badger2040.woken_by_button() # Must be done before we clear_pressed_to_wake From 379a1cb3ef0aafcfc477f1397479af6dd66e5443 Mon Sep 17 00:00:00 2001 From: thirdr Date: Wed, 18 Jan 2023 15:29:17 +0000 Subject: [PATCH 18/46] Badger2040W: New examples. --- .../badger2040w/examples/network_info.py | 68 ++++++ .../examples/badger2040w/examples/news.py | 230 ++++++++++++++++++ 2 files changed, 298 insertions(+) create mode 100644 micropython/examples/badger2040w/examples/network_info.py create mode 100644 micropython/examples/badger2040w/examples/news.py diff --git a/micropython/examples/badger2040w/examples/network_info.py b/micropython/examples/badger2040w/examples/network_info.py new file mode 100644 index 00000000..705dc179 --- /dev/null +++ b/micropython/examples/badger2040w/examples/network_info.py @@ -0,0 +1,68 @@ +import badger2040w as badger2040 +from badger2040w import WIDTH +import time +import network +import machine + +TEXT_SIZE = 1 +LINE_HEIGHT = 16 + +# Display Setup +display = badger2040.Badger2040W() +display.led(128) + + +# Button handler +def button(pin): + + time.sleep(0.01) + if not pin.value(): + return + + if button_a.value() and button_c.value(): + machine.reset() + + +# Setup buttons +button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) +button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) +button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) +button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button) + +# Connects to the wireless network. Ensure you have entered your details in WIFI_CONFIG.py :). +display.connect() +net = network.WLAN(network.STA_IF).ifconfig() + +# Page Header +display.set_pen(15) +display.clear() +display.set_pen(0) + +display.set_pen(0) +display.rectangle(0, 0, WIDTH, 20) +display.set_pen(15) +display.text("badgerOS", 3, 4) +display.text("Network Details", WIDTH - display.measure_text("Network Details") - 4, 4) +display.set_pen(0) + +y = 35 + int(LINE_HEIGHT / 2) + +if net: + display.text("> LOCAL IP: {}".format(net[0]), 0, y, WIDTH) + y += LINE_HEIGHT + display.text("> Subnet: {}".format(net[1]), 0, y, WIDTH) + y += LINE_HEIGHT + display.text("> Gateway: {}".format(net[2]), 0, y, WIDTH) + y += LINE_HEIGHT + display.text("> DNS: {}".format(net[3]), 0, y, WIDTH) +else: + display.text("> No network connection!", 0, y, WIDTH) + y += LINE_HEIGHT + display.text("> Check details in WIFI_CONFIG.py", 0, y, WIDTH) + +display.update() + +# Call halt in a loop, on battery this switches off power. +# On USB, the app will exit when A+C is pressed because the launcher picks that up. +while True: + display.halt() diff --git a/micropython/examples/badger2040w/examples/news.py b/micropython/examples/badger2040w/examples/news.py new file mode 100644 index 00000000..c8c4239a --- /dev/null +++ b/micropython/examples/badger2040w/examples/news.py @@ -0,0 +1,230 @@ +import badger2040w as badger2040 +from badger2040w import WIDTH +import time +import machine +from urllib import urequest +import gc +import qrcode +import badger_os + +# URLS to use (Entertainment, Science and Technology) +URL = ["http://feeds.bbci.co.uk/news/video_and_audio/entertainment_and_arts/rss.xml", + "http://feeds.bbci.co.uk/news/video_and_audio/science_and_environment/rss.xml", + "http://feeds.bbci.co.uk/news/technology/rss.xml"] + +code = qrcode.QRCode() + +state = { + "current_page": 0, + "feed": 2 +} + +badger_os.state_load("news", state) + +# Display Setup +display = badger2040.Badger2040W() +display.led(128) +display.set_update_speed(2) + + +# Button handler +def button(pin): + time.sleep(0.01) + if not pin.value(): + return + + if button_a.value() and button_c.value(): + machine.reset() + + +# Setup buttons +button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) +button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN) +button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) +button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN) +button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN) + +button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) +button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button) + + +def read_until(stream, char): + result = b"" + while True: + c = stream.read(1) + if c == char: + return result + result += c + + +def discard_until(stream, c): + while stream.read(1) != c: + pass + + +def parse_xml_stream(s, accept_tags, group_by, max_items=3): + tag = [] + text = b"" + count = 0 + current = {} + while True: + char = s.read(1) + if len(char) == 0: + break + + if char == b"<": + next_char = s.read(1) + + # Discard stuff like ") + continue + + # Detect ") # Discard ]> + gc.collect() + + elif next_char == b"/": + current_tag = read_until(s, b">") + top_tag = tag[-1] + + # Populate our result dict + if top_tag in accept_tags: + current[top_tag.decode("utf-8")] = text.decode("utf-8") + + # If we've found a group of items, yield the dict + elif top_tag == group_by: + yield current + current = {} + count += 1 + if count == max_items: + return + tag.pop() + text = b"" + gc.collect() + continue + + else: + current_tag = read_until(s, b">") + tag += [next_char + current_tag.split(b" ")[0]] + text = b"" + gc.collect() + + else: + text += char + + +def measure_qr_code(size, code): + w, h = code.get_size() + module_size = int(size / w) + return module_size * w, module_size + + +def draw_qr_code(ox, oy, size, code): + size, module_size = measure_qr_code(size, code) + display.set_pen(15) + display.rectangle(ox, oy, size, size) + display.set_pen(0) + for x in range(size): + for y in range(size): + if code.get_module(x, y): + display.rectangle(ox + x * module_size, oy + y * module_size, module_size, module_size) + + +# A function to get the data from an RSS Feed, this in case BBC News. +def get_rss(url): + try: + stream = urequest.urlopen(url) + output = list(parse_xml_stream(stream, [b"title", b"description", b"guid", b"pubDate"], b"item")) + return output + + except OSError as e: + print(e) + return False + + +# Connects to the wireless network. Ensure you have entered your details in WIFI_CONFIG.py :). +display.connect() + +print(state["feed"]) +feed = get_rss(URL[state["feed"]]) + + +def draw_page(): + + # Clear the display + display.set_pen(15) + display.clear() + display.set_pen(0) + + # Draw the page header + display.set_font("bitmap6") + display.set_pen(0) + display.rectangle(0, 0, WIDTH, 20) + display.set_pen(15) + display.text("News", 3, 4) + display.text("Page: " + str(state["current_page"] + 1), WIDTH - display.measure_text("Page: ") - 4, 4) + display.set_pen(0) + + display.set_font("bitmap8") + + # Draw articles from the feed if they're available. + if feed: + page = state["current_page"] + display.set_pen(0) + display.text(feed[page]["title"], 2, 40, WIDTH - 105, 2) + code.set_text(feed[page]["guid"]) + draw_qr_code(WIDTH - 100, 25, 100, code) + + else: + display.set_pen(0) + display.rectangle(0, 60, WIDTH, 25) + display.set_pen(15) + display.text("Unable to display news! Check your network settings in WIFI_CONFIG.py", 5, 65, WIDTH, 1) + + display.update() + + +draw_page() + +while 1: + + changed = False + + if button_down.value(): + if state["current_page"] < 2: + state["current_page"] += 1 + changed = True + + if button_up.value(): + if state["current_page"] > 0: + state["current_page"] -= 1 + changed = True + + if button_a.value(): + state["feed"] = 0 + state["current_page"] = 0 + feed = get_rss(URL[state["feed"]]) + badger_os.state_save("news", state) + changed = True + + if button_b.value(): + state["feed"] = 1 + state["current_page"] = 0 + feed = get_rss(URL[state["feed"]]) + badger_os.state_save("news", state) + changed = True + + if button_c.value(): + state["feed"] = 2 + state["current_page"] = 0 + feed = get_rss(URL[state["feed"]]) + badger_os.state_save("news", state) + changed = True + + if changed: + draw_page() From 23f792caa9d7f68dd720007a8f94deee820e8413 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 19 Jan 2023 12:17:31 +0000 Subject: [PATCH 19/46] Badger2040W: Finish core libs, add Badge. --- .../examples/badger2040w/badges/badge.jpg | Bin 0 -> 7878 bytes .../examples/badger2040w/badges/badge.txt | 6 + .../examples/badger2040w/examples/badge.py | 171 ++++++++++++++++++ .../badger2040w/examples/icon-net-info.jpg | Bin 0 -> 2005 bytes .../badger2040w/examples/icon-news.jpg | Bin 0 -> 1767 bytes .../examples/badger2040w/examples/info.py | 17 +- .../examples/{network_info.py => net_info.py} | 0 micropython/examples/badger2040w/launcher.py | 33 +--- .../examples/badger2040w/lib/badger2040w.py | 24 ++- .../examples/badger2040w/uf2-manifest.txt | 4 +- 10 files changed, 210 insertions(+), 45 deletions(-) create mode 100644 micropython/examples/badger2040w/badges/badge.jpg create mode 100644 micropython/examples/badger2040w/badges/badge.txt create mode 100644 micropython/examples/badger2040w/examples/icon-net-info.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-news.jpg rename micropython/examples/badger2040w/examples/{network_info.py => net_info.py} (100%) diff --git a/micropython/examples/badger2040w/badges/badge.jpg b/micropython/examples/badger2040w/badges/badge.jpg new file mode 100644 index 0000000000000000000000000000000000000000..287a43ca98546b172d0367c5f8dcad52d380ac42 GIT binary patch literal 7878 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 0 and length > width: + text = text[:-1] + else: + text += "" + return text + + +# ------------------------------ +# Drawing functions +# ------------------------------ + +# Draw the badge, including user text +def draw_badge(): + display.set_pen(0) + display.clear() + + # Draw badge image + jpeg.open_file(badge_image) + jpeg.decode(WIDTH - IMAGE_WIDTH, 0) + + # Draw a border around the image + display.set_pen(0) + display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - 1, 0) + display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - IMAGE_WIDTH, HEIGHT - 1) + display.line(WIDTH - IMAGE_WIDTH, HEIGHT - 1, WIDTH - 1, HEIGHT - 1) + display.line(WIDTH - 1, 0, WIDTH - 1, HEIGHT - 1) + + # Uncomment this if a white background is wanted behind the company + # display.set_pen(15) + # display.rectangle(1, 1, TEXT_WIDTH, COMPANY_HEIGHT - 1) + + # Draw the company + display.set_pen(15) # Change this to 0 if a white background is used + display.set_font("serif") + display.text(company, LEFT_PADDING, (COMPANY_HEIGHT // 2) + 1, WIDTH, COMPANY_TEXT_SIZE) + + # Draw a white background behind the name + display.set_pen(15) + display.rectangle(1, COMPANY_HEIGHT + 1, TEXT_WIDTH, NAME_HEIGHT) + + # Draw the name, scaling it based on the available width + display.set_pen(0) + display.set_font("sans") + name_size = 2.0 # A sensible starting scale + while True: + name_length = display.measure_text(name, name_size) + if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1: + name_size -= 0.01 + else: + display.text(name, (TEXT_WIDTH - name_length) // 2, (NAME_HEIGHT // 2) + COMPANY_HEIGHT + 1, WIDTH, name_size) + break + + # Draw a white backgrounds behind the details + display.set_pen(15) + display.rectangle(1, HEIGHT - DETAILS_HEIGHT * 2, TEXT_WIDTH, DETAILS_HEIGHT - 1) + display.rectangle(1, HEIGHT - DETAILS_HEIGHT, TEXT_WIDTH, DETAILS_HEIGHT - 1) + + # Draw the first detail's title and text + display.set_pen(0) + display.set_font("sans") + name_length = display.measure_text(detail1_title, DETAILS_TEXT_SIZE) + display.text(detail1_title, LEFT_PADDING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), WIDTH, DETAILS_TEXT_SIZE) + display.text(detail1_text, 5 + name_length + DETAIL_SPACING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), WIDTH, DETAILS_TEXT_SIZE) + + # Draw the second detail's title and text + name_length = display.measure_text(detail2_title, DETAILS_TEXT_SIZE) + display.text(detail2_title, LEFT_PADDING, HEIGHT - (DETAILS_HEIGHT // 2), WIDTH, DETAILS_TEXT_SIZE) + display.text(detail2_text, LEFT_PADDING + name_length + DETAIL_SPACING, HEIGHT - (DETAILS_HEIGHT // 2), WIDTH, DETAILS_TEXT_SIZE) + + +# ------------------------------ +# Program setup +# ------------------------------ + +# Create a new Badger and set it to update NORMAL +display = badger2040w.Badger2040W() +display.led(128) +display.set_update_speed(badger2040w.UPDATE_NORMAL) + +jpeg = jpegdec.JPEG(display.display) + +# Open the badge file +try: + badge = open(BADGE_PATH, "r") +except OSError: + with open(BADGE_PATH, "w") as f: + f.write(DEFAULT_TEXT) + f.flush() + badge = open(BADGE_PATH, "r") + +# Read in the next 6 lines +company = badge.readline() # "mustelid inc" +name = badge.readline() # "H. Badger" +detail1_title = badge.readline() # "RP2040" +detail1_text = badge.readline() # "2MB Flash" +detail2_title = badge.readline() # "E ink" +detail2_text = badge.readline() # "296x128px" +badge_image = badge.readline() # /badges/badge.jpg + +# Truncate all of the text (except for the name as that is scaled) +company = truncatestring(company, COMPANY_TEXT_SIZE, TEXT_WIDTH) + +detail1_title = truncatestring(detail1_title, DETAILS_TEXT_SIZE, TEXT_WIDTH) +detail1_text = truncatestring(detail1_text, DETAILS_TEXT_SIZE, + TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail1_title, DETAILS_TEXT_SIZE)) + +detail2_title = truncatestring(detail2_title, DETAILS_TEXT_SIZE, TEXT_WIDTH) +detail2_text = truncatestring(detail2_text, DETAILS_TEXT_SIZE, + TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail2_title, DETAILS_TEXT_SIZE)) + + +# ------------------------------ +# Main program +# ------------------------------ + +draw_badge() + +while True: + if display.pressed(badger2040w.BUTTON_A) or display.pressed(badger2040w.BUTTON_B) or display.pressed(badger2040w.BUTTON_C) or display.pressed(badger2040w.BUTTON_UP) or display.pressed(badger2040w.BUTTON_DOWN): + badger_os.warning(display, "To change the text, connect Badger2040 to a PC, load up Thonny, and modify badge.txt") + time.sleep(4) + + draw_badge() + + display.update() + + # If on battery, halt the Badger to save power, it will wake up if any of the front buttons are pressed + display.halt() diff --git a/micropython/examples/badger2040w/examples/icon-net-info.jpg b/micropython/examples/badger2040w/examples/icon-net-info.jpg new file mode 100644 index 0000000000000000000000000000000000000000..73bcd3e3758b4c23044398b2328b601429753d8e GIT binary patch literal 2005 zcmbW&cTm%58VB%S@=JvPMv8$X1PCnX0+K@Wkbo%l3`!9M6=@2h5{eL5k}qlD6k0}5Rr1YdviB)GdHt)-*?{kpZA$}p3l7R%)2$T zH4f~sx3;qeAP@k6Y!6^-1h4{72m}%VM)QjSvNDTzVmje4wgT(Wy_QN%IMfM@uQ~!YQk0eWR_jdk@{v$k@bm zpVh%b);6|w_RcP@$K2eHd-(eKpE(;4crGmbQbZ&>Dmo!C>FTxX$u}}?XJ%#R-1*_| zy`tih`@9FG4}Yw#sjaJj+|bz8-qHE|r>^c7{R3|Y-~D~){qV#ug2}0A;mqtu@#4}y zmRD9KpVz*+AOQF~YkU12_FpdSwhIb_fiUD(7X%u)JwYrCu1-Phv^G0IO>{u25aiktdJ!d|(PJHBa7naaZtd1}J*Ak1RKj0) z0q>bOlN8DU^m9B>u8e#`JT>9Jk5B#8BlJ1)K78B59A%b0; zgn*beJvchhAmn+>t8wvV>`J|9YtM~xp}2Y`&J-}?ChF>Z%gTL7j-!*kuTcQUhmC5HLt+^M#LIe2w#Z~nxEidIvcn(*rWPC#+V zrt^cRi+HS4Iu<@li^{I+FGdqWgHw5As{I#B@@XGlWp5h$rPSJ~7C#9|Lvl-?%B%2d zCk?-T@_I4KKg&1UPSHJ%o9h>nz-=j_Lw?=Fik{p`Xf_Ni8nVG*)oAvmHE;A0v-pfq z+u7T39200cJLhojaZx3|WTYl&|9s{*L`>UCj7-#m-Lxbd$y&wm%4~WlvbIsZhQZpV*tstu0lnou>|$E> zX;#ESTWW(@Y0qd8iyzKKU96a@e|*EVAWO=Qa6|c|Z7WO_MNV-`-t6(1E-eilo=RF? zUp1;@oKY&JEi76g;V#?*6T75)eL2*y1qH|=FFE{!!#KZF$B?L3y!rZXuSA;uS^o8V zmqus?r)>eudWSzLAtlBUCi>vn84|1;X1NEMW;;Y}O#j}Ju*1fbkKZUhe_>K|@%ELz z>5oLK?$lLMma4HXW#G2Tl~dDAj){$#!~C|Vaz8Vx%1RpQArSC9vv2n#H=;m$Z2!I^ z$UraZWtxEmFBsfRqKDeR-h}Y1v_`HE>5q#kU67lJ7L=6FoU~^f#$Jqdw#abm{ynpp zVuz`yQ%9P2tJ{&&ZQZAx^H+CC$D@#WRRGDtttY>xt_0KA6Ib%ETR1ZEk~L>Be9YSQ zh-pul{Mj@CKiEd%EoK}Rb5nx?BO?jsYRNF?kryv2Sgm$cYXk^Yr~)oGr})CeTYzc{ zDad1fo|jB#Yqsq0tSElRvi5MrzfX8Tc=U3dLp6{iYgrgG&gSB8I$r(pu-SLyrng#m z!N5-7pI$9pRQ7k^TzH1#=)Uy06xyTK zNndWzGc!uj$9%lG*2y51T!DRUmgeKM<6%?J-0#c}TpZ}a7-M4PNp~h%cm>d+|MkRN zGLInNaA^``3~%&)*|qz7`kX|)Q zu~R8}4~LD-y)aG(znxw_QKiR~jp|;zas&9Bu(|7Lhs<}IT8+$npZbB=G9x7?2V)Xt zxV%RW5bj~WVb=QENo)l9#82txM(K^*cY`a<87E$;M5NZ6cL|iS<9QcO7e=yp@Sxdf r9gx(nitAq|7q%A%?ua@jUVQa)b7gcBcaFtS+x{_(bnbB&Tkrn~lNoFH literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/icon-news.jpg b/micropython/examples/badger2040w/examples/icon-news.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7c1b73cb4346e250a3aa49237d02021e646f02cf GIT binary patch literal 1767 zcmbW#YdF+d7y$6|pZgdSlOZuTwq zz2AoK{Wk`Ogl^xlbJy;ueftkYb7Nu;CmcykI(jTQGwbJ**{4qbawfmv{I3@-Ub=kc zX34G6-^$8wSJa4W@7GBl)HghBX?@lvecs+7>+0_Ly|?e}yZ+&ipGHQ<#uXEjvn~iA zzpzy67uY{sB$W$+LLpJuSr>$eR!t-cg*LLq%ysd_21RHYv*K~&6({m;RO9J(>*U(o zBAeB881^!g;aS>e*}sDc{+H}8*x#-WppJx8pNAv?HW;5|7O~ru_6mL1Pc2h{gX5Zm zGmjFs2TVv_WgTsT>L>1yq{(1J%|ZeLSwSTY2F|adl+!C=APFm$58bC>xw(yLl8pk3 ziyx~>?=1f|=S@C%KBv9A$Es;bPYAL&zg(m<&5>U`Y;97~8Xj`WCsq5=$!noKVgnY} z&2ggm;T)TvQa;KLHE$uF>0%07{Nt%Lw{C8#TMx0hgBfS%R3Z*S=QK9w-{x!Z+~n!W zMMPnGVf8mp-Vv_W4ppE|He@U6!!PObj)rp5Tsf)5Z>&E=Ywi`NopzFjPkHd` zomyZpU_nzRXQ#JIl%BnLFbMKzk8n896MjvmA_fL4#+6<#`NIwJ$H!qny!9qYs<&oW z^r@(7US{H&!fOv6Y{+N;hDns*6az2rWYazV%mq=e9}LPwGX>7-a*rya!v^`Y?858) z{p?hd9=0npeqo;j0Puw`xc_*V{>*1;c zp?wz(M@M@r(h;gm<n@eHfW(8F8K`IOwpS)pEe2qV8zLC9yHeq@uY34`>44Qp?zph?oL6vA; zxD#4tao0fXDd_4CD~UX1*KlCLdh+EI;EjuUxpXQL8okR?y||YDun-2}{3-WhwyNEN zX4_3eIlXqa-EtK z`w}V%=XQ-!qy#M!WS z4oxs)`7?q773Zc@q|j1&_9co2w8LPKpM7t$qNF>(K_WCSeP&;7EfZKU%0esL{4A+2 z=wUW>l<3i-OVjw-`iKL^)Jj!XtZ~+H@|LA8yx&3Ta4*8)@!Ib_#d+xjr#{;o`!p+5klxYax)e>cE_jHB!e`rQAJty>n>)mfMdpp zWQOjiqcpjOX|`MVT_S-}bJ*(k;xXH|A zcc`+Wd#oCA@(F&n2pw7TN_Xa@O;r&J(U%s@J8!G+#X5-KC%q=#F3ZNsucyp)W!5cY zHpkH^tT@h;05=$5LWa60B?E)9u=lmOYb)=y1heuo(Lv@hTZ2v#cny;4y_Q(EnJ%); j(sIwpqoo}+O>FD7Hbx@(rB|yDB1Py0sJrizA-Meyf0i2L literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/info.py b/micropython/examples/badger2040w/examples/info.py index 7cfff345..a878edda 100644 --- a/micropython/examples/badger2040w/examples/info.py +++ b/micropython/examples/badger2040w/examples/info.py @@ -1,8 +1,8 @@ import badger2040w from badger2040w import WIDTH -TEXT_SIZE = 0.45 -LINE_HEIGHT = 16 +TEXT_SIZE = 1 +LINE_HEIGHT = 15 display = badger2040w.Badger2040W() display.led(128) @@ -18,24 +18,23 @@ display.set_pen(15) display.text("badgerOS", 3, 4, WIDTH, 1) display.text("info", WIDTH - display.measure_text("help", 0.4) - 4, 4, WIDTH, 1) -display.set_font("sans") display.set_pen(0) y = 16 + int(LINE_HEIGHT / 2) -display.text("Made by Pimoroni, powered by MicroPython", 0, y, WIDTH, TEXT_SIZE) +display.text("Made by Pimoroni, powered by MicroPython", 5, y, WIDTH, TEXT_SIZE) y += LINE_HEIGHT -display.text("Dual-core RP2040, 133MHz, 264KB RAM", 0, y, WIDTH, TEXT_SIZE) +display.text("Dual-core RP2040, 133MHz, 264KB RAM", 5, y, WIDTH, TEXT_SIZE) y += LINE_HEIGHT -display.text("2MB Flash (1MB OS, 1MB Storage)", 0, y, WIDTH, TEXT_SIZE) +display.text("2MB Flash (1MB OS, 1MB Storage)", 5, y, WIDTH, TEXT_SIZE) y += LINE_HEIGHT -display.text("296x128 pixel Black/White e-Ink", 0, y, WIDTH, TEXT_SIZE) +display.text("296x128 pixel Black/White e-Ink", 5, y, WIDTH, TEXT_SIZE) y += LINE_HEIGHT y += LINE_HEIGHT -display.text("For more info:", 0, y, WIDTH, TEXT_SIZE) +display.text("For more info:", 5, y, WIDTH, TEXT_SIZE) y += LINE_HEIGHT -display.text("https://pimoroni.com/badger2040w", 0, y, WIDTH, TEXT_SIZE) +display.text("https://pimoroni.com/badger2040w", 5, y, WIDTH, TEXT_SIZE) display.update() diff --git a/micropython/examples/badger2040w/examples/network_info.py b/micropython/examples/badger2040w/examples/net_info.py similarity index 100% rename from micropython/examples/badger2040w/examples/network_info.py rename to micropython/examples/badger2040w/examples/net_info.py diff --git a/micropython/examples/badger2040w/launcher.py b/micropython/examples/badger2040w/launcher.py index da3d16f2..87947f35 100644 --- a/micropython/examples/badger2040w/launcher.py +++ b/micropython/examples/badger2040w/launcher.py @@ -20,10 +20,6 @@ else: # Otherwise restore previously running app badger_os.state_launch() -# for e.g. 2xAAA batteries, try max 3.4 min 3.0 -MAX_BATTERY_VOLTAGE = 4.0 -MIN_BATTERY_VOLTAGE = 3.2 - display = badger2040.Badger2040W() display.set_font("bitmap8") display.led(128) @@ -51,29 +47,6 @@ def map_value(input, in_min, in_max, out_min, out_max): return (((input - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min -def draw_battery(level, x, y): - # Outline - display.set_pen(15) - display.rectangle(x, y, 19, 10) - # Terminal - display.rectangle(x + 19, y + 3, 2, 4) - display.set_pen(0) - display.rectangle(x + 1, y + 1, 17, 8) - if level < 1: - display.set_pen(0) - display.line(x + 3, y, x + 3 + 10, y + 10) - display.line(x + 3 + 1, y, x + 3 + 11, y + 10) - display.set_pen(15) - display.line(x + 2 + 2, y - 1, x + 4 + 12, y + 11) - display.line(x + 2 + 3, y - 1, x + 4 + 13, y + 11) - return - # Battery Bars - display.set_pen(15) - for i in range(4): - if level / 4 > (1.0 * i) / 4: - display.rectangle(i * 4 + x + 2, y + 2, 3, 6) - - def draw_disk_usage(x): _, f_used, _ = badger_os.get_disk_usage() @@ -114,7 +87,8 @@ def render(): for i in range(max_icons): x = centers[i] label = examples[i + (state["page"] * 3)] - icon = f"{APP_DIR}/icon-{label}.jpg" + icon_label = label.replace("_", "-") + icon = f"{APP_DIR}/icon-{icon_label}.jpg" label = label.replace("_", " ") jpeg.open_file(icon) jpeg.decode(x - 32, 24) @@ -134,9 +108,6 @@ def render(): display.set_pen(0) display.rectangle(0, 0, WIDTH, 16) draw_disk_usage(90) - vbat = badger_os.get_battery_level() - bat = int(map_value(vbat, MIN_BATTERY_VOLTAGE, MAX_BATTERY_VOLTAGE, 0, 4)) - draw_battery(bat, WIDTH - 22 - 3, 3) display.set_pen(15) display.text("badgerOS", 4, 4, WIDTH, 1.0) diff --git a/micropython/examples/badger2040w/lib/badger2040w.py b/micropython/examples/badger2040w/lib/badger2040w.py index ca5475b4..11e975f8 100644 --- a/micropython/examples/badger2040w/lib/badger2040w.py +++ b/micropython/examples/badger2040w/lib/badger2040w.py @@ -28,6 +28,9 @@ UPDATE_MEDIUM = 1 UPDATE_FAST = 2 UPDATE_TURBO = 3 +LED = 22 +ENABLE_3V3 = 10 + WIDTH = 296 HEIGHT = 128 @@ -69,26 +72,39 @@ def system_speed(speed): class Badger2040W(): def __init__(self): self.display = PicoGraphics(DISPLAY_INKY_PACK) + self._led = machine.PWM(machine.Pin(LED)) + self._led.freq(1000) + self._led.duty_u16(0) def __getattr__(self, item): # Glue to redirect calls to PicoGraphics return getattr(self.display, item) def led(self, brightness): - pass + brightness = max(0, min(255, brightness)) + self._led.duty_u16(int(brightness * 256)) def invert(self, invert): - pass + raise RuntimeError("Display invert not supported in PicoGraphics.") def thickness(self, thickness): - print("Thickness!") + raise RuntimeError("Thickness not supported in PicoGraphics.") def halt(self): - pass + enable = machine.Pin(ENABLE_3V3, machine.Pin.OUT) + enable.off() + while not self.pressed_any(): + pass def pressed(self, button): return BUTTONS[button].value() == 1 + def pressed_any(self): + for button in BUTTONS.values(): + if button.value(): + return True + return False + @micropython.native def icon(self, data, index, data_w, icon_size, x, y): s_x = (index * icon_size) % data_w diff --git a/micropython/examples/badger2040w/uf2-manifest.txt b/micropython/examples/badger2040w/uf2-manifest.txt index 3e0c198b..6325b35e 100644 --- a/micropython/examples/badger2040w/uf2-manifest.txt +++ b/micropython/examples/badger2040w/uf2-manifest.txt @@ -3,4 +3,6 @@ lib/*.py examples/*.jpg examples/*.py images/*.jpg -images/*.txt \ No newline at end of file +images/*.txt +badges/*.txt +badges/*.jpg \ No newline at end of file From d8f9b81ecab3f691524433caf866b6abbf9a063e Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 19 Jan 2023 15:36:05 +0000 Subject: [PATCH 20/46] Badger2040W: Port ebook example. --- .../289-0-wind-in-the-willows-abridged.txt | 1341 +++++++++++++++++ .../examples/badger2040w/examples/ebook.py | 242 +++ .../examples/badger2040w/uf2-manifest.txt | 3 +- 3 files changed, 1585 insertions(+), 1 deletion(-) create mode 100644 micropython/examples/badger2040w/books/289-0-wind-in-the-willows-abridged.txt diff --git a/micropython/examples/badger2040w/books/289-0-wind-in-the-willows-abridged.txt b/micropython/examples/badger2040w/books/289-0-wind-in-the-willows-abridged.txt new file mode 100644 index 00000000..f6243fd9 --- /dev/null +++ b/micropython/examples/badger2040w/books/289-0-wind-in-the-willows-abridged.txt @@ -0,0 +1,1341 @@ +The Project Gutenberg eBook of The Wind in the Willows, by Kenneth Grahame + +This eBook is for the use of anyone anywhere in the United States and +most other parts of the world at no cost and with almost no restrictions +whatsoever. You may copy it, give it away or re-use it under the terms +of the Project Gutenberg License included with this eBook or online at +www.gutenberg.org. If you are not located in the United States, you +will have to check the laws of the country where you are located before +using this eBook. + +Title: The Wind in the Willows + +Author: Kenneth Grahame + +Release Date: July, 1995 [eBook #289] +[Most recently updated: May 15, 2021] + +Language: English + +Character set encoding: UTF-8 + +Produced by: Mike Lough and David Widger + +*** START OF THE PROJECT GUTENBERG EBOOK THE WIND IN THE WILLOWS *** + +[Illustration] + + + + +The Wind in the Willows + +by Kenneth Grahame + +Author Of “The Golden Age,” “Dream Days,” Etc. + + +Contents + + CHAPTER I. THE RIVER BANK + CHAPTER II. THE OPEN ROAD + + + + +I. +THE RIVER BANK + + +The Mole had been working very hard all the morning, spring-cleaning +his little home. First with brooms, then with dusters; then on ladders +and steps and chairs, with a brush and a pail of whitewash; till he had +dust in his throat and eyes, and splashes of whitewash all over his +black fur, and an aching back and weary arms. Spring was moving in the +air above and in the earth below and around him, penetrating even his +dark and lowly little house with its spirit of divine discontent and +longing. It was small wonder, then, that he suddenly flung down his +brush on the floor, said “Bother!” and “O blow!” and also “Hang +spring-cleaning!” and bolted out of the house without even waiting to +put on his coat. Something up above was calling him imperiously, and he +made for the steep little tunnel which answered in his case to the +gravelled carriage-drive owned by animals whose residences are nearer +to the sun and air. So he scraped and scratched and scrabbled and +scrooged and then he scrooged again and scrabbled and scratched and +scraped, working busily with his little paws and muttering to himself, +“Up we go! Up we go!” till at last, pop! his snout came out into the +sunlight, and he found himself rolling in the warm grass of a great +meadow. + +“This is fine!” he said to himself. “This is better than whitewashing!” +The sunshine struck hot on his fur, soft breezes caressed his heated +brow, and after the seclusion of the cellarage he had lived in so long +the carol of happy birds fell on his dulled hearing almost like a +shout. Jumping off all his four legs at once, in the joy of living and +the delight of spring without its cleaning, he pursued his way across +the meadow till he reached the hedge on the further side. + +“Hold up!” said an elderly rabbit at the gap. “Sixpence for the +privilege of passing by the private road!” He was bowled over in an +instant by the impatient and contemptuous Mole, who trotted along the +side of the hedge chaffing the other rabbits as they peeped hurriedly +from their holes to see what the row was about. “Onion-sauce! +Onion-sauce!” he remarked jeeringly, and was gone before they could +think of a thoroughly satisfactory reply. Then they all started +grumbling at each other. “How _stupid_ you are! Why didn’t you tell +him——” “Well, why didn’t _you_ say——” “You might have reminded him——” +and so on, in the usual way; but, of course, it was then much too late, +as is always the case. + +It all seemed too good to be true. Hither and thither through the +meadows he rambled busily, along the hedgerows, across the copses, +finding everywhere birds building, flowers budding, leaves +thrusting—everything happy, and progressive, and occupied. And instead +of having an uneasy conscience pricking him and whispering “whitewash!” +he somehow could only feel how jolly it was to be the only idle dog +among all these busy citizens. After all, the best part of a holiday is +perhaps not so much to be resting yourself, as to see all the other +fellows busy working. + +He thought his happiness was complete when, as he meandered aimlessly +along, suddenly he stood by the edge of a full-fed river. Never in his +life had he seen a river before—this sleek, sinuous, full-bodied +animal, chasing and chuckling, gripping things with a gurgle and +leaving them with a laugh, to fling itself on fresh playmates that +shook themselves free, and were caught and held again. All was a-shake +and a-shiver—glints and gleams and sparkles, rustle and swirl, chatter +and bubble. The Mole was bewitched, entranced, fascinated. By the side +of the river he trotted as one trots, when very small, by the side of a +man who holds one spell-bound by exciting stories; and when tired at +last, he sat on the bank, while the river still chattered on to him, a +babbling procession of the best stories in the world, sent from the +heart of the earth to be told at last to the insatiable sea. + +As he sat on the grass and looked across the river, a dark hole in the +bank opposite, just above the water’s edge, caught his eye, and +dreamily he fell to considering what a nice snug dwelling-place it +would make for an animal with few wants and fond of a bijou riverside +residence, above flood level and remote from noise and dust. As he +gazed, something bright and small seemed to twinkle down in the heart +of it, vanished, then twinkled once more like a tiny star. But it could +hardly be a star in such an unlikely situation; and it was too +glittering and small for a glow-worm. Then, as he looked, it winked at +him, and so declared itself to be an eye; and a small face began +gradually to grow up round it, like a frame round a picture. + +A brown little face, with whiskers. + +A grave round face, with the same twinkle in its eye that had first +attracted his notice. + +Small neat ears and thick silky hair. + +It was the Water Rat! + +Then the two animals stood and regarded each other cautiously. + +“Hullo, Mole!” said the Water Rat. + +“Hullo, Rat!” said the Mole. + +“Would you like to come over?” enquired the Rat presently. + +“Oh, its all very well to _talk_,” said the Mole, rather pettishly, he +being new to a river and riverside life and its ways. + +The Rat said nothing, but stooped and unfastened a rope and hauled on +it; then lightly stepped into a little boat which the Mole had not +observed. It was painted blue outside and white within, and was just +the size for two animals; and the Mole’s whole heart went out to it at +once, even though he did not yet fully understand its uses. + +The Rat sculled smartly across and made fast. Then he held up his +forepaw as the Mole stepped gingerly down. “Lean on that!” he said. +“Now then, step lively!” and the Mole to his surprise and rapture found +himself actually seated in the stern of a real boat. + +“This has been a wonderful day!” said he, as the Rat shoved off and +took to the sculls again. “Do you know, I’ve never been in a boat +before in all my life.” + +“What?” cried the Rat, open-mouthed: “Never been in a—you never—well +I—what have you been doing, then?” + +“Is it so nice as all that?” asked the Mole shyly, though he was quite +prepared to believe it as he leant back in his seat and surveyed the +cushions, the oars, the rowlocks, and all the fascinating fittings, and +felt the boat sway lightly under him. + +“Nice? It’s the _only_ thing,” said the Water Rat solemnly, as he leant +forward for his stroke. “Believe me, my young friend, there is +_nothing_—absolute nothing—half so much worth doing as simply messing +about in boats. Simply messing,” he went on dreamily: +“messing—about—in—boats; messing——” + +“Look ahead, Rat!” cried the Mole suddenly. + +It was too late. The boat struck the bank full tilt. The dreamer, the +joyous oarsman, lay on his back at the bottom of the boat, his heels in +the air. + +“—about in boats—or _with_ boats,” the Rat went on composedly, picking +himself up with a pleasant laugh. “In or out of ’em, it doesn’t matter. +Nothing seems really to matter, that’s the charm of it. Whether you get +away, or whether you don’t; whether you arrive at your destination or +whether you reach somewhere else, or whether you never get anywhere at +all, you’re always busy, and you never do anything in particular; and +when you’ve done it there’s always something else to do, and you can do +it if you like, but you’d much better not. Look here! If you’ve really +nothing else on hand this morning, supposing we drop down the river +together, and have a long day of it?” + +The Mole waggled his toes from sheer happiness, spread his chest with a +sigh of full contentment, and leaned back blissfully into the soft +cushions. “_What_ a day I’m having!” he said. “Let us start at once!” + +“Hold hard a minute, then!” said the Rat. He looped the painter through +a ring in his landing-stage, climbed up into his hole above, and after +a short interval reappeared staggering under a fat, wicker +luncheon-basket. + +“Shove that under your feet,” he observed to the Mole, as he passed it +down into the boat. Then he untied the painter and took the sculls +again. + +“What’s inside it?” asked the Mole, wriggling with curiosity. + +“There’s cold chicken inside it,” replied the Rat briefly; “ +coldtonguecoldhamcoldbeefpickledgherkinssaladfrenchrollscresssandwiches +pottedme atgingerbeerlemonadesodawater——” + +“O stop, stop,” cried the Mole in ecstacies: “This is too much!” + +“Do you really think so?” enquired the Rat seriously. “It’s only what I +always take on these little excursions; and the other animals are +always telling me that I’m a mean beast and cut it _very_ fine!” + +The Mole never heard a word he was saying. Absorbed in the new life he +was entering upon, intoxicated with the sparkle, the ripple, the scents +and the sounds and the sunlight, he trailed a paw in the water and +dreamed long waking dreams. The Water Rat, like the good little fellow +he was, sculled steadily on and forebore to disturb him. + +“I like your clothes awfully, old chap,” he remarked after some half an +hour or so had passed. “I’m going to get a black velvet smoking-suit +myself some day, as soon as I can afford it.” + +“I beg your pardon,” said the Mole, pulling himself together with an +effort. “You must think me very rude; but all this is so new to me. +So—this—is—a—River!” + +“_The_ River,” corrected the Rat. + +“And you really live by the river? What a jolly life!” + +“By it and with it and on it and in it,” said the Rat. “It’s brother +and sister to me, and aunts, and company, and food and drink, and +(naturally) washing. It’s my world, and I don’t want any other. What it +hasn’t got is not worth having, and what it doesn’t know is not worth +knowing. Lord! the times we’ve had together! Whether in winter or +summer, spring or autumn, it’s always got its fun and its excitements. +When the floods are on in February, and my cellars and basement are +brimming with drink that’s no good to me, and the brown water runs by +my best bedroom window; or again when it all drops away and, shows +patches of mud that smells like plum-cake, and the rushes and weed clog +the channels, and I can potter about dry shod over most of the bed of +it and find fresh food to eat, and things careless people have dropped +out of boats!” + +“But isn’t it a bit dull at times?” the Mole ventured to ask. “Just you +and the river, and no one else to pass a word with?” + +“No one else to—well, I mustn’t be hard on you,” said the Rat with +forbearance. “You’re new to it, and of course you don’t know. The bank +is so crowded nowadays that many people are moving away altogether: O +no, it isn’t what it used to be, at all. Otters, kingfishers, +dabchicks, moorhens, all of them about all day long and always wanting +you to _do_ something—as if a fellow had no business of his own to +attend to!” + +“What lies over _there?_” asked the Mole, waving a paw towards a +background of woodland that darkly framed the water-meadows on one side +of the river. + +“That? O, that’s just the Wild Wood,” said the Rat shortly. “We don’t +go there very much, we river-bankers.” + +“Aren’t they—aren’t they very _nice_ people in there?” said the Mole, a +trifle nervously. + +“W-e-ll,” replied the Rat, “let me see. The squirrels are all right. +_And_ the rabbits—some of ’em, but rabbits are a mixed lot. And then +there’s Badger, of course. He lives right in the heart of it; wouldn’t +live anywhere else, either, if you paid him to do it. Dear old Badger! +Nobody interferes with _him_. They’d better not,” he added +significantly. + +“Why, who _should_ interfere with him?” asked the Mole. + +“Well, of course—there—are others,” explained the Rat in a hesitating +sort of way. + +“Weasels—and stoats—and foxes—and so on. They’re all right in a way—I’m +very good friends with them—pass the time of day when we meet, and all +that—but they break out sometimes, there’s no denying it, and +then—well, you can’t really trust them, and that’s the fact.” + +The Mole knew well that it is quite against animal-etiquette to dwell +on possible trouble ahead, or even to allude to it; so he dropped the +subject. + +“And beyond the Wild Wood again?” he asked: “Where it’s all blue and +dim, and one sees what may be hills or perhaps they mayn’t, and +something like the smoke of towns, or is it only cloud-drift?” + +“Beyond the Wild Wood comes the Wide World,” said the Rat. “And that’s +something that doesn’t matter, either to you or me. I’ve never been +there, and I’m never going, nor you either, if you’ve got any sense at +all. Don’t ever refer to it again, please. Now then! Here’s our +backwater at last, where we’re going to lunch.” + +Leaving the main stream, they now passed into what seemed at first +sight like a little land-locked lake. Green turf sloped down to either +edge, brown snaky tree-roots gleamed below the surface of the quiet +water, while ahead of them the silvery shoulder and foamy tumble of a +weir, arm-in-arm with a restless dripping mill-wheel, that held up in +its turn a grey-gabled mill-house, filled the air with a soothing +murmur of sound, dull and smothery, yet with little clear voices +speaking up cheerfully out of it at intervals. It was so very beautiful +that the Mole could only hold up both forepaws and gasp, “O my! O my! O +my!” + +The Rat brought the boat alongside the bank, made her fast, helped the +still awkward Mole safely ashore, and swung out the luncheon-basket. +The Mole begged as a favour to be allowed to unpack it all by himself; +and the Rat was very pleased to indulge him, and to sprawl at full +length on the grass and rest, while his excited friend shook out the +table-cloth and spread it, took out all the mysterious packets one by +one and arranged their contents in due order, still gasping, “O my! O +my!” at each fresh revelation. When all was ready, the Rat said, “Now, +pitch in, old fellow!” and the Mole was indeed very glad to obey, for +he had started his spring-cleaning at a very early hour that morning, +as people _will_ do, and had not paused for bite or sup; and he had +been through a very great deal since that distant time which now seemed +so many days ago. + +“What are you looking at?” said the Rat presently, when the edge of +their hunger was somewhat dulled, and the Mole’s eyes were able to +wander off the table-cloth a little. + +“I am looking,” said the Mole, “at a streak of bubbles that I see +travelling along the surface of the water. That is a thing that strikes +me as funny.” + +“Bubbles? Oho!” said the Rat, and chirruped cheerily in an inviting +sort of way. + +A broad glistening muzzle showed itself above the edge of the bank, and +the Otter hauled himself out and shook the water from his coat. + +“Greedy beggars!” he observed, making for the provender. “Why didn’t +you invite me, Ratty?” + +“This was an impromptu affair,” explained the Rat. “By the way—my +friend Mr. Mole.” + +“Proud, I’m sure,” said the Otter, and the two animals were friends +forthwith. + +“Such a rumpus everywhere!” continued the Otter. “All the world seems +out on the river to-day. I came up this backwater to try and get a +moment’s peace, and then stumble upon you fellows!—At least—I beg +pardon—I don’t exactly mean that, you know.” + +There was a rustle behind them, proceeding from a hedge wherein last +year’s leaves still clung thick, and a stripy head, with high shoulders +behind it, peered forth on them. + +“Come on, old Badger!” shouted the Rat. + +The Badger trotted forward a pace or two; then grunted, “H’m! Company,” +and turned his back and disappeared from view. + +“That’s _just_ the sort of fellow he is!” observed the disappointed +Rat. “Simply hates Society! Now we shan’t see any more of him to-day. +Well, tell us, _who’s_ out on the river?” + +“Toad’s out, for one,” replied the Otter. “In his brand-new wager-boat; +new togs, new everything!” + +The two animals looked at each other and laughed. + +“Once, it was nothing but sailing,” said the Rat, “Then he tired of +that and took to punting. Nothing would please him but to punt all day +and every day, and a nice mess he made of it. Last year it was +house-boating, and we all had to go and stay with him in his +house-boat, and pretend we liked it. He was going to spend the rest of +his life in a house-boat. It’s all the same, whatever he takes up; he +gets tired of it, and starts on something fresh.” + +“Such a good fellow, too,” remarked the Otter reflectively: “But no +stability—especially in a boat!” + +From where they sat they could get a glimpse of the main stream across +the island that separated them; and just then a wager-boat flashed into +view, the rower—a short, stout figure—splashing badly and rolling a +good deal, but working his hardest. The Rat stood up and hailed him, +but Toad—for it was he—shook his head and settled sternly to his work. + +“He’ll be out of the boat in a minute if he rolls like that,” said the +Rat, sitting down again. + +“Of course he will,” chuckled the Otter. “Did I ever tell you that good +story about Toad and the lock-keeper? It happened this way. Toad....” + +An errant May-fly swerved unsteadily athwart the current in the +intoxicated fashion affected by young bloods of May-flies seeing life. +A swirl of water and a “cloop!” and the May-fly was visible no more. + +Neither was the Otter. + +The Mole looked down. The voice was still in his ears, but the turf +whereon he had sprawled was clearly vacant. Not an Otter to be seen, as +far as the distant horizon. + +But again there was a streak of bubbles on the surface of the river. + +The Rat hummed a tune, and the Mole recollected that animal-etiquette +forbade any sort of comment on the sudden disappearance of one’s +friends at any moment, for any reason or no reason whatever. + +“Well, well,” said the Rat, “I suppose we ought to be moving. I wonder +which of us had better pack the luncheon-basket?” He did not speak as +if he was frightfully eager for the treat. + +“O, please let me,” said the Mole. So, of course, the Rat let him. + +Packing the basket was not quite such pleasant work as unpacking the +basket. It never is. But the Mole was bent on enjoying everything, and +although just when he had got the basket packed and strapped up tightly +he saw a plate staring up at him from the grass, and when the job had +been done again the Rat pointed out a fork which anybody ought to have +seen, and last of all, behold! the mustard pot, which he had been +sitting on without knowing it—still, somehow, the thing got finished at +last, without much loss of temper. + +The afternoon sun was getting low as the Rat sculled gently homewards +in a dreamy mood, murmuring poetry-things over to himself, and not +paying much attention to Mole. But the Mole was very full of lunch, and +self-satisfaction, and pride, and already quite at home in a boat (so +he thought) and was getting a bit restless besides: and presently he +said, “Ratty! Please, _I_ want to row, now!” + +The Rat shook his head with a smile. “Not yet, my young friend,” he +said—“wait till you’ve had a few lessons. It’s not so easy as it +looks.” + +The Mole was quiet for a minute or two. But he began to feel more and +more jealous of Rat, sculling so strongly and so easily along, and his +pride began to whisper that he could do it every bit as well. He jumped +up and seized the sculls, so suddenly, that the Rat, who was gazing out +over the water and saying more poetry-things to himself, was taken by +surprise and fell backwards off his seat with his legs in the air for +the second time, while the triumphant Mole took his place and grabbed +the sculls with entire confidence. + +“Stop it, you _silly_ ass!” cried the Rat, from the bottom of the boat. +“You can’t do it! You’ll have us over!” + +The Mole flung his sculls back with a flourish, and made a great dig at +the water. He missed the surface altogether, his legs flew up above his +head, and he found himself lying on the top of the prostrate Rat. +Greatly alarmed, he made a grab at the side of the boat, and the next +moment—Sploosh! + +Over went the boat, and he found himself struggling in the river. + +O my, how cold the water was, and O, how _very_ wet it felt. How it +sang in his ears as he went down, down, down! How bright and welcome +the sun looked as he rose to the surface coughing and spluttering! How +black was his despair when he felt himself sinking again! Then a firm +paw gripped him by the back of his neck. It was the Rat, and he was +evidently laughing—the Mole could _feel_ him laughing, right down his +arm and through his paw, and so into his—the Mole’s—neck. + +The Rat got hold of a scull and shoved it under the Mole’s arm; then he +did the same by the other side of him and, swimming behind, propelled +the helpless animal to shore, hauled him out, and set him down on the +bank, a squashy, pulpy lump of misery. + +When the Rat had rubbed him down a bit, and wrung some of the wet out +of him, he said, “Now, then, old fellow! Trot up and down the +towing-path as hard as you can, till you’re warm and dry again, while I +dive for the luncheon-basket.” + +So the dismal Mole, wet without and ashamed within, trotted about till +he was fairly dry, while the Rat plunged into the water again, +recovered the boat, righted her and made her fast, fetched his floating +property to shore by degrees, and finally dived successfully for the +luncheon-basket and struggled to land with it. + +When all was ready for a start once more, the Mole, limp and dejected, +took his seat in the stern of the boat; and as they set off, he said in +a low voice, broken with emotion, “Ratty, my generous friend! I am very +sorry indeed for my foolish and ungrateful conduct. My heart quite +fails me when I think how I might have lost that beautiful +luncheon-basket. Indeed, I have been a complete ass, and I know it. +Will you overlook it this once and forgive me, and let things go on as +before?” + +“That’s all right, bless you!” responded the Rat cheerily. “What’s a +little wet to a Water Rat? I’m more in the water than out of it most +days. Don’t you think any more about it; and, look here! I really think +you had better come and stop with me for a little time. It’s very plain +and rough, you know—not like Toad’s house at all—but you haven’t seen +that yet; still, I can make you comfortable. And I’ll teach you to row, +and to swim, and you’ll soon be as handy on the water as any of us.” + +The Mole was so touched by his kind manner of speaking that he could +find no voice to answer him; and he had to brush away a tear or two +with the back of his paw. But the Rat kindly looked in another +direction, and presently the Mole’s spirits revived again, and he was +even able to give some straight back-talk to a couple of moorhens who +were sniggering to each other about his bedraggled appearance. + +When they got home, the Rat made a bright fire in the parlour, and +planted the Mole in an arm-chair in front of it, having fetched down a +dressing-gown and slippers for him, and told him river stories till +supper-time. Very thrilling stories they were, too, to an +earth-dwelling animal like Mole. Stories about weirs, and sudden +floods, and leaping pike, and steamers that flung hard bottles—at least +bottles were certainly flung, and _from_ steamers, so presumably _by_ +them; and about herons, and how particular they were whom they spoke +to; and about adventures down drains, and night-fishings with Otter, or +excursions far a-field with Badger. Supper was a most cheerful meal; +but very shortly afterwards a terribly sleepy Mole had to be escorted +upstairs by his considerate host, to the best bedroom, where he soon +laid his head on his pillow in great peace and contentment, knowing +that his new-found friend the River was lapping the sill of his window. + +This day was only the first of many similar ones for the emancipated +Mole, each of them longer and full of interest as the ripening summer +moved onward. He learnt to swim and to row, and entered into the joy of +running water; and with his ear to the reed-stems he caught, at +intervals, something of what the wind went whispering so constantly +among them. + + + + +II. +THE OPEN ROAD + + +“Ratty,” said the Mole suddenly, one bright summer morning, “if you +please, I want to ask you a favour.” + +The Rat was sitting on the river bank, singing a little song. He had +just composed it himself, so he was very taken up with it, and would +not pay proper attention to Mole or anything else. Since early morning +he had been swimming in the river, in company with his friends the +ducks. And when the ducks stood on their heads suddenly, as ducks will, +he would dive down and tickle their necks, just under where their chins +would be if ducks had chins, till they were forced to come to the +surface again in a hurry, spluttering and angry and shaking their +feathers at him, for it is impossible to say quite _all_ you feel when +your head is under water. At last they implored him to go away and +attend to his own affairs and leave them to mind theirs. So the Rat +went away, and sat on the river bank in the sun, and made up a song +about them, which he called + +“DUCKS’ DITTY.” + +All along the backwater, +Through the rushes tall, +Ducks are a-dabbling, +Up tails all! +Ducks’ tails, drakes’ tails, +Yellow feet a-quiver, +Yellow bills all out of sight +Busy in the river! + +Slushy green undergrowth +Where the roach swim— +Here we keep our larder, +Cool and full and dim. + +Everyone for what he likes! +_We_ like to be +Heads down, tails up, +Dabbling free! + +High in the blue above +Swifts whirl and call— +_We_ are down a-dabbling +Uptails all! + + +“I don’t know that I think so _very_ much of that little song, Rat,” +observed the Mole cautiously. He was no poet himself and didn’t care +who knew it; and he had a candid nature. + +“Nor don’t the ducks neither,” replied the Rat cheerfully. “They say, +‘_Why_ can’t fellows be allowed to do what they like _when_ they like +and _as_ they like, instead of other fellows sitting on banks and +watching them all the time and making remarks and poetry and things +about them? What _nonsense_ it all is!’ That’s what the ducks say.” + +“So it is, so it is,” said the Mole, with great heartiness. + +“No, it isn’t!” cried the Rat indignantly. + +“Well then, it isn’t, it isn’t,” replied the Mole soothingly. “But what +I wanted to ask you was, won’t you take me to call on Mr. Toad? I’ve +heard so much about him, and I do so want to make his acquaintance.” + +“Why, certainly,” said the good-natured Rat, jumping to his feet and +dismissing poetry from his mind for the day. “Get the boat out, and +we’ll paddle up there at once. It’s never the wrong time to call on +Toad. Early or late he’s always the same fellow. Always good-tempered, +always glad to see you, always sorry when you go!” + +“He must be a very nice animal,” observed the Mole, as he got into the +boat and took the sculls, while the Rat settled himself comfortably in +the stern. + +“He is indeed the best of animals,” replied Rat. “So simple, so +good-natured, and so affectionate. Perhaps he’s not very clever—we +can’t all be geniuses; and it may be that he is both boastful and +conceited. But he has got some great qualities, has Toady.” + +Rounding a bend in the river, they came in sight of a handsome, +dignified old house of mellowed red brick, with well-kept lawns +reaching down to the water’s edge. + +“There’s Toad Hall,” said the Rat; “and that creek on the left, where +the notice-board says, ‘Private. No landing allowed,’ leads to his +boat-house, where we’ll leave the boat. The stables are over there to +the right. That’s the banqueting-hall you’re looking at now—very old, +that is. Toad is rather rich, you know, and this is really one of the +nicest houses in these parts, though we never admit as much to Toad.” + +They glided up the creek, and the Mole shipped his sculls as they +passed into the shadow of a large boat-house. Here they saw many +handsome boats, slung from the cross beams or hauled up on a slip, but +none in the water; and the place had an unused and a deserted air. + +The Rat looked around him. “I understand,” said he. “Boating is played +out. He’s tired of it, and done with it. I wonder what new fad he has +taken up now? Come along and let’s look him up. We shall hear all about +it quite soon enough.” + +They disembarked, and strolled across the gay flower-decked lawns in +search of Toad, whom they presently happened upon resting in a wicker +garden-chair, with a pre-occupied expression of face, and a large map +spread out on his knees. + +“Hooray!” he cried, jumping up on seeing them, “this is splendid!” He +shook the paws of both of them warmly, never waiting for an +introduction to the Mole. “How _kind_ of you!” he went on, dancing +round them. “I was just going to send a boat down the river for you, +Ratty, with strict orders that you were to be fetched up here at once, +whatever you were doing. I want you badly—both of you. Now what will +you take? Come inside and have something! You don’t know how lucky it +is, your turning up just now!” + +“Let’s sit quiet a bit, Toady!” said the Rat, throwing himself into an +easy chair, while the Mole took another by the side of him and made +some civil remark about Toad’s “delightful residence.” + +“Finest house on the whole river,” cried Toad boisterously. “Or +anywhere else, for that matter,” he could not help adding. + +Here the Rat nudged the Mole. Unfortunately the Toad saw him do it, and +turned very red. There was a moment’s painful silence. Then Toad burst +out laughing. “All right, Ratty,” he said. “It’s only my way, you know. +And it’s not such a very bad house, is it? You know you rather like it +yourself. Now, look here. Let’s be sensible. You are the very animals I +wanted. You’ve got to help me. It’s most important!” + +“It’s about your rowing, I suppose,” said the Rat, with an innocent +air. “You’re getting on fairly well, though you splash a good bit +still. With a great deal of patience, and any quantity of coaching, you +may——” + +“O, pooh! boating!” interrupted the Toad, in great disgust. “Silly +boyish amusement. I’ve given that up _long_ ago. Sheer waste of time, +that’s what it is. It makes me downright sorry to see you fellows, who +ought to know better, spending all your energies in that aimless +manner. No, I’ve discovered the real thing, the only genuine occupation +for a life time. I propose to devote the remainder of mine to it, and +can only regret the wasted years that lie behind me, squandered in +trivialities. Come with me, dear Ratty, and your amiable friend also, +if he will be so very good, just as far as the stable-yard, and you +shall see what you shall see!” + +He led the way to the stable-yard accordingly, the Rat following with a +most mistrustful expression; and there, drawn out of the coach house +into the open, they saw a gipsy caravan, shining with newness, painted +a canary-yellow picked out with green, and red wheels. + +“There you are!” cried the Toad, straddling and expanding himself. +“There’s real life for you, embodied in that little cart. The open +road, the dusty highway, the heath, the common, the hedgerows, the +rolling downs! Camps, villages, towns, cities! Here to-day, up and off +to somewhere else to-morrow! Travel, change, interest, excitement! The +whole world before you, and a horizon that’s always changing! And mind! +this is the very finest cart of its sort that was ever built, without +any exception. Come inside and look at the arrangements. Planned ’em +all myself, I did!” + +The Mole was tremendously interested and excited, and followed him +eagerly up the steps and into the interior of the caravan. The Rat only +snorted and thrust his hands deep into his pockets, remaining where he +was. + +It was indeed very compact and comfortable. Little sleeping bunks—a +little table that folded up against the wall—a cooking-stove, lockers, +bookshelves, a bird-cage with a bird in it; and pots, pans, jugs and +kettles of every size and variety. + +“All complete!” said the Toad triumphantly, pulling open a locker. “You +see—biscuits, potted lobster, sardines—everything you can possibly +want. Soda-water here—baccy there—letter-paper, bacon, jam, cards and +dominoes—you’ll find,” he continued, as they descended the steps again, +“you’ll find that nothing what ever has been forgotten, when we make +our start this afternoon.” + +“I beg your pardon,” said the Rat slowly, as he chewed a straw, “but +did I overhear you say something about ‘_we_,’ and ‘_start_,’ and +‘_this afternoon?_’” + +“Now, you dear good old Ratty,” said Toad, imploringly, “don’t begin +talking in that stiff and sniffy sort of way, because you know you’ve +_got_ to come. I can’t possibly manage without you, so please consider +it settled, and don’t argue—it’s the one thing I can’t stand. You +surely don’t mean to stick to your dull fusty old river all your life, +and just live in a hole in a bank, and _boat?_ I want to show you the +world! I’m going to make an _animal_ of you, my boy!” + +“I don’t care,” said the Rat, doggedly. “I’m not coming, and that’s +flat. And I _am_ going to stick to my old river, _and_ live in a hole, +_and_ boat, as I’ve always done. And what’s more, Mole’s going to stick +to me and do as I do, aren’t you, Mole?” + +“Of course I am,” said the Mole, loyally. “I’ll always stick to you, +Rat, and what you say is to be—has got to be. All the same, it sounds +as if it might have been—well, rather fun, you know!” he added, +wistfully. Poor Mole! The Life Adventurous was so new a thing to him, +and so thrilling; and this fresh aspect of it was so tempting; and he +had fallen in love at first sight with the canary-coloured cart and all +its little fitments. + +The Rat saw what was passing in his mind, and wavered. He hated +disappointing people, and he was fond of the Mole, and would do almost +anything to oblige him. Toad was watching both of them closely. + +“Come along in, and have some lunch,” he said, diplomatically, “and +we’ll talk it over. We needn’t decide anything in a hurry. Of course, +_I_ don’t really care. I only want to give pleasure to you fellows. +‘Live for others!’ That’s my motto in life.” + +During luncheon—which was excellent, of course, as everything at Toad +Hall always was—the Toad simply let himself go. Disregarding the Rat, +he proceeded to play upon the inexperienced Mole as on a harp. +Naturally a voluble animal, and always mastered by his imagination, he +painted the prospects of the trip and the joys of the open life and the +roadside in such glowing colours that the Mole could hardly sit in his +chair for excitement. Somehow, it soon seemed taken for granted by all +three of them that the trip was a settled thing; and the Rat, though +still unconvinced in his mind, allowed his good-nature to over-ride his +personal objections. He could not bear to disappoint his two friends, +who were already deep in schemes and anticipations, planning out each +day’s separate occupation for several weeks ahead. + +When they were quite ready, the now triumphant Toad led his companions +to the paddock and set them to capture the old grey horse, who, without +having been consulted, and to his own extreme annoyance, had been told +off by Toad for the dustiest job in this dusty expedition. He frankly +preferred the paddock, and took a deal of catching. Meantime Toad +packed the lockers still tighter with necessaries, and hung nosebags, +nets of onions, bundles of hay, and baskets from the bottom of the +cart. At last the horse was caught and harnessed, and they set off, all +talking at once, each animal either trudging by the side of the cart or +sitting on the shaft, as the humour took him. It was a golden +afternoon. The smell of the dust they kicked up was rich and +satisfying; out of thick orchards on either side the road, birds called +and whistled to them cheerily; good-natured wayfarers, passing them, +gave them “Good-day,” or stopped to say nice things about their +beautiful cart; and rabbits, sitting at their front doors in the +hedgerows, held up their fore-paws, and said, “O my! O my! O my!” + +Late in the evening, tired and happy and miles from home, they drew up +on a remote common far from habitations, turned the horse loose to +graze, and ate their simple supper sitting on the grass by the side of +the cart. Toad talked big about all he was going to do in the days to +come, while stars grew fuller and larger all around them, and a yellow +moon, appearing suddenly and silently from nowhere in particular, came +to keep them company and listen to their talk. At last they turned in +to their little bunks in the cart; and Toad, kicking out his legs, +sleepily said, “Well, good night, you fellows! This is the real life +for a gentleman! Talk about your old river!” + +“I _don’t_ talk about my river,” replied the patient Rat. “You _know_ I +don’t, Toad. But I _think_ about it,” he added pathetically, in a lower +tone: “I think about it—all the time!” + +The Mole reached out from under his blanket, felt for the Rat’s paw in +the darkness, and gave it a squeeze. “I’ll do whatever you like, +Ratty,” he whispered. “Shall we run away to-morrow morning, quite +early—_very_ early—and go back to our dear old hole on the river?” + +“No, no, we’ll see it out,” whispered back the Rat. “Thanks awfully, +but I ought to stick by Toad till this trip is ended. It wouldn’t be +safe for him to be left to himself. It won’t take very long. His fads +never do. Good night!” + +The end was indeed nearer than even the Rat suspected. + +After so much open air and excitement the Toad slept very soundly, and +no amount of shaking could rouse him out of bed next morning. So the +Mole and Rat turned to, quietly and manfully, and while the Rat saw to +the horse, and lit a fire, and cleaned last night’s cups and platters, +and got things ready for breakfast, the Mole trudged off to the nearest +village, a long way off, for milk and eggs and various necessaries the +Toad had, of course, forgotten to provide. The hard work had all been +done, and the two animals were resting, thoroughly exhausted, by the +time Toad appeared on the scene, fresh and gay, remarking what a +pleasant easy life it was they were all leading now, after the cares +and worries and fatigues of housekeeping at home. + +They had a pleasant ramble that day over grassy downs and along narrow +by-lanes, and camped as before, on a common, only this time the two +guests took care that Toad should do his fair share of work. In +consequence, when the time came for starting next morning, Toad was by +no means so rapturous about the simplicity of the primitive life, and +indeed attempted to resume his place in his bunk, whence he was hauled +by force. Their way lay, as before, across country by narrow lanes, and +it was not till the afternoon that they came out on the high-road, +their first high-road; and there disaster, fleet and unforeseen, sprang +out on them—disaster momentous indeed to their expedition, but simply +overwhelming in its effect on the after-career of Toad. + +They were strolling along the high-road easily, the Mole by the horse’s +head, talking to him, since the horse had complained that he was being +frightfully left out of it, and nobody considered him in the least; the +Toad and the Water Rat walking behind the cart talking together—at +least Toad was talking, and Rat was saying at intervals, “Yes, +precisely; and what did _you_ say to _him?_”—and thinking all the time +of something very different, when far behind them they heard a faint +warning hum; like the drone of a distant bee. Glancing back, they saw a +small cloud of dust, with a dark centre of energy, advancing on them at +incredible speed, while from out the dust a faint “Poop-poop!” wailed +like an uneasy animal in pain. Hardly regarding it, they turned to +resume their conversation, when in an instant (as it seemed) the +peaceful scene was changed, and with a blast of wind and a whirl of +sound that made them jump for the nearest ditch, It was on them! The +“Poop-poop” rang with a brazen shout in their ears, they had a moment’s +glimpse of an interior of glittering plate-glass and rich morocco, and +the magnificent motor-car, immense, breath-snatching, passionate, with +its pilot tense and hugging his wheel, possessed all earth and air for +the fraction of a second, flung an enveloping cloud of dust that +blinded and enwrapped them utterly, and then dwindled to a speck in the +far distance, changed back into a droning bee once more. + +The old grey horse, dreaming, as he plodded along, of his quiet +paddock, in a new raw situation such as this simply abandoned himself +to his natural emotions. Rearing, plunging, backing steadily, in spite +of all the Mole’s efforts at his head, and all the Mole’s lively +language directed at his better feelings, he drove the cart backwards +towards the deep ditch at the side of the road. It wavered an +instant—then there was a heartrending crash—and the canary-coloured +cart, their pride and their joy, lay on its side in the ditch, an +irredeemable wreck. + +The Rat danced up and down in the road, simply transported with +passion. “You villains!” he shouted, shaking both fists, “You +scoundrels, you highwaymen, you—you—roadhogs!—I’ll have the law of you! +I’ll report you! I’ll take you through all the Courts!” His +home-sickness had quite slipped away from him, and for the moment he +was the skipper of the canary-coloured vessel driven on a shoal by the +reckless jockeying of rival mariners, and he was trying to recollect +all the fine and biting things he used to say to masters of +steam-launches when their wash, as they drove too near the bank, used +to flood his parlour-carpet at home. + +Toad sat straight down in the middle of the dusty road, his legs +stretched out before him, and stared fixedly in the direction of the +disappearing motor-car. He breathed short, his face wore a placid +satisfied expression, and at intervals he faintly murmured “Poop-poop!” + +The Mole was busy trying to quiet the horse, which he succeeded in +doing after a time. Then he went to look at the cart, on its side in +the ditch. It was indeed a sorry sight. Panels and windows smashed, +axles hopelessly bent, one wheel off, sardine-tins scattered over the +wide world, and the bird in the bird-cage sobbing pitifully and calling +to be let out. + +The Rat came to help him, but their united efforts were not sufficient +to right the cart. “Hi! Toad!” they cried. “Come and bear a hand, can’t +you!” + +The Toad never answered a word, or budged from his seat in the road; so +they went to see what was the matter with him. They found him in a sort +of a trance, a happy smile on his face, his eyes still fixed on the +dusty wake of their destroyer. At intervals he was still heard to +murmur “Poop-poop!” + +The Rat shook him by the shoulder. “Are you coming to help us, Toad?” +he demanded sternly. + +“Glorious, stirring sight!” murmured Toad, never offering to move. “The +poetry of motion! The _real_ way to travel! The _only_ way to travel! +Here to-day—in next week to-morrow! Villages skipped, towns and cities +jumped—always somebody else’s horizon! O bliss! O poop-poop! O my! O +my!” + +“O _stop_ being an ass, Toad!” cried the Mole despairingly. + +“And to think I never _knew!_” went on the Toad in a dreamy monotone. +“All those wasted years that lie behind me, I never knew, never even +_dreamt!_ But _now_—but now that I know, now that I fully realise! O +what a flowery track lies spread before me, henceforth! What +dust-clouds shall spring up behind me as I speed on my reckless way! +What carts I shall fling carelessly into the ditch in the wake of my +magnificent onset! Horrid little carts—common carts—canary-coloured +carts!” + +“What are we to do with him?” asked the Mole of the Water Rat. + +“Nothing at all,” replied the Rat firmly. “Because there is really +nothing to be done. You see, I know him from of old. He is now +possessed. He has got a new craze, and it always takes him that way, in +its first stage. He’ll continue like that for days now, like an animal +walking in a happy dream, quite useless for all practical purposes. +Never mind him. Let’s go and see what there is to be done about the +cart.” + +A careful inspection showed them that, even if they succeeded in +righting it by themselves, the cart would travel no longer. The axles +were in a hopeless state, and the missing wheel was shattered into +pieces. + +The Rat knotted the horse’s reins over his back and took him by the +head, carrying the bird cage and its hysterical occupant in the other +hand. “Come on!” he said grimly to the Mole. “It’s five or six miles to +the nearest town, and we shall just have to walk it. The sooner we make +a start the better.” + +“But what about Toad?” asked the Mole anxiously, as they set off +together. “We can’t leave him here, sitting in the middle of the road +by himself, in the distracted state he’s in! It’s not safe. Supposing +another Thing were to come along?” + +“O, _bother_ Toad,” said the Rat savagely; “I’ve done with him!” + +They had not proceeded very far on their way, however, when there was a +pattering of feet behind them, and Toad caught them up and thrust a paw +inside the elbow of each of them; still breathing short and staring +into vacancy. + +“Now, look here, Toad!” said the Rat sharply: “as soon as we get to the +town, you’ll have to go straight to the police-station, and see if they +know anything about that motor-car and who it belongs to, and lodge a +complaint against it. And then you’ll have to go to a blacksmith’s or a +wheelwright’s and arrange for the cart to be fetched and mended and put +to rights. It’ll take time, but it’s not quite a hopeless smash. +Meanwhile, the Mole and I will go to an inn and find comfortable rooms +where we can stay till the cart’s ready, and till your nerves have +recovered their shock.” + +“Police-station! Complaint!” murmured Toad dreamily. “Me _complain_ of +that beautiful, that heavenly vision that has been vouchsafed me! +_Mend_ the _cart!_ I’ve done with carts for ever. I never want to see +the cart, or to hear of it, again. O, Ratty! You can’t think how +obliged I am to you for consenting to come on this trip! I wouldn’t +have gone without you, and then I might never have seen that—that swan, +that sunbeam, that thunderbolt! I might never have heard that +entrancing sound, or smelt that bewitching smell! I owe it all to you, +my best of friends!” + +The Rat turned from him in despair. “You see what it is?” he said to +the Mole, addressing him across Toad’s head: “He’s quite hopeless. I +give it up—when we get to the town we’ll go to the railway station, and +with luck we may pick up a train there that’ll get us back to riverbank +to-night. And if ever you catch me going a-pleasuring with this +provoking animal again!”—He snorted, and during the rest of that weary +trudge addressed his remarks exclusively to Mole. + +On reaching the town they went straight to the station and deposited +Toad in the second-class waiting-room, giving a porter twopence to keep +a strict eye on him. They then left the horse at an inn stable, and +gave what directions they could about the cart and its contents. +Eventually, a slow train having landed them at a station not very far +from Toad Hall, they escorted the spell-bound, sleep-walking Toad to +his door, put him inside it, and instructed his housekeeper to feed +him, undress him, and put him to bed. Then they got out their boat from +the boat-house, sculled down the river home, and at a very late hour +sat down to supper in their own cosy riverside parlour, to the Rat’s +great joy and contentment. + +The following evening the Mole, who had risen late and taken things +very easy all day, was sitting on the bank fishing, when the Rat, who +had been looking up his friends and gossiping, came strolling along to +find him. “Heard the news?” he said. “There’s nothing else being talked +about, all along the river bank. Toad went up to Town by an early train +this morning. And he has ordered a large and very expensive motor-car.” + + + +*** END OF THE PROJECT GUTENBERG EBOOK THE WIND IN THE WILLOWS *** + +***** This file should be named 289-0.txt or 289-0.zip ***** +This and all associated files of various formats will be found in: + https://www.gutenberg.org/2/8/289/ + +Updated editions will replace the previous one--the old editions will +be renamed. + +Creating the works from print editions not protected by U.S. copyright +law means that no one owns a United States copyright in these works, +so the Foundation (and you!) can copy and distribute it in the +United States without permission and without paying copyright +royalties. Special rules, set forth in the General Terms of Use part +of this license, apply to copying and distributing Project +Gutenberg-tm electronic works to protect the PROJECT GUTENBERG-tm +concept and trademark. Project Gutenberg is a registered trademark, +and may not be used if you charge for an eBook, except by following +the terms of the trademark license, including paying royalties for use +of the Project Gutenberg trademark. If you do not charge anything for +copies of this eBook, complying with the trademark license is very +easy. You may use this eBook for nearly any purpose such as creation +of derivative works, reports, performances and research. Project +Gutenberg eBooks may be modified and printed and given away--you may +do practically ANYTHING in the United States with eBooks not protected +by U.S. copyright law. Redistribution is subject to the trademark +license, especially commercial redistribution. + +START: FULL LICENSE + +THE FULL PROJECT GUTENBERG LICENSE +PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK + +To protect the Project Gutenberg-tm mission of promoting the free +distribution of electronic works, by using or distributing this work +(or any other work associated in any way with the phrase "Project +Gutenberg"), you agree to comply with all the terms of the Full +Project Gutenberg-tm License available with this file or online at +www.gutenberg.org/license. + +Section 1. General Terms of Use and Redistributing Project +Gutenberg-tm electronic works + +1.A. By reading or using any part of this Project Gutenberg-tm +electronic work, you indicate that you have read, understand, agree to +and accept all the terms of this license and intellectual property +(trademark/copyright) agreement. If you do not agree to abide by all +the terms of this agreement, you must cease using and return or +destroy all copies of Project Gutenberg-tm electronic works in your +possession. If you paid a fee for obtaining a copy of or access to a +Project Gutenberg-tm electronic work and you do not agree to be bound +by the terms of this agreement, you may obtain a refund from the +person or entity to whom you paid the fee as set forth in paragraph +1.E.8. + +1.B. "Project Gutenberg" is a registered trademark. It may only be +used on or associated in any way with an electronic work by people who +agree to be bound by the terms of this agreement. There are a few +things that you can do with most Project Gutenberg-tm electronic works +even without complying with the full terms of this agreement. See +paragraph 1.C below. There are a lot of things you can do with Project +Gutenberg-tm electronic works if you follow the terms of this +agreement and help preserve free future access to Project Gutenberg-tm +electronic works. See paragraph 1.E below. + +1.C. The Project Gutenberg Literary Archive Foundation ("the +Foundation" or PGLAF), owns a compilation copyright in the collection +of Project Gutenberg-tm electronic works. Nearly all the individual +works in the collection are in the public domain in the United +States. If an individual work is unprotected by copyright law in the +United States and you are located in the United States, we do not +claim a right to prevent you from copying, distributing, performing, +displaying or creating derivative works based on the work as long as +all references to Project Gutenberg are removed. Of course, we hope +that you will support the Project Gutenberg-tm mission of promoting +free access to electronic works by freely sharing Project Gutenberg-tm +works in compliance with the terms of this agreement for keeping the +Project Gutenberg-tm name associated with the work. You can easily +comply with the terms of this agreement by keeping this work in the +same format with its attached full Project Gutenberg-tm License when +you share it without charge with others. + +1.D. The copyright laws of the place where you are located also govern +what you can do with this work. Copyright laws in most countries are +in a constant state of change. If you are outside the United States, +check the laws of your country in addition to the terms of this +agreement before downloading, copying, displaying, performing, +distributing or creating derivative works based on this work or any +other Project Gutenberg-tm work. The Foundation makes no +representations concerning the copyright status of any work in any +country other than the United States. + +1.E. Unless you have removed all references to Project Gutenberg: + +1.E.1. The following sentence, with active links to, or other +immediate access to, the full Project Gutenberg-tm License must appear +prominently whenever any copy of a Project Gutenberg-tm work (any work +on which the phrase "Project Gutenberg" appears, or with which the +phrase "Project Gutenberg" is associated) is accessed, displayed, +performed, viewed, copied or distributed: + + This eBook is for the use of anyone anywhere in the United States and + most other parts of the world at no cost and with almost no + restrictions whatsoever. You may copy it, give it away or re-use it + under the terms of the Project Gutenberg License included with this + eBook or online at www.gutenberg.org. If you are not located in the + United States, you will have to check the laws of the country where + you are located before using this eBook. + +1.E.2. If an individual Project Gutenberg-tm electronic work is +derived from texts not protected by U.S. copyright law (does not +contain a notice indicating that it is posted with permission of the +copyright holder), the work can be copied and distributed to anyone in +the United States without paying any fees or charges. If you are +redistributing or providing access to a work with the phrase "Project +Gutenberg" associated with or appearing on the work, you must comply +either with the requirements of paragraphs 1.E.1 through 1.E.7 or +obtain permission for the use of the work and the Project Gutenberg-tm +trademark as set forth in paragraphs 1.E.8 or 1.E.9. + +1.E.3. If an individual Project Gutenberg-tm electronic work is posted +with the permission of the copyright holder, your use and distribution +must comply with both paragraphs 1.E.1 through 1.E.7 and any +additional terms imposed by the copyright holder. Additional terms +will be linked to the Project Gutenberg-tm License for all works +posted with the permission of the copyright holder found at the +beginning of this work. + +1.E.4. Do not unlink or detach or remove the full Project Gutenberg-tm +License terms from this work, or any files containing a part of this +work or any other work associated with Project Gutenberg-tm. + +1.E.5. Do not copy, display, perform, distribute or redistribute this +electronic work, or any part of this electronic work, without +prominently displaying the sentence set forth in paragraph 1.E.1 with +active links or immediate access to the full terms of the Project +Gutenberg-tm License. + +1.E.6. You may convert to and distribute this work in any binary, +compressed, marked up, nonproprietary or proprietary form, including +any word processing or hypertext form. However, if you provide access +to or distribute copies of a Project Gutenberg-tm work in a format +other than "Plain Vanilla ASCII" or other format used in the official +version posted on the official Project Gutenberg-tm website +(www.gutenberg.org), you must, at no additional cost, fee or expense +to the user, provide a copy, a means of exporting a copy, or a means +of obtaining a copy upon request, of the work in its original "Plain +Vanilla ASCII" or other form. Any alternate format must include the +full Project Gutenberg-tm License as specified in paragraph 1.E.1. + +1.E.7. Do not charge a fee for access to, viewing, displaying, +performing, copying or distributing any Project Gutenberg-tm works +unless you comply with paragraph 1.E.8 or 1.E.9. + +1.E.8. You may charge a reasonable fee for copies of or providing +access to or distributing Project Gutenberg-tm electronic works +provided that: + +* You pay a royalty fee of 20% of the gross profits you derive from + the use of Project Gutenberg-tm works calculated using the method + you already use to calculate your applicable taxes. The fee is owed + to the owner of the Project Gutenberg-tm trademark, but he has + agreed to donate royalties under this paragraph to the Project + Gutenberg Literary Archive Foundation. Royalty payments must be paid + within 60 days following each date on which you prepare (or are + legally required to prepare) your periodic tax returns. Royalty + payments should be clearly marked as such and sent to the Project + Gutenberg Literary Archive Foundation at the address specified in + Section 4, "Information about donations to the Project Gutenberg + Literary Archive Foundation." + +* You provide a full refund of any money paid by a user who notifies + you in writing (or by e-mail) within 30 days of receipt that s/he + does not agree to the terms of the full Project Gutenberg-tm + License. You must require such a user to return or destroy all + copies of the works possessed in a physical medium and discontinue + all use of and all access to other copies of Project Gutenberg-tm + works. + +* You provide, in accordance with paragraph 1.F.3, a full refund of + any money paid for a work or a replacement copy, if a defect in the + electronic work is discovered and reported to you within 90 days of + receipt of the work. + +* You comply with all other terms of this agreement for free + distribution of Project Gutenberg-tm works. + +1.E.9. If you wish to charge a fee or distribute a Project +Gutenberg-tm electronic work or group of works on different terms than +are set forth in this agreement, you must obtain permission in writing +from the Project Gutenberg Literary Archive Foundation, the manager of +the Project Gutenberg-tm trademark. Contact the Foundation as set +forth in Section 3 below. + +1.F. + +1.F.1. Project Gutenberg volunteers and employees expend considerable +effort to identify, do copyright research on, transcribe and proofread +works not protected by U.S. copyright law in creating the Project +Gutenberg-tm collection. Despite these efforts, Project Gutenberg-tm +electronic works, and the medium on which they may be stored, may +contain "Defects," such as, but not limited to, incomplete, inaccurate +or corrupt data, transcription errors, a copyright or other +intellectual property infringement, a defective or damaged disk or +other medium, a computer virus, or computer codes that damage or +cannot be read by your equipment. + +1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the "Right +of Replacement or Refund" described in paragraph 1.F.3, the Project +Gutenberg Literary Archive Foundation, the owner of the Project +Gutenberg-tm trademark, and any other party distributing a Project +Gutenberg-tm electronic work under this agreement, disclaim all +liability to you for damages, costs and expenses, including legal +fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT +LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE +PROVIDED IN PARAGRAPH 1.F.3. YOU AGREE THAT THE FOUNDATION, THE +TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE +LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR +INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH +DAMAGE. + +1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a +defect in this electronic work within 90 days of receiving it, you can +receive a refund of the money (if any) you paid for it by sending a +written explanation to the person you received the work from. If you +received the work on a physical medium, you must return the medium +with your written explanation. The person or entity that provided you +with the defective work may elect to provide a replacement copy in +lieu of a refund. If you received the work electronically, the person +or entity providing it to you may choose to give you a second +opportunity to receive the work electronically in lieu of a refund. If +the second copy is also defective, you may demand a refund in writing +without further opportunities to fix the problem. + +1.F.4. Except for the limited right of replacement or refund set forth +in paragraph 1.F.3, this work is provided to you 'AS-IS', WITH NO +OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PURPOSE. + +1.F.5. Some states do not allow disclaimers of certain implied +warranties or the exclusion or limitation of certain types of +damages. If any disclaimer or limitation set forth in this agreement +violates the law of the state applicable to this agreement, the +agreement shall be interpreted to make the maximum disclaimer or +limitation permitted by the applicable state law. The invalidity or +unenforceability of any provision of this agreement shall not void the +remaining provisions. + +1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the +trademark owner, any agent or employee of the Foundation, anyone +providing copies of Project Gutenberg-tm electronic works in +accordance with this agreement, and any volunteers associated with the +production, promotion and distribution of Project Gutenberg-tm +electronic works, harmless from all liability, costs and expenses, +including legal fees, that arise directly or indirectly from any of +the following which you do or cause to occur: (a) distribution of this +or any Project Gutenberg-tm work, (b) alteration, modification, or +additions or deletions to any Project Gutenberg-tm work, and (c) any +Defect you cause. + +Section 2. Information about the Mission of Project Gutenberg-tm + +Project Gutenberg-tm is synonymous with the free distribution of +electronic works in formats readable by the widest variety of +computers including obsolete, old, middle-aged and new computers. It +exists because of the efforts of hundreds of volunteers and donations +from people in all walks of life. + +Volunteers and financial support to provide volunteers with the +assistance they need are critical to reaching Project Gutenberg-tm's +goals and ensuring that the Project Gutenberg-tm collection will +remain freely available for generations to come. In 2001, the Project +Gutenberg Literary Archive Foundation was created to provide a secure +and permanent future for Project Gutenberg-tm and future +generations. To learn more about the Project Gutenberg Literary +Archive Foundation and how your efforts and donations can help, see +Sections 3 and 4 and the Foundation information page at +www.gutenberg.org + +Section 3. Information about the Project Gutenberg Literary +Archive Foundation + +The Project Gutenberg Literary Archive Foundation is a non-profit +501(c)(3) educational corporation organized under the laws of the +state of Mississippi and granted tax exempt status by the Internal +Revenue Service. The Foundation's EIN or federal tax identification +number is 64-6221541. Contributions to the Project Gutenberg Literary +Archive Foundation are tax deductible to the full extent permitted by +U.S. federal laws and your state's laws. + +The Foundation's business office is located at 809 North 1500 West, +Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up +to date contact information can be found at the Foundation's website +and official page at www.gutenberg.org/contact + +Section 4. Information about Donations to the Project Gutenberg +Literary Archive Foundation + +Project Gutenberg-tm depends upon and cannot survive without +widespread public support and donations to carry out its mission of +increasing the number of public domain and licensed works that can be +freely distributed in machine-readable form accessible by the widest +array of equipment including outdated equipment. Many small donations +($1 to $5,000) are particularly important to maintaining tax exempt +status with the IRS. + +The Foundation is committed to complying with the laws regulating +charities and charitable donations in all 50 states of the United +States. Compliance requirements are not uniform and it takes a +considerable effort, much paperwork and many fees to meet and keep up +with these requirements. We do not solicit donations in locations +where we have not received written confirmation of compliance. To SEND +DONATIONS or determine the status of compliance for any particular +state visit www.gutenberg.org/donate + +While we cannot and do not solicit contributions from states where we +have not met the solicitation requirements, we know of no prohibition +against accepting unsolicited donations from donors in such states who +approach us with offers to donate. + +International donations are gratefully accepted, but we cannot make +any statements concerning tax treatment of donations received from +outside the United States. U.S. laws alone swamp our small staff. + +Please check the Project Gutenberg web pages for current donation +methods and addresses. Donations are accepted in a number of other +ways including checks, online payments and credit card donations. To +donate, please visit: www.gutenberg.org/donate + +Section 5. General Information About Project Gutenberg-tm electronic works + +Professor Michael S. Hart was the originator of the Project +Gutenberg-tm concept of a library of electronic works that could be +freely shared with anyone. For forty years, he produced and +distributed Project Gutenberg-tm eBooks with only a loose network of +volunteer support. + +Project Gutenberg-tm eBooks are often created from several printed +editions, all of which are confirmed as not protected by copyright in +the U.S. unless a copyright notice is included. Thus, we do not +necessarily keep eBooks in compliance with any particular paper +edition. + +Most people start at our website which has the main PG search +facility: www.gutenberg.org + +This website includes information about Project Gutenberg-tm, +including how to make donations to the Project Gutenberg Literary +Archive Foundation, how to help produce our new eBooks, and how to +subscribe to our email newsletter to hear about new eBooks. + + diff --git a/micropython/examples/badger2040w/examples/ebook.py b/micropython/examples/badger2040w/examples/ebook.py index e69de29b..0091af84 100644 --- a/micropython/examples/badger2040w/examples/ebook.py +++ b/micropython/examples/badger2040w/examples/ebook.py @@ -0,0 +1,242 @@ +import badger2040w +import gc +import badger_os + +# **** Put the name of your text file here ***** +text_file = "/books/289-0-wind-in-the-willows-abridged.txt" # File must be on the MicroPython device + +gc.collect() + +# Global Constants +WIDTH = badger2040w.WIDTH +HEIGHT = badger2040w.HEIGHT + +ARROW_THICKNESS = 3 +ARROW_WIDTH = 18 +ARROW_HEIGHT = 14 +ARROW_PADDING = 2 + +TEXT_PADDING = 4 +TEXT_WIDTH = WIDTH - TEXT_PADDING - TEXT_PADDING - ARROW_WIDTH + +FONTS = ["sans", "gothic", "cursive", "serif"] +# ------------------------------ +# Drawing functions +# ------------------------------ + + +# Draw a upward arrow +def draw_up(x, y, width, height, thickness, padding): + border = (thickness // 4) + padding + display.line(x + border, y + height - border, + x + (width // 2), y + border) + display.line(x + (width // 2), y + border, + x + width - border, y + height - border) + + +# Draw a downward arrow +def draw_down(x, y, width, height, thickness, padding): + border = (thickness // 2) + padding + display.line(x + border, y + border, + x + (width // 2), y + height - border) + display.line(x + (width // 2), y + height - border, + x + width - border, y + border) + + +# Draw the frame of the reader +def draw_frame(): + display.set_pen(15) + display.clear() + display.set_pen(12) + display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT) + display.set_pen(0) + if state["current_page"] > 0: + draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2), + ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) + draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2), + ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) + + +# ------------------------------ +# Program setup +# ------------------------------ + +# Global variables +state = { + "last_offset": 0, + "current_page": 0, + "font_idx": 0, + "text_size": 0.5, + "offsets": [] +} +badger_os.state_load("ebook", state) + +text_spacing = int(34 * state["text_size"]) + + +# Create a new Badger and set it to update FAST +display = badger2040w.Badger2040W() +display.led(128) +display.set_update_speed(badger2040w.UPDATE_FAST) + + +# ------------------------------ +# Render page +# ------------------------------ + +def render_page(): + row = 0 + line = "" + pos = ebook.tell() + next_pos = pos + add_newline = False + display.set_font(FONTS[state["font_idx"]]) + + while True: + # Read a full line and split it into words + words = ebook.readline().split(" ") + + # Take the length of the first word and advance our position + next_word = words[0] + if len(words) > 1: + next_pos += len(next_word) + 1 + else: + next_pos += len(next_word) # This is the last word on the line + + # Advance our position further if the word contains special characters + if '\u201c' in next_word: + next_word = next_word.replace('\u201c', '\"') + next_pos += 2 + if '\u201d' in next_word: + next_word = next_word.replace('\u201d', '\"') + next_pos += 2 + if '\u2019' in next_word: + next_word = next_word.replace('\u2019', '\'') + next_pos += 2 + + # Rewind the file back from the line end to the start of the next word + ebook.seek(next_pos) + + # Strip out any new line characters from the word + next_word = next_word.strip() + + # If an empty word is encountered assume that means there was a blank line + if len(next_word) == 0: + add_newline = True + + # Append the word to the current line and measure its length + appended_line = line + if len(line) > 0 and len(next_word) > 0: + appended_line += " " + appended_line += next_word + appended_length = display.measure_text(appended_line, state["text_size"]) + + # Would this appended line be longer than the text display area, or was a blank line spotted? + if appended_length >= TEXT_WIDTH or add_newline: + + # Yes, so write out the line prior to the append + print(line) + display.set_pen(0) + display.text(line, TEXT_PADDING, (row * text_spacing) + (text_spacing // 2) + TEXT_PADDING, WIDTH, state["text_size"]) + + # Clear the line and move on to the next row + line = "" + row += 1 + + # Have we reached the end of the page? + if (row * text_spacing) + text_spacing >= HEIGHT: + print("+++++") + display.update() + + # Reset the position to the start of the word that made this line too long + ebook.seek(pos) + return + else: + # Set the line to the word and advance the current position + line = next_word + pos = next_pos + + # A new line was spotted, so advance a row + if add_newline: + print("") + row += 1 + if (row * text_spacing) + text_spacing >= HEIGHT: + print("+++++") + display.update() + return + add_newline = False + else: + # The appended line was not too long, so set it as the line and advance the current position + line = appended_line + pos = next_pos + + +# ------------------------------ +# Main program loop +# ------------------------------ + +launch = True +changed = False + +# Open the book file +ebook = open(text_file, "r") +if len(state["offsets"]) > state["current_page"]: + ebook.seek(state["offsets"][state["current_page"]]) +else: + state["current_page"] = 0 + state["offsets"] = [] + +while True: + # Was the next page button pressed? + if display.pressed(badger2040w.BUTTON_DOWN): + state["current_page"] += 1 + + changed = True + + # Was the previous page button pressed? + if display.pressed(badger2040w.BUTTON_UP): + if state["current_page"] > 0: + state["current_page"] -= 1 + if state["current_page"] == 0: + ebook.seek(0) + else: + ebook.seek(state["offsets"][state["current_page"] - 1]) # Retrieve the start position of the last page + changed = True + + if display.pressed(badger2040w.BUTTON_A): + state["text_size"] += 0.1 + if state["text_size"] > 0.8: + state["text_size"] = 0.5 + text_spacing = int(34 * state["text_size"]) + state["offsets"] = [] + ebook.seek(0) + state["current_page"] = 0 + changed = True + + if display.pressed(badger2040w.BUTTON_B): + state["font_idx"] += 1 + if (state["font_idx"] >= len(FONTS)): + state["font_idx"] = 0 + state["offsets"] = [] + ebook.seek(0) + state["current_page"] = 0 + changed = True + + if launch and not changed: + if state["current_page"] > 0 and len(state["offsets"]) > state["current_page"] - 1: + ebook.seek(state["offsets"][state["current_page"] - 1]) + changed = True + launch = False + + if changed: + draw_frame() + render_page() + + # Is the next page one we've not displayed before? + if state["current_page"] >= len(state["offsets"]): + state["offsets"].append(ebook.tell()) # Add its start position to the state["offsets"] list + badger_os.state_save("ebook", state) + + changed = False + + display.halt() diff --git a/micropython/examples/badger2040w/uf2-manifest.txt b/micropython/examples/badger2040w/uf2-manifest.txt index 6325b35e..d5388068 100644 --- a/micropython/examples/badger2040w/uf2-manifest.txt +++ b/micropython/examples/badger2040w/uf2-manifest.txt @@ -5,4 +5,5 @@ examples/*.py images/*.jpg images/*.txt badges/*.txt -badges/*.jpg \ No newline at end of file +badges/*.jpg +books/*.txt \ No newline at end of file From 6349d45768bf38ec3361d6bd2051b380a2492ba1 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 20 Jan 2023 11:34:49 +0000 Subject: [PATCH 21/46] Badger2040W: Remove BUTTON_USER since it doesn't exist. --- micropython/examples/badger2040w/launcher.py | 37 ++++++++----------- .../examples/badger2040w/lib/badger2040w.py | 16 ++++---- 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/micropython/examples/badger2040w/launcher.py b/micropython/examples/badger2040w/launcher.py index 87947f35..196994a3 100644 --- a/micropython/examples/badger2040w/launcher.py +++ b/micropython/examples/badger2040w/launcher.py @@ -20,6 +20,7 @@ else: # Otherwise restore previously running app badger_os.state_launch() + display = badger2040.Badger2040W() display.set_font("bitmap8") display.led(128) @@ -139,28 +140,20 @@ def button(pin): global changed changed = True - if not display.pressed(badger2040.BUTTON_USER): # User button is NOT held down - if pin == badger2040.BUTTON_A: - launch_example(0) - if pin == badger2040.BUTTON_B: - launch_example(1) - if pin == badger2040.BUTTON_C: - launch_example(2) - if pin == badger2040.BUTTON_UP: - if state["page"] > 0: - state["page"] -= 1 - render() - if pin == badger2040.BUTTON_DOWN: - if state["page"] < MAX_PAGE - 1: - state["page"] += 1 - render() - else: # User button IS held down - if pin == badger2040.BUTTON_UP: - pass - if pin == badger2040.BUTTON_DOWN: - pass - if pin == badger2040.BUTTON_A: - pass + if pin == badger2040.BUTTON_A: + launch_example(0) + if pin == badger2040.BUTTON_B: + launch_example(1) + if pin == badger2040.BUTTON_C: + launch_example(2) + if pin == badger2040.BUTTON_UP: + if state["page"] > 0: + state["page"] -= 1 + render() + if pin == badger2040.BUTTON_DOWN: + if state["page"] < MAX_PAGE - 1: + state["page"] += 1 + render() if exited_to_launcher or not woken_by_button: diff --git a/micropython/examples/badger2040w/lib/badger2040w.py b/micropython/examples/badger2040w/lib/badger2040w.py index 11e975f8..88a91253 100644 --- a/micropython/examples/badger2040w/lib/badger2040w.py +++ b/micropython/examples/badger2040w/lib/badger2040w.py @@ -8,12 +8,12 @@ import gc import wakeup -BUTTON_UP = 15 BUTTON_DOWN = 11 BUTTON_A = 12 BUTTON_B = 13 BUTTON_C = 14 -BUTTON_USER = 23 +BUTTON_UP = 15 +BUTTON_USER = None # User button not available on W BUTTON_MASK = 0b11111 << 11 @@ -30,6 +30,7 @@ UPDATE_TURBO = 3 LED = 22 ENABLE_3V3 = 10 +BUSY = 26 WIDTH = 296 HEIGHT = 128 @@ -45,12 +46,11 @@ SYSTEM_FREQS = [ WAKEUP_GPIO_STATE = wakeup.get_gpio_state() BUTTONS = { - 11: machine.Pin(11), - 12: machine.Pin(12), - 13: machine.Pin(13), - 14: machine.Pin(14), - 15: machine.Pin(15), - 23: machine.Pin(23) + BUTTON_DOWN: machine.Pin(BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN), + BUTTON_A: machine.Pin(BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN), + BUTTON_B: machine.Pin(BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN), + BUTTON_C: machine.Pin(BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN), + BUTTON_UP: machine.Pin(BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN), } From de8ed26460fe23c722cc642bce05726105c65985 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 20 Jan 2023 13:17:56 +0000 Subject: [PATCH 22/46] Badger2040W: Force wait for screen refresh finish. --- .../examples/badger2040w/lib/badger2040w.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/micropython/examples/badger2040w/lib/badger2040w.py b/micropython/examples/badger2040w/lib/badger2040w.py index 88a91253..3be69c0e 100644 --- a/micropython/examples/badger2040w/lib/badger2040w.py +++ b/micropython/examples/badger2040w/lib/badger2040w.py @@ -4,6 +4,7 @@ from picographics import PicoGraphics, DISPLAY_INKY_PACK from network_manager import NetworkManager import WIFI_CONFIG import uasyncio +import time import gc import wakeup @@ -75,11 +76,26 @@ class Badger2040W(): self._led = machine.PWM(machine.Pin(LED)) self._led.freq(1000) self._led.duty_u16(0) + self._update_speed = 0 def __getattr__(self, item): # Glue to redirect calls to PicoGraphics return getattr(self.display, item) + def update(self): + t_start = time.ticks_ms() + self.display.update() + t_elapsed = time.ticks_ms() - t_start + + delay_ms = [4700, 2600, 900, 250][self._update_speed] + + if t_elapsed < delay_ms: + time.sleep((delay_ms - t_elapsed) / 1000) + + def set_update_speed(self, speed): + self.display.set_update_speed(speed) + self._update_speed = speed + def led(self, brightness): brightness = max(0, min(255, brightness)) self._led.duty_u16(int(brightness * 256)) From 6e44434e7de9ee236ef8c02b0626c0ed7c085933 Mon Sep 17 00:00:00 2001 From: thirdr Date: Tue, 24 Jan 2023 15:03:55 +0000 Subject: [PATCH 23/46] fixed quit to launcher --- .../examples/badger2040w/examples/net_info.py | 20 ------------------- .../examples/badger2040w/examples/news.py | 15 -------------- 2 files changed, 35 deletions(-) diff --git a/micropython/examples/badger2040w/examples/net_info.py b/micropython/examples/badger2040w/examples/net_info.py index 705dc179..083db599 100644 --- a/micropython/examples/badger2040w/examples/net_info.py +++ b/micropython/examples/badger2040w/examples/net_info.py @@ -1,8 +1,6 @@ import badger2040w as badger2040 from badger2040w import WIDTH -import time import network -import machine TEXT_SIZE = 1 LINE_HEIGHT = 16 @@ -11,24 +9,6 @@ LINE_HEIGHT = 16 display = badger2040.Badger2040W() display.led(128) - -# Button handler -def button(pin): - - time.sleep(0.01) - if not pin.value(): - return - - if button_a.value() and button_c.value(): - machine.reset() - - -# Setup buttons -button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button) - # Connects to the wireless network. Ensure you have entered your details in WIFI_CONFIG.py :). display.connect() net = network.WLAN(network.STA_IF).ifconfig() diff --git a/micropython/examples/badger2040w/examples/news.py b/micropython/examples/badger2040w/examples/news.py index c8c4239a..e4ba7045 100644 --- a/micropython/examples/badger2040w/examples/news.py +++ b/micropython/examples/badger2040w/examples/news.py @@ -1,6 +1,5 @@ import badger2040w as badger2040 from badger2040w import WIDTH -import time import machine from urllib import urequest import gc @@ -26,17 +25,6 @@ display = badger2040.Badger2040W() display.led(128) display.set_update_speed(2) - -# Button handler -def button(pin): - time.sleep(0.01) - if not pin.value(): - return - - if button_a.value() and button_c.value(): - machine.reset() - - # Setup buttons button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN) @@ -44,9 +32,6 @@ button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOW button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN) button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button) - def read_until(stream, char): result = b"" From c3ad87765d2ffa41fe1ea313e6ae4027c8642dc9 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 24 Jan 2023 21:10:43 +0000 Subject: [PATCH 24/46] PicoGraphics: Extremely cursed thickness support for 1bit pens. Experimental. There must be less cursed way to do this. --- libraries/pico_graphics/pico_graphics.cpp | 48 +++++++++++++++++-- libraries/pico_graphics/pico_graphics.hpp | 11 +++++ .../pico_graphics/pico_graphics_pen_1bit.cpp | 4 ++ .../pico_graphics/pico_graphics_pen_1bitY.cpp | 4 ++ .../modules/picographics/picographics.c | 2 + .../modules/picographics/picographics.cpp | 12 +++++ .../modules/picographics/picographics.h | 1 + 7 files changed, 79 insertions(+), 3 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 1ace1d3f..df3a9175 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -164,9 +164,15 @@ namespace pimoroni { } if (hershey_font) { - hershey::text(hershey_font, [this](int32_t x1, int32_t y1, int32_t x2, int32_t y2) { - line(Point(x1, y1), Point(x2, y2)); - }, t, p.x, p.y, s, a); + if(thickness == 1) { + hershey::text(hershey_font, [this](int32_t x1, int32_t y1, int32_t x2, int32_t y2) { + line(Point(x1, y1), Point(x2, y2)); + }, t, p.x, p.y, s, a); + } else { + hershey::text(hershey_font, [this](int32_t x1, int32_t y1, int32_t x2, int32_t y2) { + thicc_line(Point(x1, y1), Point(x2, y2), thickness); + }, t, p.x, p.y, s, a); + } return; } } @@ -292,6 +298,42 @@ namespace pimoroni { } } + void PicoGraphics::thicc_line(Point p1, Point p2, uint thickness) { + // general purpose line + // lines are either "shallow" or "steep" based on whether the x delta + // is greater than the y delta + int32_t dx = p2.x - p1.x; + int32_t dy = p2.y - p1.y; + bool shallow = std::abs(dx) > std::abs(dy); + if(shallow) { + // shallow version + int32_t s = std::abs(dx); // number of steps + int32_t sx = dx < 0 ? -1 : 1; // x step value + int32_t sy = (dy << 16) / s; // y step value in fixed 16:16 + int32_t x = p1.x; + int32_t y = p1.y << 16; + while(s--) { + int32_t ht = thickness / 2; + rectangle({x - ht, (y >> 16) - ht, ht * 2, ht * 2}); + y += sy; + x += sx; + } + }else{ + // steep version + int32_t s = std::abs(dy); // number of steps + int32_t sy = dy < 0 ? -1 : 1; // y step value + int32_t sx = (dx << 16) / s; // x step value in fixed 16:16 + int32_t y = p1.y; + int32_t x = p1.x << 16; + while(s--) { + int32_t ht = thickness / 2; + rectangle({(x >> 16) - ht, y - ht, ht * 2, ht * 2}); + y += sy; + x += sx; + } + } + } + void PicoGraphics::line(Point p1, Point p2) { // fast horizontal line if(p1.y == p2.y) { diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index d9f421ca..8e6a0df8 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -175,6 +175,7 @@ namespace pimoroni { PenType pen_type; Rect bounds; Rect clip; + uint thickness = 1; @@ -228,6 +229,7 @@ namespace pimoroni { virtual void set_pen(uint8_t r, uint8_t g, uint8_t b) = 0; virtual void set_pixel(const Point &p) = 0; virtual void set_pixel_span(const Point &p, uint l) = 0; + virtual void set_thickness(uint t) = 0; virtual int create_pen(uint8_t r, uint8_t g, uint8_t b); virtual int create_pen_hsv(float h, float s, float v); @@ -264,6 +266,7 @@ namespace pimoroni { void triangle(Point p1, Point p2, Point p3); void line(Point p1, Point p2); void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b); + void thicc_line(Point p1, Point p2, uint thickness); protected: void frame_convert_rgb565(conversion_callback_func callback, next_pixel_func get_next_pixel); @@ -276,6 +279,7 @@ namespace pimoroni { PicoGraphics_Pen1Bit(uint16_t width, uint16_t height, void *frame_buffer); void set_pen(uint c) override; void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_thickness(uint t) override; void set_pixel(const Point &p) override; void set_pixel_span(const Point &p, uint l) override; @@ -292,6 +296,7 @@ namespace pimoroni { PicoGraphics_Pen1BitY(uint16_t width, uint16_t height, void *frame_buffer); void set_pen(uint c) override; void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_thickness(uint t) override; void set_pixel(const Point &p) override; void set_pixel_span(const Point &p, uint l) override; @@ -334,6 +339,7 @@ namespace pimoroni { void set_pen(uint c) override; void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_thickness(uint t) override {}; void set_pixel(const Point &p) override; void set_pixel_span(const Point &p, uint l) override; @@ -360,6 +366,7 @@ namespace pimoroni { PicoGraphics_PenP4(uint16_t width, uint16_t height, void *frame_buffer); void set_pen(uint c) override; void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_thickness(uint t) override {}; int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override; int create_pen(uint8_t r, uint8_t g, uint8_t b) override; int reset_pen(uint8_t i) override; @@ -389,6 +396,7 @@ namespace pimoroni { PicoGraphics_PenP8(uint16_t width, uint16_t height, void *frame_buffer); void set_pen(uint c) override; void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_thickness(uint t) override {}; int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override; int create_pen(uint8_t r, uint8_t g, uint8_t b) override; int reset_pen(uint8_t i) override; @@ -410,6 +418,7 @@ namespace pimoroni { PicoGraphics_PenRGB332(uint16_t width, uint16_t height, void *frame_buffer); void set_pen(uint c) override; void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_thickness(uint t) override {}; int create_pen(uint8_t r, uint8_t g, uint8_t b) override; void set_pixel(const Point &p) override; void set_pixel_span(const Point &p, uint l) override; @@ -431,6 +440,7 @@ namespace pimoroni { PicoGraphics_PenRGB565(uint16_t width, uint16_t height, void *frame_buffer); void set_pen(uint c) override; void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_thickness(uint t) override {}; int create_pen(uint8_t r, uint8_t g, uint8_t b) override; int create_pen_hsv(float h, float s, float v) override; void set_pixel(const Point &p) override; @@ -447,6 +457,7 @@ namespace pimoroni { PicoGraphics_PenRGB888(uint16_t width, uint16_t height, void *frame_buffer); void set_pen(uint c) override; void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_thickness(uint t) override {}; int create_pen(uint8_t r, uint8_t g, uint8_t b) override; int create_pen_hsv(float h, float s, float v) override; void set_pixel(const Point &p) override; diff --git a/libraries/pico_graphics/pico_graphics_pen_1bit.cpp b/libraries/pico_graphics/pico_graphics_pen_1bit.cpp index 30fb1e53..59f2a4af 100644 --- a/libraries/pico_graphics/pico_graphics_pen_1bit.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_1bit.cpp @@ -18,6 +18,10 @@ namespace pimoroni { color = std::max(r, std::max(g, b)) >> 4; } + void PicoGraphics_Pen1Bit::set_thickness(uint t) { + thickness = t; + } + void PicoGraphics_Pen1Bit::set_pixel(const Point &p) { // pointer to byte in framebuffer that contains this pixel uint8_t *buf = (uint8_t *)frame_buffer; diff --git a/libraries/pico_graphics/pico_graphics_pen_1bitY.cpp b/libraries/pico_graphics/pico_graphics_pen_1bitY.cpp index ea4afe99..b391022d 100644 --- a/libraries/pico_graphics/pico_graphics_pen_1bitY.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_1bitY.cpp @@ -18,6 +18,10 @@ namespace pimoroni { color = std::max(r, std::max(g, b)); } + void PicoGraphics_Pen1BitY::set_thickness(uint t) { + thickness = t; + } + void PicoGraphics_Pen1BitY::set_pixel(const Point &p) { // pointer to byte in framebuffer that contains this pixel uint8_t *buf = (uint8_t *)frame_buffer; diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index bf01cdc5..6d801fb6 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -22,6 +22,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_set_palette_obj, 2, ModPicoGraphics_s MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_pen_obj, ModPicoGraphics_set_pen); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_create_pen_obj, 4, 4, ModPicoGraphics_create_pen); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_create_pen_hsv_obj, 4, 4, ModPicoGraphics_create_pen_hsv); +MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_thickness_obj, ModPicoGraphics_set_thickness); // Primitives MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_set_clip_obj, 5, 5, ModPicoGraphics_set_clip); @@ -56,6 +57,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics__del__obj, ModPicoGraphics__del__); STATIC const mp_rom_map_elem_t ModPicoGraphics_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&ModPicoGraphics_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&ModPicoGraphics_set_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_thickness), MP_ROM_PTR(&ModPicoGraphics_set_thickness_obj) }, { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&ModPicoGraphics_clear_obj) }, { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&ModPicoGraphics_update_obj) }, diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 20487930..b394bcaf 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -711,6 +711,18 @@ mp_obj_t ModPicoGraphics_create_pen_hsv(size_t n_args, const mp_obj_t *args) { return mp_obj_new_int(result); } +mp_obj_t ModPicoGraphics_set_thickness(mp_obj_t self_in, mp_obj_t pen) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); + + if(self->graphics->pen_type != PicoGraphics::PEN_1BIT) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Thickness not supported!")); + } + + self->graphics->set_thickness(mp_obj_get_int(pen)); + + return mp_const_none; +} + mp_obj_t ModPicoGraphics_set_palette(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { size_t num_tuples = n_args - 1; const mp_obj_t *tuples = pos_args + 1; diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index e46ba904..d07ad4fd 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -72,6 +72,7 @@ extern mp_obj_t ModPicoGraphics_hsv_to_rgb(size_t n_args, const mp_obj_t *args); extern mp_obj_t ModPicoGraphics_set_pen(mp_obj_t self_in, mp_obj_t pen); extern mp_obj_t ModPicoGraphics_create_pen(size_t n_args, const mp_obj_t *args); extern mp_obj_t ModPicoGraphics_create_pen_hsv(size_t n_args, const mp_obj_t *args); +extern mp_obj_t ModPicoGraphics_set_thickness(mp_obj_t self_in, mp_obj_t thickness); // Primitives extern mp_obj_t ModPicoGraphics_set_clip(size_t n_args, const mp_obj_t *args); From c56844ae69160e2b41ca3a633d8af1e5476f09dc Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 25 Jan 2023 10:19:01 +0000 Subject: [PATCH 25/46] Badger2040W: Fix clock network check. --- micropython/examples/badger2040w/examples/clock.py | 1 + micropython/examples/badger2040w/lib/badger2040w.py | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/micropython/examples/badger2040w/examples/clock.py b/micropython/examples/badger2040w/examples/clock.py index 48297997..fe95eac0 100644 --- a/micropython/examples/badger2040w/examples/clock.py +++ b/micropython/examples/badger2040w/examples/clock.py @@ -6,6 +6,7 @@ import badger2040w display = badger2040w.Badger2040W() display.set_update_speed(3) +display.set_thickness(4) WIDTH, HEIGHT = display.get_bounds() diff --git a/micropython/examples/badger2040w/lib/badger2040w.py b/micropython/examples/badger2040w/lib/badger2040w.py index 3be69c0e..5e277118 100644 --- a/micropython/examples/badger2040w/lib/badger2040w.py +++ b/micropython/examples/badger2040w/lib/badger2040w.py @@ -1,6 +1,7 @@ import machine import micropython from picographics import PicoGraphics, DISPLAY_INKY_PACK +import network from network_manager import NetworkManager import WIFI_CONFIG import uasyncio @@ -153,7 +154,15 @@ class Badger2040W(): self.display.text("Connecting...", 10, 10, 300, 0.5) self.display.update() + def isconnected(self): + return network.WLAN(network.STA_IF).isconnected() + + def ip_address(self): + return network.WLAN(network.STA_IF).ifconfig()[0] + def connect(self): + if WIFI_CONFIG.COUNTRY == "": + raise RuntimeError("You must populate WIFI_CONFIG for networking.") self.display.set_update_speed(2) network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=self.status_handler) uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK)) From b5fb62c8f6b02f3339730ea78481cf84a42a3d91 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 25 Jan 2023 10:44:21 +0000 Subject: [PATCH 26/46] Badger2040W: Fix noise in icon files. --- .../badger2040w/examples/icon-badge.jpg | Bin 1856 -> 1967 bytes .../badger2040w/examples/icon-clock.jpg | Bin 1880 -> 2075 bytes .../badger2040w/examples/icon-ebook.jpg | Bin 1767 -> 1851 bytes .../badger2040w/examples/icon-fonts.jpg | Bin 1424 -> 1398 bytes .../badger2040w/examples/icon-help.jpg | Bin 2057 -> 2345 bytes .../badger2040w/examples/icon-image.jpg | Bin 1377 -> 1268 bytes .../badger2040w/examples/icon-info.jpg | Bin 2005 -> 2261 bytes .../badger2040w/examples/icon-list.jpg | Bin 1654 -> 1654 bytes .../badger2040w/examples/icon-net-info.jpg | Bin 2005 -> 2261 bytes .../badger2040w/examples/icon-news.jpg | Bin 1767 -> 1851 bytes .../badger2040w/examples/icon-qrgen.jpg | Bin 2832 -> 3443 bytes 11 files changed, 0 insertions(+), 0 deletions(-) diff --git a/micropython/examples/badger2040w/examples/icon-badge.jpg b/micropython/examples/badger2040w/examples/icon-badge.jpg index c732ee168946ca712ea7a891b91cc23e9e6955b4..1dffe94a146b792dc24cd201487fbf3078ffab5f 100644 GIT binary patch delta 1748 zcmai!X;hQ<62|`mNszFUu#`fiXhE@B1OyZaNEOf`rW7Jz$zcs>5GWT(CGr-KMG--~ zYym;At@N@))__n$q9h6g6lF)*L{t_ND>0bleH%aCbM85J&U}1ko|)gAGrig@ok9~| zRTY)bsSGt`qSR3+H8qq527^}D)X>z#YGAQi+WNX$+IreptgfN1o&gSz$7|{s85`n^ z^>KI{(hIQaz#X`6*`f!oHBUlQKz+*=0Ej^0Uwe7eW^q`K`#4wHOEftp4V1h)DUR-r zvM-s+=VZrO-k|MpFTd)uqiB2d0N%#b`AGh#Wah5+WuFN?JKV!tO@B<$LjUUWh<*S&YY{Mgsy1r3AxE|&RFE# zJ)6G2BI)3wIv*M;rFGWhX9I7BBt# zh@u7ow0Of61ZYz`#eo$p;UCkn(IfrI%=e_II7~_5-Q8JN>K+=M_2JuHt4>Bhb}Rxi zvZ2S61q}Qp9ojt5g#dj@VR7Wc-Qw}wjoh`3&7O(f3{ri_is(gSy+x7BW=oF- z^xa!yzSs_JOuK0#a}`w!D55quL%JiM5(W<<;9}n4mQlFx)h353`)=#rQqJl1X^v^f zl|?5rn_@)+^m5E?A2d(#ef*5lg<&HAP^Upd3((vo@>f~LR(Ik z2B%doPYxf5|C<@&thtZ-^HS}(@P3m7IK-sqKDn3BOz4HARu_h@i^+>dSDReCE};MT z#y++C#uow29d}~}3p?8{9$!14PK_$A4qx*2_{wtpNvMGmSV7v*3uj0im_PrQ!2)4A zxiMT~=Ek3v8ITHws>pi$imI7iOJ$nPfLerND6fhdLIBeW0f`*N9To=xk?%Gg3Nj(d z*Db?kFbIKws&v$}T^p^*heCvN9P_tmo2c z9_+vt|7)zCnlz8?_^Vkj*yLGf*RGn0NA|ft?lJ0@J!sxKivaE+xv%I9kAwOU!nta0 zFy<05?mbGc(sSpISeVdq;n8>xjjLV|miW=}^y ziN8x*Al+DT%*XMRqPG3xjY-BCUKsy`fJkfai5b=RRXI16!!1KXCCkoPc!I37ZAnow z;BsUJ_VEgf?1Cu)>>IIYrMSc#h6{xh0C6>;R~^udvLgPqq7IrXCqQk4H6yX0FVuk} z9?yK&u!j|0a3qKHY|rRw+Y`%*GYOYsNc(STaeW3#!-LAp#G#+L`oJSZtV`5y(pFv? zQRJ4hV74nPk$NHS&(QV!J05DLUzr3Qv$0fZXz1_F@KD5xS@&l(x?Pz~wS9?#J zXsOcQW7oHl*UTbNK_^v=bv?jkx#a&4xXa2jM->hGg%-RTL z#Hnrc9!OYGdhYq=bSKsL;R@wam4*njmLtQ{2l#GgQfNLN=l;>(6EC@alO7=p7o0fh zS++f!+EExcZC9z);D}ES{Gomd0r!tVTup)UnO<^xwj5^%rxSFEq8U#F zJhX@Yr-vMCq@F)Yc~*iIkYnVy+@=RVwrGrxN-pD5J0t_R^T z7%WBwhs9#?c$_LhN1dRiM$psJCh8dI8yOntlgY+ZTbi*cokAvCI9bx|9hgj}5pBCG zo8e-+jmdz;zzc!L;|Xd6lDayHVL~=x{155TkHB9-AW>))3>Jr1RfAhWohCpckZ3dtja5OT0Row*ER-f%#l!)l<@qi4V1l+O z<04LH2e-7g8Bf{fC*6GLM33qgDs#eYQJ18rZ%(tYwBmM|BT~7aSde7$&D*Kznc2CI zOUs{DKFe0u;1NJTA(W<2n!p`=UbDD!L3OD~CnZLjkyf|6FY?xcVu2P>NIw*~sivLq z{2BgDwk6xjvw8E(&BcnAP}{z?Chg^SHc8aR)KAlAiy49H)=56AbllMeFzwQf?N;c@ zUQQ5o<}%A$Y+gZWqt%tju$}kJ!;3cG{0Su_9byC_a$oZ(T9=nVh<47ihJfpQP+he552YvtUSZ{f;T&ao7pIPv`s@yScs zlX}hkeEP<&#VEBvcDt2Ii;=&zh1_;vB(33m7rE|a(<-gV3;NsieSJwvJrO8bj$@T8(g0e5}W(NgJ9ZGkiJhuoR zrMp6Vf8_9}$5S?+|0y(}-K%$jqv4;+<%;let*CZ4vzS{&HnQS-V>5PU%es8z{-gwU z^!{f%g?^~0;}p`ApiAa;eme}h2I^sO=_L#%Uk=ZPssEuX<<4(#B)mxP4!_CHI_`YX zE^=C;<;T7xTgUALA1oOOA*y>@Brv$ha{X%LNmuBSZFSk#2Yv7RI5}_9i73Z#433~$ z>|B%pC$6+r30}yDyxT{)VWVY|XB5f_`ILp*agE-)(|qzdr_vZmeBQ8+6;JC}KYcgQ zEnr^kR1#M&6m82M56n>Xg)Lb_;@65E{tr^xMsAlnG-NdhLtvK;Fm#4NPLd>ST_qHn zDd!u>^P#C|7(DWo^A0rs=UHZobzMxHvNv?%jQefq2SgL`ghxjMY<{WY)u;b>p=v+d zJ&_zmF&Zzv7%9D)S2@=C>#QIr#+Q`2JiDhh?%EjZS3x-LUB3 z1TPU9?;o@3HSOJ?RW;vpeQzC0&#Cpl@%vEw=jjVWuEg%arnz9BpR2^Y#>$G3Fpp}3 za6#JPy+agZdkUKxH9C-Ds3zs{S_8Kz^m|H+Xhbr1XlGTnh9}zA6I;-Yz49;EmDJC` zV4kJq&v+z%tQ_@Mh)AfzMLH-?(o&M9(u}@UYE3*$x?Q83mhg!ZlGASiPjswz~=~ zy{m@CGa=avBWZrhNf;D|DjPc48wO8fXV)xHQ$*RG#xEJJR%SR=`G=EC=*i*5F2%Xi zT^pKqFwo;y%#;vwSvJ;^iq>=czNr~xzT#vb>m+U!+!#9qR-L* diff --git a/micropython/examples/badger2040w/examples/icon-clock.jpg b/micropython/examples/badger2040w/examples/icon-clock.jpg index 57079255f788e14f1a745b890f35d45ede16d4c5..5470fbc5f119873c07eb06863847e3f541b1ce82 100644 GIT binary patch delta 1857 zcmai!`#;l*AICpB?sFS9;V?2ChITp>i54ZJqaAVy`OYOpqt7|rtYROz=8}89^>uIx zU*y=xy@$tQC3lbDZ^l@YML6VYH&3eOarL_*V0BH5Gv|Ady(3EHMJ4i(k=j| z2pk8F%gDfi-1=E)4p5Yl0RSAZefCK!EghvNk>mTh>!oJ36U#&aY;MVd>?`WT5o#eq z)hNO8ZSO%vZx|KqZC3U6uJQh<4(a}OB`dR|x8AV^KCHD)ztaJ(-Za;@v*WBw&`d)>s(n>u99z$g*kJ++Q5b6 z=@Ltl0&)i1t;^d5?fM~HDWFu_(f@*|dBVbf)WUV&d*rHfQJXQk@M7q&M!0acET=vM z4&C1|+Ad+tm!c3-AR0n=2m%-7+p5S=&z2N;@Dw7k(N{0qPgp0jWRL8b!{uf+DmO;IX*d%2T_?b?c?3QMqh}_v=IS#@15Hb0AXaqA{oF*?fq5>gv@q z3cczgv`!bK7wL?Hu}CQOCbP#-acJx04JFVx&)0LQUBI?Ue!cfn6bKI zj7D3DCT+oSs^#$;ke^b0yV;YZq)DjwQ2*lOAYw!=!^zz1LxPvnPL6SIfpzJ$6qwD} zNPZ~=E~_U7V6z+X6y`<;pBM@Lnt!^Ied^{QtN`cg#q=-Bv&GQ)kfZOjSpS7$Y!?SH z73)^Zj>~Wv=l%B;mKxifKbV022`~Ny8HLGDmi_%#C0Z{ylRCd#Esmp18=8u81G zXvSL$u$vVWdPi1Z%I9^z&%APETbUM*n{R@IBtxVWs2|&X4j!yoFa4j@(ErogZ&5*l z7(QFXrL8s0GmzwPtIydQEHdOV<-4UHG3>~*ZE-e#t5S|1s&i)8frU0_a{$`xmXJ1A z!v!S=N@x2Qu!&)lxMuK+6>?E*KfGq>`Uuk7Y=(|4eWwG5x+xcxe@oePL-741aMZ$Q zY(=cIDDawTdkowImDVVl(sg+M;DHr&*lkG8xiHW#WrRuzK1O);bfFU)tHbx}r^yd; ziH0J|n->9EqXq*lk2r_3ym6MfgZdVIGnVw+yO^;`%!v9sS~?WQnA6`dn7-0}T5LnE z`9+W#?*~P*-zDB~%Uj^inB7U(pnI8r&4_sE20mL!I~l<+zbQVuabmk%3UF&Es)6KB zJ8-KLOinm&gBaG4Kb8(!-d$#mHaVe6hOh;oi+T8k3-UV8!;)fnxLceR2QszJ)OH^^G_=o_lYY@t(jd6O$wk z+qE{kbC7iVtJt=8W6CY&sVIP7+UOsie$W+zBqz#<2ey>OVBe|xhd{Ao0S5 ziS9z%#Zmx^;%A*$P~Exo5n7Z21Ephq5~w!%;jEB1r!I2EfsxsBi#uq07P-fDJWL8W zbw&rs@_UP%ZV2(0?rX}o-@_OTRUh<0%Z)q)D{$c`5&DOeWBUL4;U48j_WPY00z}A`g^RZ5Hz4WkKi!m|CIA2c delta 1577 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 XXQXHk`Skgr(gi+%`twt52pRYXK|Pt+ diff --git a/micropython/examples/badger2040w/examples/icon-fonts.jpg b/micropython/examples/badger2040w/examples/icon-fonts.jpg index 1eac916c8f07df9bf7bebd891650c7f2d55a6733..8a0e9aadb3456c0d44437a833fd8d72c35cfd69d 100644 GIT binary patch delta 1175 zcma))do4-m`kg+p4pB`2(=DV%rQ~2Hf`NbrJ8nUF4NXewX|_> z)p6>w%&im=_j9(8Aj)toE9(?fgi|zHNvGM5B){*{zxU7H^ZE0ApL3q~dCKrA)3QTh z`UeiYM>hsK3~`2r1_p+v#>PfCf+>N3H^t+LW)@_knYkGrPqrqTTUt>l6awj>jkT4H zg%!mL4gow4_yd1EJ#%ocYaUquI6XZ8=s+7)U*Pth0SMNX#|BBNbTpzvb3*xHN8Pph zO)O}^VP-AF({}nt?}HbF^)+6t;is>VqK5bMG5Z)rAeP6uYma(%L9jkaUwwxd&^H6_bHxis+W46*EDGP~y2f_1Z%w!M(;w?o_w6ap;5rKXolJG+tZxpI6UkgeiykvqY)K&8H?)`D(GUz(eu-MPmFC$#nK+i`tAoWvvc|R zUtbxzRT4nas1V6%jZVIPLa7gdY2gk=4bpsCItIbM2ailww1{+R_U$%nEbplD(B?JX zB6am8R~Es|{#a>Ln5IPHxsBuihq-B1@ACG9;+ns&(W*GqFpf-4a^F4;BNLi*SjF z&J>4S6C-im4nAAT!qbQy3-WAR^x_HxBsoJUlD2GR5&3DW+Zyk@}24g z6C4!zUlt4A3Kqt(u=q7sEw@UFl})p9=-nB*-wcb@cDo#{XTG?}N5jyy{TT!kvnUfA zonmP{MS@oGN&)XJ`>;C%UBAg82)@ML*>`K_S!XgsmD0R49zv9-i&LMb6}tDT<(%UU zfB#fL_|9eBvGT}hVz3j9%pRh-LSV3}tsNlB__m`}t`e!P6299$dBsxIiw4(nTDWtu zYH*k#aq~VGFz!&W&lreWV{IoZGE`h;w1Dg9m`TShh$(+gc%he(-koFpLjvc5>hlk+ zR-4M!=|!5QD@H!zT%I1yL`}_P$R!Br`;X9|U1rK1n5A}3KCv0{ S-pfj;**CO`JgI{M=l=y6yjs5i delta 1117 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 H6j%S*16?hT delta 1755 zcmb7@=T{T<0)~GXkckk65KLr+Awf1sB!h7T6bpz_Kx&mCNL7~XVIYbeR1BCFWu`Jp zL5m=?pjDIx84iYEFd#AlhM+*$JGq|TbN_(*ob!HrKRh4aw^}({DHqQ~%F83<<&X#j z0);}Nv8oDK3+HtPT8$15gMQ4u`=Ja&S0+KohpTN?SW=GdCx4x$JkJuWlA)sc z5U_v6Le2QA#{-*XZg$+h#z^$cX62Lieu4jY(VCqo@6OD0J8hxffbX@-Z+A0o7k{Gb zK0mhj%)b1=btZKGM%Wz6ldfE|uozb+&&1GCo+D1ILr*hS6n zqJ5WmsJ4E=bz-ib#?MNkb1Hab-MbMdKWSJ#Mt5_me`Mmv>jLZ?-p@&GB^}!abfuPF zx?q*@XA<-I;?uW(hxl$i#xuJ=#?AX|?=Kf@+e`F+D`4JtxOgF9{ux)vu!n5k?U(U7 zW02dPP7VHtiFulYt2idVko((m5v6ffv;Eb?oO{>otnj*ffz^{xAMm)#kaTl}mRtxn zIJ}27sf2ajUUpJaiS2~ncyk_`gOxB)79Wv&Fv@PzK7;Wnn-yB>!j}7o;f~+e<9C8z z4)l3q+0EOXndqCbW6Vw&;MP67B;i-uHjJOrJJIaNPZ>6fAo;bT@x2x>QgO&;A*jC} zUiamo&FY<~cP8q8Ee3S<k-V(n{K~kCJu{OQyHenpak;xaDTox zXdhFo{L(3<4<#0POZX*K(didxV6;g2$V9BWA71#EP!Ksq+cD^KNWRa^9qgK8L`G_nZl-&*E#{afNea zhLf~U2Ck+Yl@7{4E?1zt6*ltiOLdW3&&@vdc+kj-9So(|(@=4YXBzd=>7V6CJr9HY zpcqJp&(Z4Fc^Ox37DFLIZlg!l&i#oI6&{oCwNp03Hweq7hAmsW42*gv-@ zb=eR-_Cf>IoSFicG!4ZRC_`7u^m)D=g%s5|Y`f z7IPhJ@Y=Z0r|#n;K{VGFcN#vrG~;BT(nLM#c7?_0V)f}L$BhLR#E>CX4{PIMnfK1; zE7AI;D;`y6Bwck9^WVMHUX?}x6vM{EM_Ek9IZ>L_+Urz zHHA)P*?qZ{7E3)KA-A>Y@=1pVQWH{WPcP;fZhH45SfHULGGLjxM&fcb0E^BpOW!9x n>2oWqa#&n=wlSU`FMediDPw;=Od*vXCKYphjmpv)GQocUhN>1` diff --git a/micropython/examples/badger2040w/examples/icon-image.jpg b/micropython/examples/badger2040w/examples/icon-image.jpg index 0c34c1c815202f0271ddbfc68a2da81891ab7cf3..5b6c26713ee1f9e6cd0ba609382b797c0ff3cafa 100644 GIT binary patch delta 1044 zcmaFJ^@VeSq%SiQ69@qT3lOn#u(GnSuyV1pvvKfn@$hhSadY$X2?_A>3G#7s3y28_ z3X6z}it_M_ONfa`2#JV_{6E0J&B5Tn;K0Zz$S`r^&H7sm9E^+%4E79vgBNva0MYvA z>mSu0`OnbxpJDs*x2&swe}+^4rvGO+X;Oc9oqgv0Uuy9`<1hVZ_^H;DWcr~fl(|BA2w&!BSgKLg*6zsu`i%&dP}@BN?Q$*gbdf2b^f>-^})e})Wg`?h_m zAHzFL@AJNn(%EL^HodYaZ|xiPt^MaZme0D`q`JN9k?qC;Zx^l!t4{vbbgg6f&u~!B z{>g7U$@)9~{~3JCOMm}$6$yX9|3~QYKmW}Sr~d`|?#uP^`2APHAJk(J4fQn5mMD#` zHS)e)a%ElOv}fFAQ(Z0{m3G_Yv2xC)#l8Y*%nT zc)!=S;NRfcyG--2rAJ)UpJ^Z0zwLZ{U%c*0VNF4-(<9xo!@=TFzP(2;?=cJWRF?Si z=jc7@4rR+8S2ple+NHW|3~n1 z%#V{F<&V^veN;d0za=~B>6_`>rEB!wOw6;_34FglO|af=ce1Na*&?myOgrO$6!!lO zJO5{^{qJr4NbJ4;8NLC-x2Ym~{>J-9s^1ITsEPQ`(9-XERcF@epbJYb#9dWCc$a6@ zp^sC%rBm2a>L+=Iuv2X(H0fU(eI{>SyB`O)*@uj}JDKC(Byu~A?7s`!59 zHFMqKlxu}v&m8j{kmH+V6 zzZaO6O#avd(_HWO{|t(tv`mDu>zDsCeDFX2L(S%T*Z$Q14BfMq_wA`(T@fF-qu-}m rR_(q=WL^|!YUyV^o0E%rjvO+{ICkLZv`R)THu*1F;B2~R|Nol+QjHBP delta 1070 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 ba0dBXXvx3;1yu@)syzaVD58oeqQC#ySF-Pz delta 1703 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 ba0dBXXvx3;1yu@)syzaVD58oeqQC#ySF-Pz delta 1703 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 XXQXHk`Skgr(gi+%`twt52pRYXK|Pt+ diff --git a/micropython/examples/badger2040w/examples/icon-qrgen.jpg b/micropython/examples/badger2040w/examples/icon-qrgen.jpg index b34dbbc33dee586bedde4cadd54adc54ba9e498f..d34b637c833fa319e2e631b465e4b50b8be7f910 100644 GIT binary patch delta 3236 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 delta 2536 zcmb7__g9mN5{AFfLJLTfPF5*F>I#8S0+DrB%%Zr80)l{wpnwnok$~Vw6%>@}MQK@e zCAcmSN{G@Tf+!+ErAa4J0+NsfFtm{Ga_&9%54i6+^V^&`b7tOoW>qV9Z>}aNEhPn) zl9YzS;W9GPvhu13c{w?GO=T5DRb4Hlp01XT&QAswsGs(m>FekiV-A@8d=QOBBT@EF zc2-ymYqS+K1{{XT$jHdc$!j1G8dm#s_F4TO()@2O^cql-1`Yv-#9{jZF(sI|5-cxx zB%~8S!T@pD{{;L;FfnlnNh!FrjI12g2~d>)F_@Tygt!D;QbGcNiN)@QxRQkAzJpTA zE+^p^B31TVB}=RRlJ~f_T}I#f6i@A9)Mwef256=sUtL2}%LrwBz$CBF2$quf!v_2| zGdnlWT3GzPvby#|u)eXm1&spo;;`MO#FYRXAlM=J_P5wS?RybAjJ#Z%N_b?^mDv2y znCXJbhl{<0fDJ#oB5vUV1azC`h%l~QQ=0}3+?{3!So}3+9;w=PfY{SPQu+~&!Vlf* z3xpTUy%l%|L@b=lF-t4QW5HrT03w9H@@lfEnr3JxFHY>q&frVi*jgqGC~Zm}%wYNK z*&rWz*-yQ>QG@YWRPIHrZn|U1nZYjEK@?nbsi61T)-rkL4!^)-u!ZEvc9#7Y>%#=? zR!_=UbZYjDX8Ti-GPjO+ljCd`F4E*9$RxG-g95O@=(qdti*AD9IdQA^t@~5&0?TGt zkEfyW_o(S*tVc01OvKQ~9N{9q8P zQ{P1Ujwg70ng{Et+lK#?OVWtp!VXm7?HH4i9P{Mlf?-uyEd^$iL9Y1EV zDHR+_v%(peP7={(5dtLWv$+ca0zL#hQ~pCL<1J`zx=mnqRgn|hx;hvu;1|OD%Hw0l z?ycG?SZ6Cnnd)^xz_)VpW!<^-sgCXDv(|N244U$^B~owe=_>6T|yhI;usyy8njz}*(O?Q@I!qy8kqg-UDFk3ouhbErtkI)(o7 zhib`B7OqW%IpgS*ru*Ti{E#Q>2GGo(LMDY2E2oz85w>%bO5gcD2~Sco7dNZ_V&iH1 zE!8i$x+=pqH`7E*_EynyBju6uiOtLFVA9o`(m;K+55$a42gFdl^YftS=RU-&)3m^f znzRXhue06___)-TarJi(Rm-!oi-D>7Asch?vtOvkEe{V+LpTZA3i&-jSNf}{Ta8?k z#J^Nc4voJWx3ZgW>TV$D1rRfi@+)$Sbz9d&$lHvSVGk8@kv^_?dVhAdG90B3=DNnO z^kQC8$J9Mt&o(s|3+APj9^PBB=DaRd@Yd@v;QJQ&oAHgP%mwVexNp*E zM8tRqab_w$C}MRf+KH&m6ia?R4l}A60}zMB$9Vz8O&v> zJ?)M5&H*bmN^jvz+Nqmfe6>dvgZ4Bu~!hl zw#aa zZ^xDpEUIFjeSm<4ts5PxJw!GhUzmSM-c~_o?S+7{q1YwTBOT@IQJ;B(7rrCNi^G%& z7q#BEr3V`KGd9PoUfnSf%eMml7CG|0g!?A<@h$RREI8-{j5(Yc{>r_cG%=&z&QNb*O|yEqL}B>e-f-Eh^?TRxs>T8ZEJV6aRt?{C6%W$62 zYKOee9^0$>ZPEUWQ;pwV8hV-n``x)QwZ}HZA~59Sc(SYP(@*3)9b~TN8JZ} z^S!5|uE7?)A%OP)0^S@Kr9*%WYBa(6`FDDd=+m}BALirCwq?)j$cJOGqr|Sr_Uew` zH+-ijR5N}uBa zR*%%*;B2>XH5g8n;yuD3UYL8o@UTS{IfN9ODZYkDm%B2l)c+Ud6I;|BW>67)!e+K77iJ%I;y2_2fJhgb zSSoB3?O@*I#Wfl27SS8My{Nv8>Soeo^>34UV}e-P4lAYu&U=^Qb23FbAr6gIk%CiM zi$boI-`$eNkKgV70H$HDt5f=a?f)m{o~vggZ6xt|TtHaSO{8^?-}81m4Y&@heC Date: Wed, 25 Jan 2023 11:20:20 +0000 Subject: [PATCH 27/46] Badger2040: Add image path to badge.txt. --- micropython/examples/badger2040w/badges/badge.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/micropython/examples/badger2040w/badges/badge.txt b/micropython/examples/badger2040w/badges/badge.txt index 0f75daef..1295a461 100644 --- a/micropython/examples/badger2040w/badges/badge.txt +++ b/micropython/examples/badger2040w/badges/badge.txt @@ -3,4 +3,5 @@ H. Badger RP2040 2MB Flash E ink -296x128px \ No newline at end of file +296x128px +/badges/badge.jpg \ No newline at end of file From 7a2ffccf168d9178ee67f1a0301060f4048881ec Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 25 Jan 2023 11:32:46 +0000 Subject: [PATCH 28/46] Badger2040W: Simplify clock, time is set via NTP. --- .../examples/badger2040w/examples/clock.py | 115 +----------------- 1 file changed, 5 insertions(+), 110 deletions(-) diff --git a/micropython/examples/badger2040w/examples/clock.py b/micropython/examples/badger2040w/examples/clock.py index fe95eac0..6b1d15dc 100644 --- a/micropython/examples/badger2040w/examples/clock.py +++ b/micropython/examples/badger2040w/examples/clock.py @@ -21,90 +21,6 @@ rtc = machine.RTC() display.set_font("gothic") -cursors = ["year", "month", "day", "hour", "minute"] -set_clock = False -cursor = 0 -last = 0 - -# Set up the buttons -button_down = machine.Pin(badger2040w.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_up = machine.Pin(badger2040w.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN) - -button_a = machine.Pin(badger2040w.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_b = machine.Pin(badger2040w.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_c = machine.Pin(badger2040w.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) - - -def days_in_month(month, year): - if month == 2 and ((year % 4 == 0 and year % 100 != 0) or year % 400 == 0): - return 29 - return (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[month - 1] - - -# Button handling function -def button(pin): - global last, set_clock, cursor, year, month, day, hour, minute - - time.sleep(0.01) - if not pin.value(): - return - - if button_a.value() and button_c.value(): - machine.reset() - - adjust = 0 - changed = False - - if pin == button_b: - set_clock = not set_clock - changed = True - if not set_clock: - rtc.datetime((year, month, day, 0, hour, minute, second, 0)) - - if set_clock: - if pin == button_c: - cursor += 1 - cursor %= len(cursors) - - if pin == button_a: - cursor -= 1 - cursor %= len(cursors) - - if pin == button_up: - adjust = 1 - - if pin == button_down: - adjust = -1 - - if cursors[cursor] == "year": - year += adjust - year = max(year, 2022) - day = min(day, days_in_month(month, year)) - if cursors[cursor] == "month": - month += adjust - month = min(max(month, 1), 12) - day = min(day, days_in_month(month, year)) - if cursors[cursor] == "day": - day += adjust - day = min(max(day, 1), days_in_month(month, year)) - if cursors[cursor] == "hour": - hour += adjust - hour %= 24 - if cursors[cursor] == "minute": - minute += adjust - minute %= 60 - - if set_clock or changed: - draw_clock() - - -# Register the button handling function with the buttons -button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button) - def draw_clock(): hms = "{:02}:{:02}:{:02}".format(hour, minute, second) @@ -112,17 +28,9 @@ def draw_clock(): hms_width = display.measure_text(hms, 1.8) hms_offset = int((WIDTH / 2) - (hms_width / 2)) - h_width = display.measure_text(hms[0:2], 1.8) - mi_width = display.measure_text(hms[3:5], 1.8) - mi_offset = display.measure_text(hms[0:3], 1.8) ymd_width = display.measure_text(ymd, 1.0) ymd_offset = int((WIDTH / 2) - (ymd_width / 2)) - y_width = display.measure_text(ymd[0:4], 1.0) - m_width = display.measure_text(ymd[5:7], 1.0) - m_offset = display.measure_text(ymd[0:5], 1.0) - d_width = display.measure_text(ymd[8:10], 1.0) - d_offset = display.measure_text(ymd[0:8], 1.0) display.set_pen(15) display.clear() @@ -131,19 +39,6 @@ def draw_clock(): display.text(hms, hms_offset, 40, 0, 1.8) display.text(ymd, ymd_offset, 100, 0, 1.0) - if set_clock: - if cursors[cursor] == "year": - display.line(ymd_offset, 120, ymd_offset + y_width, 120) - if cursors[cursor] == "month": - display.line(ymd_offset + m_offset, 120, ymd_offset + m_offset + m_width, 120) - if cursors[cursor] == "day": - display.line(ymd_offset + d_offset, 120, ymd_offset + d_offset + d_width, 120) - - if cursors[cursor] == "hour": - display.line(hms_offset, 70, hms_offset + h_width, 70) - if cursors[cursor] == "minute": - display.line(hms_offset + mi_offset, 70, hms_offset + mi_offset + mi_width, 70) - display.update() @@ -154,10 +49,10 @@ if (year, month, day) == (2021, 1, 1): last_second = second + while True: - if not set_clock: - year, month, day, wd, hour, minute, second, _ = rtc.datetime() - if second != last_second: - draw_clock() - last_second = second + year, month, day, wd, hour, minute, second, _ = rtc.datetime() + if second != last_second: + draw_clock() + last_second = second time.sleep(0.01) From d4273ebbcb1dfa22726d048f81edd53a7dc8c6a2 Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Wed, 25 Jan 2023 16:28:28 +0000 Subject: [PATCH 29/46] Badger2040W: Add weather example and icons. --- .../badger2040w/examples/icon-cloud.jpg | Bin 0 -> 2405 bytes .../badger2040w/examples/icon-net-info.jpg | Bin 2261 -> 2918 bytes .../badger2040w/examples/icon-news.jpg | Bin 1851 -> 3238 bytes .../badger2040w/examples/icon-rain.jpg | Bin 0 -> 3324 bytes .../badger2040w/examples/icon-snow.jpg | Bin 0 -> 4008 bytes .../badger2040w/examples/icon-storm.jpg | Bin 0 -> 3055 bytes .../badger2040w/examples/icon-sun.jpg | Bin 0 -> 3117 bytes .../badger2040w/examples/icon-weather.jpg | Bin 0 -> 3055 bytes .../examples/badger2040w/examples/weather.py | 106 ++++++++++++++++++ 9 files changed, 106 insertions(+) create mode 100644 micropython/examples/badger2040w/examples/icon-cloud.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-rain.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-snow.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-storm.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-sun.jpg create mode 100644 micropython/examples/badger2040w/examples/icon-weather.jpg create mode 100644 micropython/examples/badger2040w/examples/weather.py diff --git a/micropython/examples/badger2040w/examples/icon-cloud.jpg b/micropython/examples/badger2040w/examples/icon-cloud.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b1b1e706f20d5c30ead97beab47c45e66c1012c4 GIT binary patch literal 2405 zcmbVL2~<;O7QXK#k1VW#u*eaJfM^MfD5z*rHVXn;AOzV|3IPNLB0FdWg1EFgpuz-^ z)Z=k|DAj9_ve21=90bS z6VPyXadQC-!ypiSfRy0Z+?<_*y?CB3ZreUW0Ra45j373VY6TE0OiJLnI&u610y(tj zfWZ<_0~~Zi1c`CmeO&nPUYmZ1vXR}hRNVF6wErGZ4GT{c0AL&xb`ZoRBq96>!s}9# z;uN?LVYVPLBn;sz2wNne0uk<2_(R{~Q3c+!fN=zYoxtZgBW-MiIeUJELw|(@kqNOV z#|Gt?hQ$ie{kZ>I9Hzhr6gV~}8P&F63WX}+LSG+rnxc0pxPlvO2QT12C?rD^#6S{Q zqEm=GiNHf~r}yyn7x-R?6^d9Quoq$>WPuNg8K4|wi@i;ZuwJv^!c?39hyjwE zS`I+V2beoal5a{#a_&3;o* zNJ7ZM?@-V;9uWaBSq`8Y0HD+0#S^)%VqY{exQ1#zeZgCH1eRb^H7Z#J?4Safgz2MWdloP|+X7})|w=#NOC z{Zg#h&xYZsMkN}Z!Bj>G)f#|f6beqID5^%;=_n3V7NNOpwWE@jcL>cmp1mgPR0-Y0 z>3X9!@B0Z;>(GRQ45p5*-V*)gW-C^HU~aQ^-Fn*%8=bd&Db;=Zs!*NudOm*%@)r(6zCjhBw3^9C4s0T#lS zT;j;EZ`SIsa;b4wlo+l%8f`y`bD+KO8{I$xVK6a17L+icB_j^kXU`iqGusW0?bNM# z@IasxW$6LF;_T~L$JewSQRf6OAzkc102{n$5}Kkk!%NcQev#bJfBw7ka>I_5mZguc zKKD#jS#RxmGV8Q?m+Q4kY)Gj0hbGZx9n=NOsEyUrSrvWJ`@_dt&t3}Hc6wcHL0*-Q zqq$YsDTA%%9Ss@{2kBHVqMj|U+$pAe*Nr%O|5RHImMzT@3!+2 z-8-5cCrt3a1ey8UxQmP~@v%t~#@gS+%TuSFCZZehMZ#(9yU8Xn;~zj$mlX!av(rP^E)v*vw!%-S<6~(dJ%!!avopInyus6&WsT? zLc4s2r3+)k6w}0B`i(As;~kuFr`RwlHc-l|tDX4xvQ5h7<&}PW%{+E=Ty5sKT09(` zj~?AM#BHT();QSRlg>1D`b=la??}Eo+W$>)GuGw>;)}-eB0*{fx*ZpL0ZkW}!dQ*O-co z3I;wvE8scbz1yfqc*VkQS-HHZ+u-Kf?W=;SJoZhNbKER?YtXMdob218sJrbowj_=fg=5&#fXMFOu@Ie42rZNsP+8QU8TxP|vem{)HrF tAk1o4-@iWHWJVElW5Rp|7RP6X&C9rY_lbdSQTpY#+qEzjv}9!8zX6q%Nyq>I literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/icon-net-info.jpg b/micropython/examples/badger2040w/examples/icon-net-info.jpg index 447205063c2fc3ac26750246e2e20fca9c8a88dc..a8a5cdd9ca17c3eb0cd229d3cbed1abf48956909 100644 GIT binary patch literal 2918 zcmbVM3p|wR8h_?yT!t|WQEgbGl%(9cY&D8VkxMQ~R*W#a##r~Q$w(=*Qi+MSD79MI zluKA5j0#&s*0o$}ql-mq&ZIHlc}Kh3{?6}oe&?KLzHi?D?|Gj8`#%5Yecuo3#s)!k zi>!VNOUCs%_R}3MqR+-M6EWf!_IG2ln6y&Y%na5Cv=qfk-e$ zV<_@OfGdh``~-jQEZ-Ti{1J-{EX1$@E^xqamJhN$Ksm@h_BJBW%yia;qih5qJ;typ z0|0V5z|3(Bdw(9oW-b5_`T=f*e&lm=0am?5{^K8gj2r;!A%Gjgk3N3^K=}~>t)4Ky zaKG7g2A3)g)K)nq>(fdQ+P)rtwyew^h~nSXeKf}-XeE$z7m3l|wKUSe)xxpLL&HP$wpZ0$DNZ`tnV?%|0x zjuo&cFesS)RYYV|bWH5Gdk-E;JbWZ6Ipt*fsf8$Jvc^5DJkbn8dg5r|WvK!?U zl|R=v2pezTx!cs--tn;W*RJlK-l5?qPk(zhGWz_*x71X_ya{v zhWU`eq)ghZvj0w4!vCf0FJT{b^#X-}Lz_pS0TX7n=i=iP!4Uo&s5uw}*Y@QPkzX~A zc!{qFeR~%$(sU*rMz@sjO=>;Gk3Ey2`);8Z`TNOn=f;(^6p*|WXJJ4p6bpu_>#0Ps zNrRMHn%$H;Ri?n`G|~Njd;!nt{pG`L&IN0itz2weVcCWouAO+p?~ReBaHY=XwNl$$ zf^B^IcgH-(+y9!Br*TC=JB4T3!-xv**;IFQV+If zV6czYPsp@MlzT>sPVBW}Zej*G$!Z__;%SfAQ|Q|xWu!AF9bOjP$WFeK&5u5lwdkE5 zn|ktfi0dU$dJ0VADm(YCx!BypRW;hC zD*63Jzn=QjSuWPixIvxbG>N*|u57hjs_yRtJb4x|$fgceq~ ztDG?6Xf^dW#;;GAC_nUuNeK4%dC}oF9A?9`@zwE?=e<4!-rfzBM{nG1Bkd|No3FA} z{UK^-j>2f%>b9$;PHMru{3LVlpK60U%C@>ymY?~W>@!)hq`01*`+G@{8{Mss8AGi2@7`#$Khhl4| zu|=N~@FKcu9$oVJ)??c9JMN7u-4*VeQbbmA;xoa_VBXJ_EF;quvGMDVP6#Aw`h$YR zxMkEiRWIk>PUMJi(yX0I+}33!FB9*b*&AsBBn!mQ+4Jo8eFruAi*%WyEEBrb)4A}ea+;3KuPrj`YaM!jj zjke6zIA|SGC`@W=B2>DQp{isz<@#y{wDSiG_@y;x3wnI|W2Xn)$`b-Ix6Zq%Sm#&i zzS|*`bzr^`F2SYq+BU8EsyGq()g@JpB#ZL~OudDv3jO5~xt?tIe%`fJ zo0gCKlHvPRd|aB?XlOh!Ztio}=jT)>?xzj;SbC-YlDXI5kVjbcC3lBJeRopI1?BGh zbd~ye>RidXi6Y@oON`ALrP>c9?msjxuRPZ3eJ$lR{gjd6aYo9m<(}VEX*baN+sGs2 zF(0Hns{O6f%B~v1y%|B=na5A+vm2+@RbRfAdWHSP;i!zW)Rr$!u`GFaGc2!>3oxiN z;s^SsU{Dg17^mwku`iVhOFN4=j1F_Bu~olI@>3b={hY+dj48scEajUuty7?(0PhPv zd^M>pzGA}x37tFaR8LJUucg#zf7vJIm~ZA7Jd9$Oc84wttjJVfam;M-Nv3{tcK=gh z@wZ8XmIKu|u2i88odBK5fyVKpG~P0Co{5CfH9dZIeOi%sZ(WF}m7=`#xa0gSNe}4B zJwBd$Ysq^nRzO@%8_tRZba2L5>73S?aKS*lho1#XD`0DmVN> zDdt@S6!Y0O)z51G^8w{e{JRY|;bzdgt>g2zXE&Ipne-?rD{1dw|R=WTI delta 1970 zcmV;j2Tl0q7S$0H|JeWF01!$>Nk#wx0RR9200961lg0u@48Q;j2mn9;Kmh>}0Fz?_ z*?-yq2mt{A06zfzQ=*FSuZkbHH^6^`nyAw}QSmcJgHjVuZ7rUg=IT>hOA7^(Invc6 zFfe0{vIQiD13OzB{{V%*;G{pZZ;UnDT_VHcmY;8Tal2%irIp^FZZ@f7zI%vci8xb@ z%rbBWNdWy7r0Ui>{*`5^>6fOr1(5cE$7m-m!3T$&L@?oj%`-sks~U=2rK|C0rFxF#aroLg@6A5 z@I-$K+UZ75h~E&kjZadR7#LglUKp(5wU=r0lgynZGp^#HTVzKHNne`_YU}<8@9;y$ z`WCkrfIcbsf%UCE^|aZqCA_iKZR~EMWiwmP3^7E)Ra1h7L}e_bf(Fy`2aSFRe$gNB zOdlV`;{N~)YIhp9gUrI>eOF0I?$kM=i=^dBY-e@%%P+lP=pmpl%0n56RLAqg&p8C!4*B%eyrUyXn8QE!NT zFa4~4Y@H|IFN1Hs*P`h+w)$ngrLD=hvy)PE-E(<3hBC|cb&=w5e9t9q=YL_eyo+C{ zKeMmEZw~&=zXR zC43k0_k=XbZQ#_k{{Ro_8da>fY|9EuJ+zS{IaOj5GlED2<2VPUetQ1^!7={;VXur| z0RA}ZJ~Q$DoBsd^ew7}JCV!tDq%Ods1fOz}U2 zCAdBh)Mjl*PPesbVTSWdY5xGyG>N2@WDdxo6t-kw8s2Y}%7y*D(v!~!C4Z}R_`&}G z1h2h^<5%tN;~yUQj>6yjb@a_!#Lx>yk~nQ|Zf@a@LW{hTzFpkt70X~SJg^KuXY25< z{t6fS8T?E5Kd$(L;@6ElVW;@FO7Rzop2p7RTgfHW9UW$p+|IveiWJ)oxI(cIiG@^9 zfMe>f_#)56Ul;h_!oL!{H-F+E5$YP=i{anwk)&H{6B)k3k|oS-6inG=i*2+aV+UgG zJ5&~I{*_nfSNs;!!rEQmz%K&$l3QK+)}P{Gr`uflj6Aq5EoYKs+78pXtzbDIk+XsU zZ2cGi00i*yt@n@r0Ak;TTAra5yf+YOkEJTxD=L_*=a$YUA()-UJAZU6bArW)0ALTI ztMP;O8j{EMRQ~{inE0RJscBke?yEektK_s-QpXf(r*=yQvXrnO02we& zNFPOi!5e%ns(63)M}NG(zqR{4rn%y4-9t~4%vST@Sgq}g;1XB&*3&K<2jtE$K|gg@ z=3o34+-Mu z3eWp0Yn~tRQhw523B3CU**?UY>swsBH}%39#7s*TCDTMVVl zeii#ae$oE`wAB9q3H&Ya58!8j^$i=uo(;Xek6zYgwTfp~l6#rf-f?#jg2x2Rq)JQ3 z@hDQHGB@h?$Di6Oz+ba(gKm69E@sI53sa!MK&GyC6FLg0*ePwVi6{2ekrrI{ft&!(QvM-U5B&^^s zn*RX9eg4oeo0yjxEe3D=X_{{V-x ze$w9-f8vzzZ-%@-4~aDo`1F4ZXg4>Sh}rwc@_(V0Y0GRjy=~X-I2}*~kIzCvXP&TWHC^00mVFimE*ViYTIrD5Agr E*#Mm5g#Z8m diff --git a/micropython/examples/badger2040w/examples/icon-news.jpg b/micropython/examples/badger2040w/examples/icon-news.jpg index 02cf932d54d48c9a3e2c6c2a27f10fe30849c704..936ec8b530c908676765138a16138c62bf29187c 100644 GIT binary patch delta 2899 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 Fe*>P1UoQXv delta 1587 zcmV-32F&@U8M_V=|JeWF01!$>Nk#wx0RR9200EH_NDROL3kU!}06+l&5de{~*?-yq z2mt{A06zfzQ=*C}qKYW5m3}FI!A`$tpN0Pb+IIf{@S6Vs!dt4?`Csub@U^qv{iA-v z`>UUp)wZkdZ{G}UW&7i8c~|^Cui%IM3f~Yv@Lgm70Lhi_{{RMmZ!dwr9X`o#;r{?0 z>GnF+$Jt{VCc1yK?+o+smhr5(S%2jW3K0WH18wAnQq_NGf7|ci*X+-#-)Md)*X}hB z7Ft6M!}xPVv}>EavM|~Uov_B+51Fz_QMO@#JJWZHX+Q8;?}1v5t7U0%qIly=x1MB* zOY6Nh)uFalU<{5Uxpyj{u6gmgYsiIBp;Q3;G5sD55rH|hv8-Kj(lx*;s?9Z{7m|P_FkWP92R#_ zMFp(eCH>Kt<}*66Nf7PE(to6Gue!hC*B`SN{Sz@8m^n-NN*NPeQd=f&`WO6<;0PsV5_ad4ZAX?GIuuM7vKK?Wv}=o4~2dr{3G!1 zjXojx*H~+h5^0vYt(KkPpDNvK;+YJJvP(2_8Cb^fk`*He!Nz15YJd8F#Xs;#{{Y#y z#2OXVg@=SS4-DPSw`QrO>vwN)1{g8eE+m#CxB{niZNnU3;E&61_$XiOzu{lmGvh{! z;SUIE8pflh-uQkUR!McaqLyJR+}y-e7~+g=+X@_DoRiN$KX1QgOdR z#-piT_)AH-y1cuUrGJ`vUd|?Y9oUl0%thm;V3-tN#F#Sn#*~j&{HLLw!g5 z5mWw6W5qxAIo*Hh4UK*O0AH1V@LcctqJQ@r{{Y(x`~Lv;PX7RtSok;p0Agm1{{W;g z*Q(dzxBM2b{!X95-}WY2{{ZQA^?s^;$=~v89|r#b>`c+W^nZpL`B(l6SN{MevEgs~ z9PNMfhWd~ABB%VC$BKXKbGrWk(i}fwf_Lp>+1bf{gc1s);Q%d0QfGx{{ZC5@~_*U_UHcqhSC23geU$e zpZG(+;TrpQ{KdZA_MfzUpZ=Idvv1k`^Sib=`+mdz3V)68yY_hfn|>DfYe|OV;t!3i zJSC)CU1@r3o<*gct7mJzIqun51`6-;#Ilg_GD+p0oLBrmJN~Gj{#}3l#a|_V!9xE4 zY7Ywj)_)o_Ul;g8Pu4W;Hp|2C=~6|l!xU2)Qs(ATz(*{DZrPA$Amko86Z>iVCx6MT zd>j7&v41m0{{Ye$Yggl^z`qE7(SHs#9|d^VPWyJ1b%`RHA{OGxa0p9?9D}k|+;DI~ z1(ky%GM_*AGy4Yo4fq%KOOFru3s1h*t^Ug(*7ec-p?D{Ql(>zh%E2jOT$mOxTWdx*ZmKox8Du401Fd>zckW_*QBpUfw_JRKZf@6FV z_}`^7X`UXp_;KPGp)uO(o)xx^)(}F;uuW*7MJn%*GY}G15vqw)3i7YnSN;hR;ID@k z)_U*7*SGQKiz1n%T`JmV{>8ToA~Zy+B0a-l4&f#uB345aZ4Td6YTvQnz^!Xaz0>YK z4}W+bJA1fZ-bb|1Ep4V%WhzQb8Y{-wJUTFCI3R)nub4h0f590(5O}9ux4-bNyW$T7 z+BNJFUFmU3x7PmvWmVfOP#Lotq4UFQAHG2|JnB$LD&EQ diff --git a/micropython/examples/badger2040w/examples/icon-rain.jpg b/micropython/examples/badger2040w/examples/icon-rain.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e0d536d5ad20963d36852fc17c062aa7088b89bc GIT binary patch literal 3324 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 T8mhDetU><2@KA6Z8GigPi%&B2 literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/icon-snow.jpg b/micropython/examples/badger2040w/examples/icon-snow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db18190d91d3ee3b13eb11bc6bb73fc0d3846536 GIT binary patch literal 4008 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 C5O>)C literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/icon-storm.jpg b/micropython/examples/badger2040w/examples/icon-storm.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b01a93712ab8beee8b2210795a688a880e44f54f GIT binary patch literal 3055 zcmbVO2UJvN7QQoYhTa*PvOo|l2tg4WMi{ChARQElNSOhoN)d=O4N9>@iXa+fuu+C0 zA|h%WG!&H(3(`A8i6}6Pk&H6K+kY@ebM~xzcK5#ao!j31?tkBZ9^QkGfXognYbziS z2;hMZz{iMJt8`iT7nI6;6zLt;>Eiy~ksK?`$rMo%qtslqm}20L&74e*5+2!arZ20io)Lz*aX zLUyw+#4lNlcR*3TC@Kj2P=p19Ln!zx#)DuDkPnj2y^W%;Ggwp+B+LNFLpc6c8$dV* zfPV_d=ZkTie*pj+0B8*R93RdA*z^wRPkq*D6#+=60^Df&tn?v3z?^jUll zhVDc<9e`5;Ah{br{t1AX=f}Pwo4^hiy8&EKuWZ`^3eEy74?wxSzQ9`q1$^q;fAsmQ ze|SHb14bkYP9!9Bl10d55{WD(EG#4Rh^R&(VG&U=apX`Z14IIb5lNV!YUG`W>_Czw%YC)hR7l>@M_6+|#o$m@vB)yB zntKXPPuW`Qd?OEwiYY27t1Qu8zGCGn9mDk-Hg4K%WNu+;wQalg4rdovH+Qsfe*QFi zKw!|msOXpjv2pR=eV=;dXj*zkW_C{Q>Ad_i1!pf@yma|WNoiU6wc6`-H|lRT+`9jB zQ*%q}gNKivbv*Cv>h9_78yy?}?ZwN9-(OA6a^C*&ZthR+`ws$M1i(Jh`o!#Cc%dc` zh$Iq55*F|x5M$AW$&$!ltre0pbrkm5FRy8ENQ7dRRa|pVblEy5wt{cuQ!zy?!%^*7 z0kuVD{~fWz{};1Q#6I)t0||_P77vpJ6W}{Dq<^jEuEc>yNp|5XRkg8ik4CfnXFFLr z#x>Pm9u;L*E|#~c%Czd_=DAy01dpWoaaR>zVHHcCrh&#Ytx zK98{}X}EcAU+TA<&AL6Vt}5SRmWGitbhlgVlb1Kl zTWbz3Got>Y+*cFy?Vpw@-a%RZSP<~7xkqpy2XmK>>ZdL7PB-*yH*fxKj!Bz47cS9f z`oha|vs_Ak_QvUveqGO{L0Rlqnp#=cYJgLHG@0#bFB12Cv%{{q{?Vc05x!z*8Na$@ z($9sXdh6>~J{(^kxv~RvyBSVOO-&e>nB5_a;~>RzW{2gBJrVG9>Gr*PY#2HeRFEaeYd|dSgCfOQn#^3>xBL4 z0*av#HJ+|Ezy(*Ll<^(|A~f6*fEiPueb&is z=n+s4W(;80v`CUfGI+xXHLNb7HV(Ks(oQkEOD; z-*HB4@>S0bwsxAe4_AMas(VcBL5cw@+=Rq6pUdMPHDvW!_1{ZoABt;FYAzi($JD5= ze`2S5z)FSYbUu398XJk}3R}l3oyTn(A<4!;s5%vgdXrI|r>s%sg(oU{le@Q_OF ziRo&MTLqjy-5wZlnx>oX_~|WOOZ&wlooZt6E_C@kwKF`rednX`ozE+-91Lb|xp{UK ztM`Ay zNp5TByrDV=9m|!1jLgn$2wXzEL!#UmUpPWpzbx{gNLaMpeJ=&NmqFYA$Ik z*Ul=5$z{gxyV~-Mc-QZK8f3x;=7PBRY*$OTe4OWq$&r!z4&K%guFu`)x>FjviZfp^ z`h&tUUPvC3tocTP-&uef!DlkdJVV%Fj$ z<5Ga+vX%5Es%VOd2O2c#HgB#@$yDq3FvPVjP*4`7U2G#u$-BkLV{yBu!eSI6)C{kk z-oBc6Rfn@mf@3wyD?h0XykdrQIm=hQ-`$*lB6(Dsg~Jh4hG>4q`s%Nxr>xhf*3Rpd zCk)w|zqz()Xdm`Z#y`#)`Ef{}&y4AxQB80uYEn~W)4E>& zT;@fKu}g~YZr@!T-&rgBR?+GvZSVWOa~ZMe*j#d>8n9>XKNfmrEYCil6JE?cxFglG hx2GSwvHqb}wzcjr%>{)SbUNMFS}P^`@7i|_@A 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 UXUEN_Tjk=|n0FGQtOy_f6Fh^dAOHXW literal 0 HcmV?d00001 diff --git a/micropython/examples/badger2040w/examples/icon-weather.jpg b/micropython/examples/badger2040w/examples/icon-weather.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b01a93712ab8beee8b2210795a688a880e44f54f GIT binary patch literal 3055 zcmbVO2UJvN7QQoYhTa*PvOo|l2tg4WMi{ChARQElNSOhoN)d=O4N9>@iXa+fuu+C0 zA|h%WG!&H(3(`A8i6}6Pk&H6K+kY@ebM~xzcK5#ao!j31?tkBZ9^QkGfXognYbziS z2;hMZz{iMJt8`iT7nI6;6zLt;>Eiy~ksK?`$rMo%qtslqm}20L&74e*5+2!arZ20io)Lz*aX zLUyw+#4lNlcR*3TC@Kj2P=p19Ln!zx#)DuDkPnj2y^W%;Ggwp+B+LNFLpc6c8$dV* zfPV_d=ZkTie*pj+0B8*R93RdA*z^wRPkq*D6#+=60^Df&tn?v3z?^jUll zhVDc<9e`5;Ah{br{t1AX=f}Pwo4^hiy8&EKuWZ`^3eEy74?wxSzQ9`q1$^q;fAsmQ ze|SHb14bkYP9!9Bl10d55{WD(EG#4Rh^R&(VG&U=apX`Z14IIb5lNV!YUG`W>_Czw%YC)hR7l>@M_6+|#o$m@vB)yB zntKXPPuW`Qd?OEwiYY27t1Qu8zGCGn9mDk-Hg4K%WNu+;wQalg4rdovH+Qsfe*QFi zKw!|msOXpjv2pR=eV=;dXj*zkW_C{Q>Ad_i1!pf@yma|WNoiU6wc6`-H|lRT+`9jB zQ*%q}gNKivbv*Cv>h9_78yy?}?ZwN9-(OA6a^C*&ZthR+`ws$M1i(Jh`o!#Cc%dc` zh$Iq55*F|x5M$AW$&$!ltre0pbrkm5FRy8ENQ7dRRa|pVblEy5wt{cuQ!zy?!%^*7 z0kuVD{~fWz{};1Q#6I)t0||_P77vpJ6W}{Dq<^jEuEc>yNp|5XRkg8ik4CfnXFFLr z#x>Pm9u;L*E|#~c%Czd_=DAy01dpWoaaR>zVHHcCrh&#Ytx zK98{}X}EcAU+TA<&AL6Vt}5SRmWGitbhlgVlb1Kl zTWbz3Got>Y+*cFy?Vpw@-a%RZSP<~7xkqpy2XmK>>ZdL7PB-*yH*fxKj!Bz47cS9f z`oha|vs_Ak_QvUveqGO{L0Rlqnp#=cYJgLHG@0#bFB12Cv%{{q{?Vc05x!z*8Na$@ z($9sXdh6>~J{(^kxv~RvyBSVOO-&e>nB5_a;~>RzW{2gBJrVG9>Gr*PY#2HeRFEaeYd|dSgCfOQn#^3>xBL4 z0*av#HJ+|Ezy(*Ll<^(|A~f6*fEiPueb&is z=n+s4W(;80v`CUfGI+xXHLNb7HV(Ks(oQkEOD; z-*HB4@>S0bwsxAe4_AMas(VcBL5cw@+=Rq6pUdMPHDvW!_1{ZoABt;FYAzi($JD5= ze`2S5z)FSYbUu398XJk}3R}l3oyTn(A<4!;s5%vgdXrI|r>s%sg(oU{le@Q_OF ziRo&MTLqjy-5wZlnx>oX_~|WOOZ&wlooZt6E_C@kwKF`rednX`ozE+-91Lb|xp{UK ztM`Ay zNp5TByrDV=9m|!1jLgn$2wXzEL!#UmUpPWpzbx{gNLaMpeJ=&NmqFYA$Ik z*Ul=5$z{gxyV~-Mc-QZK8f3x;=7PBRY*$OTe4OWq$&r!z4&K%guFu`)x>FjviZfp^ z`h&tUUPvC3tocTP-&uef!DlkdJVV%Fj$ z<5Ga+vX%5Es%VOd2O2c#HgB#@$yDq3FvPVjP*4`7U2G#u$-BkLV{yBu!eSI6)C{kk z-oBc6Rfn@mf@3wyD?h0XykdrQIm=hQ-`$*lB6(Dsg~Jh4hG>4q`s%Nxr>xhf*3Rpd zCk)w|zqz()Xdm`Z#y`#)`Ef{}&y4AxQB80uYEn~W)4E>& zT;@fKu}g~YZr@!T-&rgBR?+GvZSVWOa~ZMe*j#d>8n9>XKNfmrEYCil6JE?cxFglG hx2GSwvHqb}wzcjr%>{)SbUNMFS}P^` Date: Fri, 27 Jan 2023 11:23:01 +0000 Subject: [PATCH 30/46] Badger2040W: Bump MicroPython to 67fac4e. --- .github/workflows/micropython-badger2040w.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/micropython-badger2040w.yml b/.github/workflows/micropython-badger2040w.yml index bf57db08..50f8080c 100644 --- a/.github/workflows/micropython-badger2040w.yml +++ b/.github/workflows/micropython-badger2040w.yml @@ -7,7 +7,7 @@ on: types: [created] env: - MICROPYTHON_VERSION: eefd946e60aba3ac61c7bfbd0272d07be289e3f3 + MICROPYTHON_VERSION: 67fac4ebc53db6337008ba06df7932faec80f57c BOARD_TYPE: PIMORONI_BADGER2040W # MicroPython version will be contained in github.event.release.tag_name for releases RELEASE_FILE: pimoroni-badger2040w-${{github.event.release.tag_name || github.sha}}-micropython From a70ce8a4a64e96120d7b88a1d590097d6cd83119 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 27 Jan 2023 13:00:39 +0000 Subject: [PATCH 31/46] Badger2040W: Call wrapped-update in lib. --- micropython/examples/badger2040w/lib/badger2040w.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/examples/badger2040w/lib/badger2040w.py b/micropython/examples/badger2040w/lib/badger2040w.py index 5e277118..f5a6f7f5 100644 --- a/micropython/examples/badger2040w/lib/badger2040w.py +++ b/micropython/examples/badger2040w/lib/badger2040w.py @@ -152,7 +152,7 @@ class Badger2040W(): self.display.text(ip, 10, 30, 300, 0.5) else: self.display.text("Connecting...", 10, 10, 300, 0.5) - self.display.update() + self.update() def isconnected(self): return network.WLAN(network.STA_IF).isconnected() From 9ea196adb1d4a715e7ffec27f261679f026d6146 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 27 Jan 2023 13:01:40 +0000 Subject: [PATCH 32/46] Badger2040W: Tidyup icons, crop to 52x52. --- .../badger2040w/examples/icon-badge.jpg | Bin 1967 -> 1793 bytes .../badger2040w/examples/icon-clock.jpg | Bin 2075 -> 1928 bytes .../badger2040w/examples/icon-ebook.jpg | Bin 1851 -> 1623 bytes .../badger2040w/examples/icon-fonts.jpg | Bin 1398 -> 1195 bytes .../badger2040w/examples/icon-help.jpg | Bin 2345 -> 2151 bytes .../badger2040w/examples/icon-image.jpg | Bin 1268 -> 1367 bytes .../badger2040w/examples/icon-info.jpg | Bin 2261 -> 2062 bytes .../badger2040w/examples/icon-list.jpg | Bin 1654 -> 1548 bytes .../badger2040w/examples/icon-net-info.jpg | Bin 2918 -> 1485 bytes .../badger2040w/examples/icon-news.jpg | Bin 3238 -> 1987 bytes .../badger2040w/examples/icon-qrgen.jpg | Bin 3443 -> 2593 bytes .../badger2040w/examples/icon-weather.jpg | Bin 3055 -> 1591 bytes micropython/examples/badger2040w/launcher.py | 2 +- 13 files changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/examples/badger2040w/examples/icon-badge.jpg b/micropython/examples/badger2040w/examples/icon-badge.jpg index 1dffe94a146b792dc24cd201487fbf3078ffab5f..0b86070d49d70bde119e5820f1fe26cc408e48c5 100644 GIT binary patch literal 1793 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 diff --git a/micropython/examples/badger2040w/examples/icon-ebook.jpg b/micropython/examples/badger2040w/examples/icon-ebook.jpg index 02cf932d54d48c9a3e2c6c2a27f10fe30849c704..4e7551fc8cc3443f50aa05b8d9a18f36cbd7298c 100644 GIT binary patch delta 1572 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 diff --git a/micropython/examples/badger2040w/examples/icon-fonts.jpg b/micropython/examples/badger2040w/examples/icon-fonts.jpg index 8a0e9aadb3456c0d44437a833fd8d72c35cfd69d..cef072f6b9265f726baf5057625ed639787a5fba 100644 GIT binary patch literal 1195 zcmex=``2_j6xdp@o1cgOJMMZh|#U;coyG6VInuyV4pa*FVB^NNrR z{vTiv{LcZ1_a>bU}s?kN|^~TFfg;RFtM|F1D+1Ld+goH&n6-C7)3@uu>N-C)u8HZ0351V@V%2J>{5fszF=7K~8k?nwp-eTZk zW(2y0S&+e=VO0(rU$)qht8xvl@ro0z)+--gVG=-f7?*P8I{v` zUO+wK&Q8hpGXmjjZV5_6UzCfzb}CVElZK;~itzqM6?eLR{=$xnh z)O*H*DW9uZdwechGO?aH

+P|t_!|Tm=mK{Q+nCn_{;Ha+&>N^oDhB8#;S9~HKOl|WS_l-rQ2dDsTWT7WrNH0 zCUGu^X|>*XMqJBPaA*6B{(>Tg2@$6kZGbxa@fF8!-0U}B=!*n&*+_?;Wj#CRh$5Gn z(K3dO&J)-xJ`3EMVe+ui+fcCWq}_rug+C9TGL^WOy^y=6)c4LV|85MkFaL3PvRo?r za8&w~#I8O1ybaC@1HgOUP+_}&KV8EWa=^JPoUpZRO} zw&|aN1djlJmwDf=nNR1YV|{+z$e zc0>FzX2xcQNBynlnO?7rL+Y=}tt+{9{o&mByBRNbEor}cSJ?E+=9+~$*Pds0WX;hF zICr*0D{{H4`8B)NyEXoqTd!TK3awu{=V$Kf>CdE}?$^G-*kvVoE2!1y%Hw6fc3zH- z?|f?>Wu@<_|7G)J(=VI;9L%}?JewmmN3USno9nTuv-*E61{-C(`gd$@dT79}-HV@Y bTbDm2f7+e(1-yR_Bmh0c#?07o@c&H!2*S-B delta 1345 zcmaJa*WHih7S90o+w;596p(4 zZn1dD(q+q6xw(6IuJ+!z=_{Yjz5&~J1VTZ@76RnHFH~j`St#TPC?hB?w-fO-hsiV z&z=trkBBEEQrVxcCa0!fE8o4J`=I)$p4T8^fccb}0Q3KUJm^~`7AlyT2ba*6T0uXRYb?UG3*$n2!OL`mmSq!4G56+ z5+*)CXu=dxeI5Z>az}VK^FNX)zm*8+*w3>%yHkmPoHpk>X|x{e#2A>BR29>gdMF;c zSJ~9t;If(2;vC@PdM>y~^)2)8Qv9|TCc&XXAmHNaLJyE3N60|KmCw(JCq0Ww&No0POtx6L<{mt9C$H}BE zfe!I43G|o2y+WIKOlNT1(uL4?z2Is{)bZf)Z+j#=^uF8x& zt=*eel|PynkAUW&{CV|gv;L3CGOHS%ogv$D1WZKfA{4ZI{savHM-b47V@D?<;4lI% zCiH59MkYhf8hoiqtu3)BgZYzYRhh+64ET4R=QBK30a;4Obnji925Jl;Cwa@Z?#aGr z{7nh>dhi%Ei=FfJ@%9Ua{`NW*B-p1j*jEUZ#t5*;n}u;fx{X)55ujPiuqG&~d4_j# z=U6(sOR8)&OUf9bth-If=FjZrB49xNT2l*S?jpdgLBi0kc*~#5={C4m)Fg`c6!NPMOqbp+<}vTQ z>{JaAQ%|hDC$hU6Rq*8eg1XAAN^5_op?-4n*o;tdW~=^I=9<^(37uDrr^Ur37rE41 zq`t6)(T}`stIF!GyVM=5T>}CjBaD*``7)u&ttgfQ50EXq`$K!j!Ut(*NtL7fqhEA2 z3h-g4ZQG9JV<;3?d#5aOQ-1lZWu}O1iO1H9<(UrZBjX6Lk`r5bqUz~%ESuYfyTLqq z&1J!TBE<)v<5JEM{!c>a-w|`)al}3Fo>-~7o?a?~ulAGA5gJnsx9Q+(SIp7$UOD_K zUmelV_GbtX4ys9TS07pL#pBfQ$8#C)s4G1Y(D0ia0l`P9vl@>&#^N;6E~O|tnSqt3 z@ROb-=Xo}3<+Sz8_dgdeIO!&HE?EtAQG#9Y*3@>qI|9%X`rB<-3EQEo)LkGlRAS4F zZ+3x5^^)mcgb#HsP(AD*3Osxc`u8~HYKUzSQu0iKB2`6KMsnzW&S?bL7Mu87=&e2m zHP5bVY3I1+-a2%1(L~i%S-$SYaZ_J@76XMh*W%KMasgy@>T`9_oExcj=&4(aHtr*i f6<4?^V-R<*_tDaJpZWB-GL6Zi@Er!)BO`wSz1y&C diff --git a/micropython/examples/badger2040w/examples/icon-help.jpg b/micropython/examples/badger2040w/examples/icon-help.jpg index 2306f27ba60f0bf937a406be4bdd5c016b0bc262..80c3f6f5d64f21e091841339898293cda98a7473 100644 GIT binary patch delta 2104 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 Vb|smanTaHm&{0JcQAHG2|JjpxgMk15 diff --git a/micropython/examples/badger2040w/examples/icon-image.jpg b/micropython/examples/badger2040w/examples/icon-image.jpg index 5b6c26713ee1f9e6cd0ba609382b797c0ff3cafa..e8ab644ac187be05cf38e6d9c389edf1373218d2 100644 GIT binary patch literal 1367 zcmex=``2_j6xdp@o1cgOJMMZh|#U;coyG6VInuyV4pa*FVB^NNrR z{vTivGFrpX;(h3q4#1y^7 zzyq|LNsw8P!Jc8;%tz-%_K|RvTzo*a&eZnh%6v7a-!I-UbDq|V%=z-4LHF9CbmOfeHpfz>Jx?ViEmnGY!aT0_ za&t!SVWZrTj?U1Ksi8nnAQXPr?nGVh?f(q7KG+{^uzUH<`AgpYf7cuT=`eox-z2}d z>_5Y|J^UXNMDoSGtG#Z=oVZ+c%5B!|r>@9R5YYP0-%1f>PixnAXCf_)vcRKK@%cE-hg-cV7 zRxA;!II(ET;Sx0#$LUd-4)LXxojdufow!yg`I$XvW!x;b-AGLA`Q@)~wKKHao^J~8 zye6bKvA1+OOT+BK&2m9no!ip57On7TS*4=V;UTr^-|;l3mtnzK>sD_wm#Yjo8yEgq zc~NG^-E(3cKyXT-qf4QKO99ASq@<)!{xfWHnzNR95#RRZZ>AO+GNmj~D>^YN&XmoH z;|%AqiRZjlyYAeeSP)pEARBPJK)^#LZM3BI?(@J7L!pf98~IJXQNe zBIwDXU5A(buAX<@_gs(nZpT1zkK~Y`x3>gi_da@Ak-L`JH^}HzUVB}%!Zc^Eg|Xd@ zJ?g#7q{JF}-E;yyT?9h|1x>HJ_%CCwCnjrgU7s=M$hDsrcNJOQdFQVG+w;PV2?tKE zoZZeiJ0;KO#n5|D<%K{ literal 1268 zcma)5TTqin7~KGYkRSw1Al5pJ6$w|Za;LOGAdx^RBM6b8WUN3zMg);~LsCEmqZmab zHN%uKAQ7!nPy&J)F+q&9mHS1D!Emzzk|+&Ol%`LfDdZ~>6!)1Z6vg&HJ=vvM7`rCIJ#EngNn;%JKZI9cZ$e(ui^!D`+3=Tbi zr5qg_pO}38#~by#_j7-0=Cuop@HxONkBtHh(L$~h!rIANB}WDU7lKC74Elz4zx1f2 zC?I0@ttkfM<)^A2E3dWh+rQ6b)6>p8T$sD^l6y?S=YD%66YK-=@k?tmb>BeHwHbn^ zOMD3Ao*d~dN~&Vfk+s0;hG4;wr_FAk`2vEF4hUQqSr9mML15Wr5OH2#=8SW~As7>A zYPAlcnP8*q_Efav=TYG`WHITaidGl)t`_tNgMqBRm9q z{<>V}Ow9!lv~Hk`>AqUU`8^VXh(p;r1C_uSvC`X&E=Asc#Wx_$%?%u4NqRpj#?Zae zNZIknH;2DC*n4Yt*#yq}Qb>2(YFd40O?iD~1U}gqJo$b!@V?Q;#EPkdi+mg zVuu}7!HkhYJwfs?!Nb7!qHq)Z1q!LZq_BFI52MR%oSxirKV@F3aSESx^|kt$UR>=g z^$Sg4>dVx%Gp9!tcDcQoIT^cxlh{|xUJ`&cPxD!X-?lZZd=fid@k@xK$pYS z2dSir;n|@xnvG9bV%|UY_aV?A!_7aOR#B&r9h=1u=Insr z1drP1Cg_Ojtm;hYBexD)Tz{l44PTvTn#d`kZ%1!z%1z_^Hv_p;J@N$kK6tkyi6`^tIO!K7d_ZtG_!n3kRo+*zXwv`=0xtQ9|xqSGaLJ1uD3nxEeJpcdz diff --git a/micropython/examples/badger2040w/examples/icon-info.jpg b/micropython/examples/badger2040w/examples/icon-info.jpg index 447205063c2fc3ac26750246e2e20fca9c8a88dc..4a43961be38aac54fd2a9f3f33659530899bfac9 100644 GIT binary patch delta 2014 zcmb7^c{~%0AICR4vT|&rB|K%rkRw+;(cvC3#}JX6BWEZNa%_&um5RvppfYoxV=<)> zMvj$d&aFdu$Q?aOSRTLQ^?N=4{ywkQ_n*)A`+a}De|<*~cj3t0@!d%P+!A*l2LSF# z4XBodv>@{VCO{Av3;{!65C}|C^nj@3|E=A2074j`3(y4t5da|s5QG5kb^)aKVgR7M z`k!FJ0O&plc(11c2M7u6 zg5*Cr{{jBXMf`*QUzZ0E0Ri`}03iSd0LOD+^ACq|)DQCiEV!LJ6i`>Ym3V_T zC*wu=1qIoq9Y5_HK=78y!vgra1l3^XX!+vy(UM(&0rzKdi@1pD4(zu|w~4Mq6@{zj6G=0M z)QF7gE!8^x6ERgrR~8r44l{F0Um1>C`PV+;+TpPEQukirIGh4hH;%w@F#Y}+fr zE}&vrjf89T{Z(tp)4~eby9<~p5rYw}$S_R}t$Kt&Z?v_n`*_sEpuyt{nbtIQnt$7d z86!o}a8~qCRdpYrsA5(|@_t8rPN)10BIviYe!?5?ikY=M)tT^SdsN`N@}WR?s+63k z)IbMJq^rYp0FTGV0a*nOjoK@7p;TkK;x%0a0%!Rn=qq(fgh(U6cYP-@DGJWcV0Pp(O2UIvB}*!M2R_o+=@(9Wds4=38!)K&8ISNnKj_n z6@F1-n>&O@)Ah6e&$)v|aVX?0ED;qjKtwq3#~vY(FZq{M&UDYeaOPmVFW6J`CP z-vd{szv<9er4#BnL2r?e841zOF)|8yP4$JNSsHi*@4(uo$XI*o4!M2t63@9wg6()A zQr>=H|EVhCCl$qVuV<5angqCeUq6NA1wE0Kk>t2@PsIMP?I-j^8q@{xneJ7q&t+VT3x5gN5O8c#8N4jV{h8N-HscIMMVM!dw6bZ-ZsYMFKn_UI4#(v_n!I_xz$sY-#Oh8 z*RidU;xaB1ft;3ODwdBrO08Uu@L^Iky1dSdR~#RbPJLjJ-gf!CLEz-)+hd3{@xD(Ja~IG`Exv&F?Q+8c=xfT;p@^5-P9)n67b_C z*0bDHO6HSdIUEKG`nXVLty$uf3M&;T%`~4H`HGYZ?9Tv{TuDoK z$nR-KZQyRNNOY44)w5rsZp_QlhDxeil#ga`)US&{TugJaW#qA^@yYT(;1A&)vbSOr z*7Nuu!+3|}sau_;>(WlQ?H}xuw-;Q0?UUc=jbiAxYzv-;`#+|U=&-3UW3W-LN?DHv zIepZ5qXs|fV-IococC{bc&&erX$RJ9xF&QFXGQtsJCpw{N78V)>x|gs8QKD=#GyN4 zuDS5n`)^PAe99>AV~pro1?i?=u&;?o6LnWGMbBf1Yxu-t-Z!6kcTN*6bdCjZ4=3Ij&qLyRh@JRkMU!tygtz%6cTU%fwwS< zI~(qHb1~t~l!M$;74*lv8MkD^u1(+1ey3G!-rpH*?n8?~>6tHb3D#N2wA=!d+Im@- zX^1vdv5C_y(bRt77tC@qO#rQCd{!4v;nsoaO*6=QzO%{`ONw-^o?bEs8l692j!5N! Oy+I{ABAZ8dC;kQ;a+mu6 delta 2215 zcmV;Y2w3-y5Y-V9|JeWF01!$>Nk#wx0RR9200EH_NPoZp3kU!}06+l&5diLo_va__cwzs&sy28W6#m2|T$;#5x)YaD4*xB0Q;^XAy=I7|?>hbdP^!4`l z`1$((+5iXv0RR9$0R2;Qh@w3k8xn z($yp|Fk_9f1tf+8J6jz80ENHcq(8H7j5XU`BE#aApKo_@yJVWBmENCjHmPI2dx&F+ zI8%+xGH?b-0R0uD>ef2`m1U{vm$v$jn|lge+TL19vco)1p^`*(Br>v)Ljpkr5mxA; zxPPyW9~Znk@E75Kh&+4ZsV*bXv{+VI#iS-#q-J%FIMH|oo<~Flh)`G-Wl>HTc)# zf9(;4Gu z@I%J>7Pl9GJ}LNt^{qbjwArsEys_17>~5lEGh5FLF+{>uQ-X#>Wh|tE2GjEgjeZDz z(I4@p{jmNVU0%J9_BV|5A0`cdO^F!Whmb#)JPvc1r1In;2`+^hTW|{`pGwhRjeqb_ zZ-{;`{j7g%ohRTggKxgqqUkrb`enVPt;x8vlTviub9p$1GRyXLk>YTC&n0c=VYIx9 zU#UN{ufT5({>{G#^e+Q=cG}%i%6}AV`{-aXHl=z|MAvcx%y&r3oEB}05ftr316$*N zg0H?Md>8Tegfz)*;MBGM01xUKRjjvc%L+?9w2>n@Rbmt~f=C48I0vPEdj9~yG5-Kz zuZ&*+{y6JCGx7eL{{RSnl^%;GpB)1GAb$%Xm233V zR?=*B{VMlN)a6yj zb@a_!#Lx>yk~nQ|Zf@a@LW{hTzFpkt70X~SJg^KuXY25<{t6fS8T?E5Kd$(L;@6El zVW;@FO7Rzop2p7RTgfHW9UW$p+|IveiWJ)oxI(cIiG@^9fMe>f_5$YP=i{anwk)&H{6B)k3k|oS-6inG=i*2+aV+UgGJ5&~I{*_nfSNs;!!rEQm zz%K&$l3QK+)}P{Gr`uflj6Aq5EoYKs+78pXtzbDIk+XsUZ2cGi00i*yt@n@r0Ak;T zTAra5yf+YOkEJTxD}O4Otml@_CLx%e#yfN@bArW)0ALTItMP;O8j{EMRQ~{inE0RJ zscBke?yEektK_s-QpXf(r*=yQvXrnO02we&NPizif597kEvk5b_D8(G zzqR{4rn%y4-9t~4%vST@Sgq}g;1XB&*3&K<2jtE$K|gg@=3o34+-Mu3eWp0Yn~tRQhw523B3CU z**?UY>swsBH}%39#7s*TCDTMVVleii#ae$oE`wAB9q3H&Ya z58!8j^$i=uo(;Xek6zYgwTfp~l6#rf-f?#jg2x2Rq)JQ3@hDQHGB@h?$Di6Oz+ba( zgKm69E@sI53 zsa!MK&GyC6FLg0*ePwVi6{2ekrrI{ft&!(QvM-U5B&^^sn*RX9eg4oeo0yjxEe3D=X_{{V-xe$w9-f8vzzZ-%@-4~aDo z_G pRjy=~X-I2}*~kIzCvXP&TWHC^00mVFiVUhf0*WZ2iYTJL|JiisMD+jw diff --git a/micropython/examples/badger2040w/examples/icon-list.jpg b/micropython/examples/badger2040w/examples/icon-list.jpg index f1d8ac2b684c2851511d6bf2d30f868fd54b7913..e9552dda805da9fbda03a7d5640139954aab2167 100644 GIT binary patch literal 1548 zcmb7@Yc$k(7{~u}Gc#re!we?Wy2QjJqO6f^Fz(vi#wEM5n;J^SxD`?^$z|hEky~@r zm{DU<3{r`4P)bSTQY48mMlMUpZFcOw*zLu>*w1;+bI$L1&hve~FMf~YjpPHM;AH1$ z2Y{rIKqLT=3<5R)1PtB^DNt#^5HJ`N3X_GyWe{jtG#Vv~LSf_-6)z!94w4$eQxV2-_aoo46TMAoM>^Hmqsty2X2uNxPf&~r&pPBU9-XeAtFIH~mj%v*M zfWtDdz8Src*|KljAkTQW4l%9h7Ewp-h4}pD$ux>qB~;wy5x5hgTxc6yJ^I*9{s7FS1%5y1n9`>vJO4&xPO1 zNKA_u^3;%5>p}z`p+$t$P(3GUJ&D}2UagIm8De&Fg=i%xo%vfE$Rv+C&Vg(Lpra1s z4p~{(ffNC?()k>IciR5IycqTo&RRf%&B7IO@ait zQ1G<~0{#>h9C7~)?-tMEF?(aj4O=Vq#z~gP<@6qbTBt&B%qXt2@N@*VYe?MTZNzAQ zQF6T7NMW9tJ$DZ~OEOhEO#aTzkbPpRZa{xLFq1zba_M&tY_#Sjl(dB!1fzEj33{Rk z^Fp7Bkd9I`IT>pbk2S&lblt}0Hth)w55kiXPk|QYs`=CdZA+cv$pX*Fdd(k8nbo)L z#}$`cjxz_wUE7H*1z7EhtZU3#t>=FB<$968zG#DUq+ZK~j8#=NX!)h8;>*L2qv(^J zAsGK-2Pfz&WgB(yP1!oe+7AEXzUnWjB8G-;w3{GY561SJws_RvYR>Yz%oiPQWW^JR z#QoL3v@f0z`r0nJ@6-8sT8~3e3O^(}{&^~jlHK=%Qgjkep8^#vJ{U;I;{>^>B9rC4 zk+Fk^s&b~<=k*E6J^cD8q}iR~;JRvn>Xw)oVzo_$hH@8SFtd1}wI1|m401r8;?eI{ zlTpXn<>+!CiIGc>Ur(QY$wPX2zwBu{=I37xsINURuNS#faW*u!{L{4LEy(FE{QZa|^Bk<9;FYs6lb%Y!ot%O}yD^mB&RSrcjQ4+BxcV2f;kT!n z<|b#&1I(uwP1XGuM!MgJ3!0Di3D<bp zGto^^G4@aK=ZGk;GP6x#Hr69{J6DrDu)B~Ol=X3+9Ac82f;~!hkWn&`pMF)BeMiYv XWZLQAXgz#a8QkoH0tJwENZ$SlG0}>b delta 1603 zcmbVM_g7PQ9Q}qRs}hJKI0`sOG>!_Qf|Xc6Kv1HBL=$TS4d4P%kYFM2)PVw81qIxL z?Vvd*0-{X_dpR&dB&Z=GN>nfm<0E-_-#**^1^xW`x#xcF=iYPfNo%dO9efFU06D;S zwJ#u%03ZQUhMhlB4Xn(;O0bedvIVdXI1md{(mw}r|IcYN0 ze#&fT8hy^(#coTME_3(r_F3hN`1!962oBj8%HFh@vwa6YA~I^{t^;xL2NMK|hmIUQ zmU8?=YFg&mb6MFr=Pz8$&C4$+EGoWv>+Zd>`{fmt52|Wv>*^aCo0?mm%U*PJ%3pRV zRBwCV^}YYlul_hRJTm%K`wbn_K?N}X{xcI8f^*a8xoM0VN%X?>H#1PgR?k338gNSH z8ym9vS@){Q6>T&4$BL>_UNw<5ZRxHqDW(Z?2Se?H(UKlfmt1?&P&RrqDW;I~$-%DV zv$KcmE`{>M^~BsA8_!q&@VYwr`WCaEy=}**y|1!C;~NK-L*Ua20Yk@wU{*T><0}nC zNdE<-4+(_e-9;v%k~@@rF;Es_A~k}Y^}{@RwO1g>)2%Y~rCo1TFd}|Ab13^T0({R4ibYBj= zcV2&sNj{+7wicl~V^Dge!N}7QQB@v?;LPq(z1DSTX&sX)e07dfvFz^ zXDR3<2=+ZScyQRwJPnJbI8r0I8~NF-MDVa)CoC;iS4eCNpXa6fq|Ax16JOX%51*C2 zsAA6o*UbHX)BUwJXfjV~qnjvpM0%tz=pmOXi5jv=!@d%G1 zxG@z$73|xy@BseyH`V3!s)TL(7+PGskvNkFL31j$7J|x1{K|Yr9}lJZrHaV{rq*^S zNHlcU!RD2~OZnDB93pg*vDbOWbxzuKHN?!_zEANyxqcp{jb=$bO%SDI6J&`91kYxw zAi$@lO2*8@64c^t%<-!~p{yH(4$Cmv0A?Kffl$;~pe|xnOpVOocai>ZxhCFxVEE+a zs|U`G$@LKsNN2mT$Vq;sL$vDF6`ryHc}(aE_R7jDdrL+W4vhTj#ljxO&$l!aJk{mL zZOcfO>FIcjC)toGo`%p;uqD@`JEF_i-uX0AH>o%HvT@2x+K#{nM`Mk=j1nUw6EGOpAL*PssT8gW#>Eg;nr;spZ7pGAxCg4KBX=#Gcu~JiC zUsSi#jl05kD*r)9*5Xf_TAFS73ku!yspF3>sm&xIq5Vu%1M@4FIs5{GL4_Uy?G|)0 z1lDp5t(G~SSx!VV6R+2^u{C(Jmbd&#RW|aKtBn5nwM6hCTJU7tt#)3TQp1sqc_3EE z%L}_9D3EvPgSYO~`(xx%LmqA+C{jJSar0GFr|#9FTgvVkP0s=+G%pTXUm0)bgIvm) zyEy^0_=k;o6YUU!Dk1P@)k1(#mB{dP2TdRA6a=G-F(%>isc#TCeJ_#!35)v?5Z=&} zR^>Es0#Iec*2(wjn)BzE1CmuD=1C CYBgX0 diff --git a/micropython/examples/badger2040w/examples/icon-net-info.jpg b/micropython/examples/badger2040w/examples/icon-net-info.jpg index a8a5cdd9ca17c3eb0cd229d3cbed1abf48956909..f581777378dd81ed0b3fe74548a16f4c7ef65d05 100644 GIT binary patch delta 1342 zcmV-E1;P5}7R?Kg6_dvTkAE}(Gy?$<00I#K0}%oL!~h!r00IL60RaF20000000000 z00;&L2?_)S|HJ?=5C8!K0|NsC0S5&D0000000IF61O)~X00$8W2@@0*A|V(VBQaK$ z)Fv`lmec>l02KiN0RR910000000000000000{_GS6cGUc000000Dk}g0000000000 z|Jncy0|5X65d#qbKLFFartG2E^eI)ljPU7QWH@OO@KxDDi;Vj0@+sY zS-cNbW;sl=tcY~ecz?<)d2yyb^Gzu(0&WbDLnIy%NdOU56;MZ>5ImoKM)!V}us?5| z{LKY{ww>;4k-QQ22W@Hf41w~I4UVk(f_Jf{V!e;*f_1C`@ z8YK7?i;D7&^tV#jB3O|qLKuV1i%*z@K^1ML$xTp<&=APnE=V4YhwQg+Qe#J`Ztd41 zyHW?6b!fK9s}OMq4N12ja6GPyf#c;sSRmxl2)-tO+F0EJ^!2x%x7xOz-0Lwu|-o2%Ibh@ccM5bHyi#hOl z9VygW%kDhjppq+UlGX6VRFQc=LgZ6|MCBASx2g`;d!f_KDy4GLUXQpIOa@9!s--o* z1h{Pox0{c|A|*jWGx;=5q60){<4?#Yoi_F1)y+R{7Jmh+WmGqcl@e>MrGBYGsa7O3 zYJz1PR+!tr|D`;YJJO7kzBZ4d&KR(Zg^zQh(0uP z$si5TMny#1#SD;-G*J>nB@jTbUiQ0-KC07}j^5hzI%+b4JePVWL*G*+af4QEPVPW}k3TrDfo#(&Yr0?_x>?gMg|f!3hfR zzeN>K%`_iZKxi>O&Fw9|`-Qu8Nc)8{J-tbF>3>pX-j7ads#OPbUL0+tbY5_sGS4Tx zN`sP@&wwD&EurnTup2`ewQ9(Zchr%W7&-aUYS3CT$0i4S?kfGW7odBt#HZ2ctk}4Fbd0pIQv`bzsq@ z!KBBp-FE}e$EHD+>y0wlw$~>l)Im_iw|^Xtiq>tBqpOJ~DyRv*#&@8(CvH7D9_-te z{2MY?EI(4V;z=10O;s^`fZlh?(EU(=Q4fX4a#8V^Yc_z;8UsLR5q|4EDP8?UZN;^5 z*+K5LTQAnU?E$8gq)%b=XEI??eonXP(NV5BaR{+o#6iH#jg0O0yxYmR^y_kcl{0Wy zl&3j*b$;Zd$cr8$0;!n_I3ebBc|;b4c_m+}h#{DVLHYwgXbl0NGzNgs8UsQ9*^o(A Aga7~l literal 2918 zcmbVM3p|wR8h_?yT!t|WQEgbGl%(9cY&D8VkxMQ~R*W#a##r~Q$w(=*Qi+MSD79MI zluKA5j0#&s*0o$}ql-mq&ZIHlc}Kh3{?6}oe&?KLzHi?D?|Gj8`#%5Yecuo3#s)!k zi>!VNOUCs%_R}3MqR+-M6EWf!_IG2ln6y&Y%na5Cv=qfk-e$ zV<_@OfGdh``~-jQEZ-Ti{1J-{EX1$@E^xqamJhN$Ksm@h_BJBW%yia;qih5qJ;typ z0|0V5z|3(Bdw(9oW-b5_`T=f*e&lm=0am?5{^K8gj2r;!A%Gjgk3N3^K=}~>t)4Ky zaKG7g2A3)g)K)nq>(fdQ+P)rtwyew^h~nSXeKf}-XeE$z7m3l|wKUSe)xxpLL&HP$wpZ0$DNZ`tnV?%|0x zjuo&cFesS)RYYV|bWH5Gdk-E;JbWZ6Ipt*fsf8$Jvc^5DJkbn8dg5r|WvK!?U zl|R=v2pezTx!cs--tn;W*RJlK-l5?qPk(zhGWz_*x71X_ya{v zhWU`eq)ghZvj0w4!vCf0FJT{b^#X-}Lz_pS0TX7n=i=iP!4Uo&s5uw}*Y@QPkzX~A zc!{qFeR~%$(sU*rMz@sjO=>;Gk3Ey2`);8Z`TNOn=f;(^6p*|WXJJ4p6bpu_>#0Ps zNrRMHn%$H;Ri?n`G|~Njd;!nt{pG`L&IN0itz2weVcCWouAO+p?~ReBaHY=XwNl$$ zf^B^IcgH-(+y9!Br*TC=JB4T3!-xv**;IFQV+If zV6czYPsp@MlzT>sPVBW}Zej*G$!Z__;%SfAQ|Q|xWu!AF9bOjP$WFeK&5u5lwdkE5 zn|ktfi0dU$dJ0VADm(YCx!BypRW;hC zD*63Jzn=QjSuWPixIvxbG>N*|u57hjs_yRtJb4x|$fgceq~ ztDG?6Xf^dW#;;GAC_nUuNeK4%dC}oF9A?9`@zwE?=e<4!-rfzBM{nG1Bkd|No3FA} z{UK^-j>2f%>b9$;PHMru{3LVlpK60U%C@>ymY?~W>@!)hq`01*`+G@{8{Mss8AGi2@7`#$Khhl4| zu|=N~@FKcu9$oVJ)??c9JMN7u-4*VeQbbmA;xoa_VBXJ_EF;quvGMDVP6#Aw`h$YR zxMkEiRWIk>PUMJi(yX0I+}33!FB9*b*&AsBBn!mQ+4Jo8eFruAi*%WyEEBrb)4A}ea+;3KuPrj`YaM!jj zjke6zIA|SGC`@W=B2>DQp{isz<@#y{wDSiG_@y;x3wnI|W2Xn)$`b-Ix6Zq%Sm#&i zzS|*`bzr^`F2SYq+BU8EsyGq()g@JpB#ZL~OudDv3jO5~xt?tIe%`fJ zo0gCKlHvPRd|aB?XlOh!Ztio}=jT)>?xzj;SbC-YlDXI5kVjbcC3lBJeRopI1?BGh zbd~ye>RidXi6Y@oON`ALrP>c9?msjxuRPZ3eJ$lR{gjd6aYo9m<(}VEX*baN+sGs2 zF(0Hns{O6f%B~v1y%|B=na5A+vm2+@RbRfAdWHSP;i!zW)Rr$!u`GFaGc2!>3oxiN z;s^SsU{Dg17^mwku`iVhOFN4=j1F_Bu~olI@>3b={hY+dj48scEajUuty7?(0PhPv zd^M>pzGA}x37tFaR8LJUucg#zf7vJIm~ZA7Jd9$Oc84wttjJVfam;M-Nv3{tcK=gh z@wZ8XmIKu|u2i88odBK5fyVKpG~P0Co{5CfH9dZIeOi%sZ(WF}m7=`#xa0gSNe}4B zJwBd$Ysq^nRzO@%8_tRZba2L5>73S?aKS*lho1#XD`0DmVN> zDdt@S6!Y0O)z51G^8w{e{JRY|;bzdgt>g2zXE&Ipne-?rD{1dw|R=WTI diff --git a/micropython/examples/badger2040w/examples/icon-news.jpg b/micropython/examples/badger2040w/examples/icon-news.jpg index 936ec8b530c908676765138a16138c62bf29187c..0c281d340fc15f98c925509d5d68c0382d4d3841 100644 GIT binary patch delta 1844 zcmV-42g~@T8N&~dq<=I3Gy?$<00I#K0}%oL!~h!r0RaF50RaI300000000002?ziN z2MPoQ|HJ?_5C8!K0|NsB1p@#J0000000IF61O)~X2N4qh2ownw78fBRBQY{F7#Soq zHbO&EXQt%;!~him0RaF200000000000000000RHS02C1c0Dk}g000000000000000 z0RP$m3wI&lR;pDBlQ4XGYYEFN+BZ>9okoPz zQ3STxOn=cE2Mj}`>x9iW(?090cDrkVBIOH7>SIkj@jX0i^|>GPjtlG7yb<$(kE$XW(#JDn1aer`kMMXtLMG_K3Au&`TArciuL{tG6 zxZc_?-%bs9w(r|kOp2wb#Y|;TE6!#pq&tyQ=W!@15jKVdf}$_9rlYsy2Em)qEn=o? z{*BstgGg_JC2|rzak3)upA}Z$V=jMi~-dC4}?Vk}= zW`9-uE?!?B$b8-7&k@TU_RAFCZT3&opw)T>AJMZwtSgzirmRexB3_`|RXG&sw9%Rf z%t-G=Z30m;D2AkHa@rCyR@DUd9D^YX_e(pdu(gX;^$SjI*^&z3vK|&Eq_74?Ngb0Wqzao0MP#cODeW+%g>8^>dUo%H{Sd#Ghv3f@bTQ=ZhsB( z$v<}6eK$~xIt=J4p3MC|uKw^L&aXzUQ|((apERlRYO(=j$T!iRMFwLEj#%c#N@m(@ z?&7ARLV;BO08yv>*Z%-i{{Y+28uv|$Q__7$m26+s8ihW6B51Q!q>IBILV_w03vQ@5 z379V6>I;CVLTH96n}fHlTD@UaeSbS{`^w*PJu1nn*w4bH$Bf8h5Tr*~k>RUsW(|-$ z;4nZdi)18J>NMG`oM}+yv@WvyMk*%Rfg+&^3aTioDk>_X^Z+}d5+HOrhM zVn5l~eWqJsG7}^$+GV%D%73HHf{G|E;kx(5+B6>TbdYFGOOHpo=`R%O9aZ*3gk8Zz ziw>qaVf8|7quBWHAOrO;O78s}x?i_1Yj&Y+R$0k>YJ(~qpoUHIv|qK>l$$gc z0Z0oK#FaV6zgJTALF|*%$|cukv(FaHS#QsnRkuNntwgXNu?dLT*XCI z&Okym1J!#=^*+tIYj^0!(zobOM-+!Hq3#7arvKs zpIJLtEZXfON2zs(?z4E|#JDRknr;g%Zb-7(ZCoR8wnSFJ*1U{k()r%bQ#cS8pWVm zd9U;)=^BG+)9zS|@4)1NP>~yQ0xlQ9Mb@%bo67Cg?{qy3fH9iRNX_%^F> zRQ@9OA1~izFzy~di-#W*E$zQK@4o*4pzXKUaEm$zmq&dov@I7%tFBevq*O1-e@+JP i7n+$KKiXnjFby`-nIZoGswawoC}OF)g?-RxLI2r=CQ?fP literal 3238 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 literal 3443 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 ObA>zJXaHL1=zjsaMHC1C diff --git a/micropython/examples/badger2040w/examples/icon-weather.jpg b/micropython/examples/badger2040w/examples/icon-weather.jpg index b01a93712ab8beee8b2210795a688a880e44f54f..35d3bd0032c2eb93c546df0261b2804873149b99 100644 GIT binary patch delta 1449 zcmV;a1y=g+7q<+M6_dvTkAE}(Gy?$<00I#K0}%oL!~hxq00RI60RR910000000000 z00;>M1_uiN!~iQ000IF61OfpB0s;d7000000RjUA1qKHQ5fT6s2^1C~BNZYfF)}kj z|HJ?l0RaI300000000000000000092!~hf#0RR9100000000000Dk}g0095m01N{G z00I#M5dc2`r+H>mY{Bts&PRKy`YSb_ife^+Ppzc%!4erHey9sK3Z(F$lgHo_w{VTMt&+SSZ5TJ=Xalq_Oq%I>OS82;2U{3^d9x51a+KaMv0AGkGS=(X`mW%UkOV(U#e z>|hhJb?w-ILKpZ4fOrRiTz)@3M>M|_(fk)m^ZVuE&5+w6mXKd>QTMj6YPJ;63B$X_ zsSJ^?X;C7LVSgjCgs1}j*;!98_#E=UR1qx&HtaPFh&1CW>EEp374Q>Znrm^&yB@$`Fggp3DI@@E(n# ze52gbEvAb*4rtB6x1yvw7TwS zh+)?JcAmp+H#CCHk5X5>ja6AtB83f1(lSKsAAh)w{c-x%cLbhG5bl2|dCn1~npvk? zVZ&&>ziRy@-mbM}fO^lL;Z}!VAMoDtDTPka*Y}B2-)$+v? zI#Z`rW7$F%)NuFb3PFMqyoKSb1a-(}4x(u2AEvadAKv6Ykv!z(8U z@~I3T`h{HCKgdmX@w4mgf;}*(#cj5WVXmI?w`Q(|Wip~iPT%835uHq~ytgDk`~$%t z9FG9-4*>8dzssiTA=8a8O(L;YR6&*Hu%!0~i6lW!XzuF3O01)_(nMk@!-Eip$AsW|h8~?ox6qE-1adt3riJw+x~)EAWcUcoMX47z>MqY3?ni z)~Rinjx}e+ZL-X2WTUdsMMn$DRaD4QHBeZpAnnIIC?EJd4THcu1He29U7@>e#5bY6 zP0Qc4T--0;X=K9RNpGj96m<142Oh1Zi6$_r$bC^!)AcCmNlsk9Cy=T>0pK11;D7(w DnGTjK literal 3055 zcmbVO2UJvN7QQoYhTa*PvOo|l2tg4WMi{ChARQElNSOhoN)d=O4N9>@iXa+fuu+C0 zA|h%WG!&H(3(`A8i6}6Pk&H6K+kY@ebM~xzcK5#ao!j31?tkBZ9^QkGfXognYbziS z2;hMZz{iMJt8`iT7nI6;6zLt;>Eiy~ksK?`$rMo%qtslqm}20L&74e*5+2!arZ20io)Lz*aX zLUyw+#4lNlcR*3TC@Kj2P=p19Ln!zx#)DuDkPnj2y^W%;Ggwp+B+LNFLpc6c8$dV* zfPV_d=ZkTie*pj+0B8*R93RdA*z^wRPkq*D6#+=60^Df&tn?v3z?^jUll zhVDc<9e`5;Ah{br{t1AX=f}Pwo4^hiy8&EKuWZ`^3eEy74?wxSzQ9`q1$^q;fAsmQ ze|SHb14bkYP9!9Bl10d55{WD(EG#4Rh^R&(VG&U=apX`Z14IIb5lNV!YUG`W>_Czw%YC)hR7l>@M_6+|#o$m@vB)yB zntKXPPuW`Qd?OEwiYY27t1Qu8zGCGn9mDk-Hg4K%WNu+;wQalg4rdovH+Qsfe*QFi zKw!|msOXpjv2pR=eV=;dXj*zkW_C{Q>Ad_i1!pf@yma|WNoiU6wc6`-H|lRT+`9jB zQ*%q}gNKivbv*Cv>h9_78yy?}?ZwN9-(OA6a^C*&ZthR+`ws$M1i(Jh`o!#Cc%dc` zh$Iq55*F|x5M$AW$&$!ltre0pbrkm5FRy8ENQ7dRRa|pVblEy5wt{cuQ!zy?!%^*7 z0kuVD{~fWz{};1Q#6I)t0||_P77vpJ6W}{Dq<^jEuEc>yNp|5XRkg8ik4CfnXFFLr z#x>Pm9u;L*E|#~c%Czd_=DAy01dpWoaaR>zVHHcCrh&#Ytx zK98{}X}EcAU+TA<&AL6Vt}5SRmWGitbhlgVlb1Kl zTWbz3Got>Y+*cFy?Vpw@-a%RZSP<~7xkqpy2XmK>>ZdL7PB-*yH*fxKj!Bz47cS9f z`oha|vs_Ak_QvUveqGO{L0Rlqnp#=cYJgLHG@0#bFB12Cv%{{q{?Vc05x!z*8Na$@ z($9sXdh6>~J{(^kxv~RvyBSVOO-&e>nB5_a;~>RzW{2gBJrVG9>Gr*PY#2HeRFEaeYd|dSgCfOQn#^3>xBL4 z0*av#HJ+|Ezy(*Ll<^(|A~f6*fEiPueb&is z=n+s4W(;80v`CUfGI+xXHLNb7HV(Ks(oQkEOD; z-*HB4@>S0bwsxAe4_AMas(VcBL5cw@+=Rq6pUdMPHDvW!_1{ZoABt;FYAzi($JD5= ze`2S5z)FSYbUu398XJk}3R}l3oyTn(A<4!;s5%vgdXrI|r>s%sg(oU{le@Q_OF ziRo&MTLqjy-5wZlnx>oX_~|WOOZ&wlooZt6E_C@kwKF`rednX`ozE+-91Lb|xp{UK ztM`Ay zNp5TByrDV=9m|!1jLgn$2wXzEL!#UmUpPWpzbx{gNLaMpeJ=&NmqFYA$Ik z*Ul=5$z{gxyV~-Mc-QZK8f3x;=7PBRY*$OTe4OWq$&r!z4&K%guFu`)x>FjviZfp^ z`h&tUUPvC3tocTP-&uef!DlkdJVV%Fj$ z<5Ga+vX%5Es%VOd2O2c#HgB#@$yDq3FvPVjP*4`7U2G#u$-BkLV{yBu!eSI6)C{kk z-oBc6Rfn@mf@3wyD?h0XykdrQIm=hQ-`$*lB6(Dsg~Jh4hG>4q`s%Nxr>xhf*3Rpd zCk)w|zqz()Xdm`Z#y`#)`Ef{}&y4AxQB80uYEn~W)4E>& zT;@fKu}g~YZr@!T-&rgBR?+GvZSVWOa~ZMe*j#d>8n9>XKNfmrEYCil6JE?cxFglG hx2GSwvHqb}wzcjr%>{)SbUNMFS}P^` Date: Fri, 27 Jan 2023 13:02:53 +0000 Subject: [PATCH 33/46] Badger2040W: Move weather icons from examples dir to icons/. --- .../examples/badger2040w/examples/weather.py | 10 +++++----- .../badger2040w/{examples => icons}/icon-cloud.jpg | Bin .../badger2040w/{examples => icons}/icon-rain.jpg | Bin .../badger2040w/{examples => icons}/icon-snow.jpg | Bin .../badger2040w/{examples => icons}/icon-storm.jpg | Bin .../badger2040w/{examples => icons}/icon-sun.jpg | Bin micropython/examples/badger2040w/uf2-manifest.txt | 3 ++- 7 files changed, 7 insertions(+), 6 deletions(-) rename micropython/examples/badger2040w/{examples => icons}/icon-cloud.jpg (100%) rename micropython/examples/badger2040w/{examples => icons}/icon-rain.jpg (100%) rename micropython/examples/badger2040w/{examples => icons}/icon-snow.jpg (100%) rename micropython/examples/badger2040w/{examples => icons}/icon-storm.jpg (100%) rename micropython/examples/badger2040w/{examples => icons}/icon-sun.jpg (100%) diff --git a/micropython/examples/badger2040w/examples/weather.py b/micropython/examples/badger2040w/examples/weather.py index 78290264..aa35bede 100644 --- a/micropython/examples/badger2040w/examples/weather.py +++ b/micropython/examples/badger2040w/examples/weather.py @@ -72,15 +72,15 @@ def draw_page(): # Weather codes from https://open-meteo.com/en/docs # Weather icons from https://fontawesome.com/ if weathercode in [71, 73, 75, 77, 85, 86]: # codes for snow - jpeg.open_file("examples/icon-snow.jpg") + jpeg.open_file("/icons/icon-snow.jpg") elif weathercode in [51, 53, 55, 56, 57, 61, 63, 65, 66, 67, 80, 81, 82]: # codes for rain - jpeg.open_file("examples/icon-rain.jpg") + jpeg.open_file("/icons/icon-rain.jpg") elif weathercode in [1, 2, 3, 45, 48]: # codes for cloud - jpeg.open_file("examples/icon-cloud.jpg") + jpeg.open_file("/icons/icon-cloud.jpg") elif weathercode in [0]: # codes for sun - jpeg.open_file("examples/icon-sun.jpg") + jpeg.open_file("/icons/icon-sun.jpg") elif weathercode in [95, 96, 99]: # codes for storm - jpeg.open_file("examples/icon-storm.jpg") + jpeg.open_file("/icons/icon-storm.jpg") jpeg.decode(13, 40, jpegdec.JPEG_SCALE_FULL) display.set_pen(0) display.text(f"Temperature: {temperature}°C", int(WIDTH / 3), 28, WIDTH - 105, 2) diff --git a/micropython/examples/badger2040w/examples/icon-cloud.jpg b/micropython/examples/badger2040w/icons/icon-cloud.jpg similarity index 100% rename from micropython/examples/badger2040w/examples/icon-cloud.jpg rename to micropython/examples/badger2040w/icons/icon-cloud.jpg diff --git a/micropython/examples/badger2040w/examples/icon-rain.jpg b/micropython/examples/badger2040w/icons/icon-rain.jpg similarity index 100% rename from micropython/examples/badger2040w/examples/icon-rain.jpg rename to micropython/examples/badger2040w/icons/icon-rain.jpg diff --git a/micropython/examples/badger2040w/examples/icon-snow.jpg b/micropython/examples/badger2040w/icons/icon-snow.jpg similarity index 100% rename from micropython/examples/badger2040w/examples/icon-snow.jpg rename to micropython/examples/badger2040w/icons/icon-snow.jpg diff --git a/micropython/examples/badger2040w/examples/icon-storm.jpg b/micropython/examples/badger2040w/icons/icon-storm.jpg similarity index 100% rename from micropython/examples/badger2040w/examples/icon-storm.jpg rename to micropython/examples/badger2040w/icons/icon-storm.jpg diff --git a/micropython/examples/badger2040w/examples/icon-sun.jpg b/micropython/examples/badger2040w/icons/icon-sun.jpg similarity index 100% rename from micropython/examples/badger2040w/examples/icon-sun.jpg rename to micropython/examples/badger2040w/icons/icon-sun.jpg diff --git a/micropython/examples/badger2040w/uf2-manifest.txt b/micropython/examples/badger2040w/uf2-manifest.txt index d5388068..715515cd 100644 --- a/micropython/examples/badger2040w/uf2-manifest.txt +++ b/micropython/examples/badger2040w/uf2-manifest.txt @@ -6,4 +6,5 @@ images/*.jpg images/*.txt badges/*.txt badges/*.jpg -books/*.txt \ No newline at end of file +books/*.txt +icons/*.jpg \ No newline at end of file From 26eeb2b042d39bef99e7fe9ed327b7e97a53e140 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Fri, 27 Jan 2023 21:53:34 +0000 Subject: [PATCH 34/46] Badger2040W: Use partial update for seconds on clock --- .../examples/badger2040w/examples/clock.py | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/micropython/examples/badger2040w/examples/clock.py b/micropython/examples/badger2040w/examples/clock.py index 6b1d15dc..12175438 100644 --- a/micropython/examples/badger2040w/examples/clock.py +++ b/micropython/examples/badger2040w/examples/clock.py @@ -5,7 +5,7 @@ import badger2040w display = badger2040w.Badger2040W() -display.set_update_speed(3) +display.set_update_speed(2) display.set_thickness(4) WIDTH, HEIGHT = display.get_bounds() @@ -14,7 +14,7 @@ try: display.connect() if display.isconnected(): ntptime.settime() -except RuntimeError: +except (RuntimeError, OSError): pass # no WiFI rtc = machine.RTC() @@ -23,6 +23,8 @@ display.set_font("gothic") def draw_clock(): + global second_offset, second_unit_offset + hms = "{:02}:{:02}:{:02}".format(hour, minute, second) ymd = "{:04}/{:02}/{:02}".format(year, month, day) @@ -39,7 +41,35 @@ def draw_clock(): display.text(hms, hms_offset, 40, 0, 1.8) display.text(ymd, ymd_offset, 100, 0, 1.0) + display.set_update_speed(2) display.update() + display.set_update_speed(3) + + hms = "{:02}:{:02}:".format(hour, minute) + second_offset = hms_offset + display.measure_text(hms, 1.8) + hms = "{:02}:{:02}:{}".format(hour, minute, second // 10) + second_unit_offset = hms_offset + display.measure_text(hms, 1.8) + + +def draw_second(): + global second_offset, second_unit_offset + + display.set_pen(15) + display.rectangle(second_offset, 8, 75, 56) + display.set_pen(0) + + if second // 10 != last_second // 10: + s = "{:02}".format(second) + display.text(s, second_offset, 40, 0, 1.8) + display.partial_update(second_offset, 8, 75, 56) + + s = "{}".format(second // 10) + second_unit_offset = second_offset + display.measure_text(s, 1.8) + + else: + s = "{}".format(second % 10) + display.text(s, second_unit_offset, 40, 0, 1.8) + display.partial_update(second_unit_offset, 8, 75 - (second_unit_offset - second_offset), 56) year, month, day, wd, hour, minute, second, _ = rtc.datetime() @@ -48,11 +78,17 @@ if (year, month, day) == (2021, 1, 1): rtc.datetime((2022, 2, 28, 0, 12, 0, 0, 0)) last_second = second +last_minute = minute +draw_clock() while True: year, month, day, wd, hour, minute, second, _ = rtc.datetime() if second != last_second: - draw_clock() + if minute != last_minute: + draw_clock() + last_minute = minute + else: + draw_second() last_second = second time.sleep(0.01) From cbcd9edd9a04b806658b980b3bef18aae2991fc0 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 31 Jan 2023 15:20:41 +0000 Subject: [PATCH 35/46] Badger2040W: Fix wakeup and quit to launcher button handling. --- micropython/examples/badger2040w/launcher.py | 4 ++-- .../examples/badger2040w/lib/badger2040w.py | 21 ++++++++++++++----- micropython/modules/wakeup/wakeup.c | 2 ++ micropython/modules/wakeup/wakeup.cpp | 5 +++++ micropython/modules/wakeup/wakeup.h | 1 + 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/micropython/examples/badger2040w/launcher.py b/micropython/examples/badger2040w/launcher.py index cbbf7796..941e21a8 100644 --- a/micropython/examples/badger2040w/launcher.py +++ b/micropython/examples/badger2040w/launcher.py @@ -16,6 +16,7 @@ woken_by_button = badger2040.woken_by_button() # Must be done before we clear_p if badger2040.pressed_to_wake(badger2040.BUTTON_A) and badger2040.pressed_to_wake(badger2040.BUTTON_C): # Pressing A and C together at start quits app exited_to_launcher = badger_os.state_clear_running() + badger2040.reset_pressed_to_wake() else: # Otherwise restore previously running app badger_os.state_launch() @@ -116,8 +117,7 @@ def render(): def wait_for_user_to_release_buttons(): - pr = display.pressed - while pr(badger2040.BUTTON_A) or pr(badger2040.BUTTON_B) or pr(badger2040.BUTTON_C) or pr(badger2040.BUTTON_UP) or pr(badger2040.BUTTON_DOWN): + while display.pressed_any(): time.sleep(0.01) diff --git a/micropython/examples/badger2040w/lib/badger2040w.py b/micropython/examples/badger2040w/lib/badger2040w.py index f5a6f7f5..3b763092 100644 --- a/micropython/examples/badger2040w/lib/badger2040w.py +++ b/micropython/examples/badger2040w/lib/badger2040w.py @@ -45,8 +45,6 @@ SYSTEM_FREQS = [ 250000000 ] -WAKEUP_GPIO_STATE = wakeup.get_gpio_state() - BUTTONS = { BUTTON_DOWN: machine.Pin(BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN), BUTTON_A: machine.Pin(BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN), @@ -55,13 +53,26 @@ BUTTONS = { BUTTON_UP: machine.Pin(BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN), } +WAKEUP_MASK = 0 + def woken_by_button(): - return WAKEUP_GPIO_STATE & BUTTON_MASK > 0 + return wakeup.get_gpio_state() & BUTTON_MASK > 0 def pressed_to_wake(button): - return WAKEUP_GPIO_STATE & (1 << button) > 0 + return wakeup.get_gpio_state() & (1 << button) > 0 + + +def reset_pressed_to_wake(): + wakeup.reset_gpio_state() + + +def pressed_to_wake_get_once(button): + global WAKEUP_MASK + result = (wakeup.get_gpio_state() & ~WAKEUP_MASK & (1 << button)) > 0 + WAKEUP_MASK |= (1 << button) + return result def system_speed(speed): @@ -114,7 +125,7 @@ class Badger2040W(): pass def pressed(self, button): - return BUTTONS[button].value() == 1 + return BUTTONS[button].value() == 1 or pressed_to_wake_get_once(button) def pressed_any(self): for button in BUTTONS.values(): diff --git a/micropython/modules/wakeup/wakeup.c b/micropython/modules/wakeup/wakeup.c index f6284f71..e5204112 100644 --- a/micropython/modules/wakeup/wakeup.c +++ b/micropython/modules/wakeup/wakeup.c @@ -1,12 +1,14 @@ #include "wakeup.h" STATIC MP_DEFINE_CONST_FUN_OBJ_0(Wakeup_get_gpio_state_obj, Wakeup_get_gpio_state); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(Wakeup_reset_gpio_state_obj, Wakeup_reset_gpio_state); STATIC MP_DEFINE_CONST_FUN_OBJ_0(Wakeup_get_shift_state_obj, Wakeup_get_shift_state); STATIC MP_DEFINE_CONST_FUN_OBJ_0(Wakeup_reset_shift_state_obj, Wakeup_reset_shift_state); STATIC const mp_map_elem_t wakeup_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_wakeup) }, { MP_ROM_QSTR(MP_QSTR_get_gpio_state), MP_ROM_PTR(&Wakeup_get_gpio_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_gpio_state), MP_ROM_PTR(&Wakeup_reset_gpio_state_obj) }, { MP_ROM_QSTR(MP_QSTR_get_shift_state), MP_ROM_PTR(&Wakeup_get_shift_state_obj) }, { MP_ROM_QSTR(MP_QSTR_reset_shift_state), MP_ROM_PTR(&Wakeup_reset_shift_state_obj) } }; diff --git a/micropython/modules/wakeup/wakeup.cpp b/micropython/modules/wakeup/wakeup.cpp index afe5c8da..e5127526 100644 --- a/micropython/modules/wakeup/wakeup.cpp +++ b/micropython/modules/wakeup/wakeup.cpp @@ -62,6 +62,11 @@ mp_obj_t Wakeup_get_gpio_state() { return mp_obj_new_int(runtime_wakeup_gpio_state); } +mp_obj_t Wakeup_reset_gpio_state() { + runtime_wakeup_gpio_state = 0; + return mp_const_none; +} + void err_no_sr() { mp_raise_msg(&mp_type_RuntimeError, "Wakeup_get_shift_state: board does not have a shift register."); } diff --git a/micropython/modules/wakeup/wakeup.h b/micropython/modules/wakeup/wakeup.h index 7330b739..d14cff23 100644 --- a/micropython/modules/wakeup/wakeup.h +++ b/micropython/modules/wakeup/wakeup.h @@ -2,5 +2,6 @@ #include "py/objstr.h" extern mp_obj_t Wakeup_get_gpio_state(); +extern mp_obj_t Wakeup_reset_gpio_state(); extern mp_obj_t Wakeup_get_shift_state(); extern mp_obj_t Wakeup_reset_shift_state(); \ No newline at end of file From 3a2a43f4b36ddedf9e0553014fa48a700c04eb0c Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 31 Jan 2023 15:53:41 +0000 Subject: [PATCH 36/46] Badger2040W: Correct wakeup LED. --- micropython/_board/badger2040w/wakeup_gpio.patch | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/micropython/_board/badger2040w/wakeup_gpio.patch b/micropython/_board/badger2040w/wakeup_gpio.patch index abaef7f0..ec1c9931 100644 --- a/micropython/_board/badger2040w/wakeup_gpio.patch +++ b/micropython/_board/badger2040w/wakeup_gpio.patch @@ -16,17 +16,17 @@ index 70dd3bb..b8c1ed0 100644 +// Pins to toggle on wakeup +#ifndef PICO_WAKEUP_PIN_MASK -+#define PICO_WAKEUP_PIN_MASK ((0b1 << 10) | (0b1 << 25)) ++#define PICO_WAKEUP_PIN_MASK ((0b1 << 10) | (0b1 << 22)) +#endif + +// Direction +#ifndef PICO_WAKEUP_PIN_DIR -+#define PICO_WAKEUP_PIN_DIR ((0b1 << 10) | (0b1 << 25)) ++#define PICO_WAKEUP_PIN_DIR ((0b1 << 10) | (0b1 << 22)) +#endif + +// Value +#ifndef PICO_WAKEUP_PIN_VALUE -+#define PICO_WAKEUP_PIN_VALUE ((0b1 << 10) | (0b1 << 25)) ++#define PICO_WAKEUP_PIN_VALUE ((0b1 << 10) | (0b1 << 22)) +#endif + extern char __StackLimit; /* Set by linker. */ From a275f31c7a01420f7cc92ca6aac73dbaecf5610c Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 31 Jan 2023 15:54:04 +0000 Subject: [PATCH 37/46] Badger2040W: (Try to) fix abrupt poweroff screen corruption. --- micropython/examples/badger2040w/lib/badger2040w.py | 1 + 1 file changed, 1 insertion(+) diff --git a/micropython/examples/badger2040w/lib/badger2040w.py b/micropython/examples/badger2040w/lib/badger2040w.py index 3b763092..7c2057e1 100644 --- a/micropython/examples/badger2040w/lib/badger2040w.py +++ b/micropython/examples/badger2040w/lib/badger2040w.py @@ -119,6 +119,7 @@ class Badger2040W(): raise RuntimeError("Thickness not supported in PicoGraphics.") def halt(self): + time.sleep(0.05) enable = machine.Pin(ENABLE_3V3, machine.Pin.OUT) enable.off() while not self.pressed_any(): From d7b9881c0f6a3965517eb2c1a1e4ab6c1f07d249 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 7 Feb 2023 14:00:17 +0000 Subject: [PATCH 38/46] Badger2040W: Add pins.csv to board fixup. --- .../PIMORONI_BADGER2040W/mpconfigboard.h | 5 +--- .../badger2040w/PIMORONI_BADGER2040W/pins.csv | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 micropython/_board/badger2040w/PIMORONI_BADGER2040W/pins.csv diff --git a/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.h b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.h index 888d1cad..89594311 100644 --- a/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.h +++ b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.h @@ -15,9 +15,6 @@ // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose // #define MODUSSL_MBEDTLS_DEBUG_LEVEL 1 -#define MICROPY_HW_PIN_CYW43_COUNT CYW43_WL_GPIO_COUNT -#ifdef CYW43_WL_GPIO_LED_PIN -#define MICROPY_HW_PIN_CYW43_LED_PIN_NUM CYW43_WL_GPIO_LED_PIN -#endif +#define MICROPY_HW_PIN_EXT_COUNT CYW43_WL_GPIO_COUNT #define MICROPY_HW_PIN_RESERVED(i) ((i) == CYW43_PIN_WL_HOST_WAKE || (i) == CYW43_PIN_WL_REG_ON) \ No newline at end of file diff --git a/micropython/_board/badger2040w/PIMORONI_BADGER2040W/pins.csv b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/pins.csv new file mode 100644 index 00000000..012bc7c7 --- /dev/null +++ b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/pins.csv @@ -0,0 +1,30 @@ +GP0,GPIO0 +GP1,GPIO1 +GP2,GPIO2 +GP3,GPIO3 +GP4,GPIO4 +GP5,GPIO5 +GP6,GPIO6 +GP7,GPIO7 +GP8,GPIO8 +GP9,GPIO9 +GP10,GPIO10 +GP11,GPIO11 +GP12,GPIO12 +GP13,GPIO13 +GP14,GPIO14 +GP15,GPIO15 +GP16,GPIO16 +GP17,GPIO17 +GP18,GPIO18 +GP19,GPIO19 +GP20,GPIO20 +GP21,GPIO21 +GP22,GPIO22 +GP26,GPIO26 +GP27,GPIO27 +GP28,GPIO28 +WL_GPIO0,EXT_GPIO0 +WL_GPIO1,EXT_GPIO1 +WL_GPIO2,EXT_GPIO2 +LED,EXT_GPIO0 \ No newline at end of file From 3f0efa9765e984b73c8b7a7517607a61070ab522 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 7 Feb 2023 14:01:59 +0000 Subject: [PATCH 39/46] Badger2040W/CI: Bump MicroPython to 35524a6. --- .github/workflows/micropython-badger2040.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/micropython-badger2040.yml b/.github/workflows/micropython-badger2040.yml index b71fa1e3..81e71d25 100644 --- a/.github/workflows/micropython-badger2040.yml +++ b/.github/workflows/micropython-badger2040.yml @@ -7,7 +7,7 @@ on: types: [created] env: - MICROPYTHON_VERSION: 67fac4ebc53db6337008ba06df7932faec80f57c + MICROPYTHON_VERSION: 35524a6fda1e44692ad599a39c802c168c897de9 BOARD_TYPE: PIMORONI_BADGER2040 # MicroPython version will be contained in github.event.release.tag_name for releases RELEASE_FILE: pimoroni-badger2040-${{github.event.release.tag_name || github.sha}}-micropython From 0410b7c775cfc413cbf507755e5e95bae97e05ab Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 7 Feb 2023 15:03:54 +0000 Subject: [PATCH 40/46] Badger2040W: Add thickness back. Better error backdrop. --- micropython/examples/badger2040w/examples/badge.py | 1 + micropython/examples/badger2040w/examples/ebook.py | 2 ++ micropython/examples/badger2040w/examples/help.py | 1 + micropython/examples/badger2040w/examples/list.py | 1 + micropython/examples/badger2040w/lib/badger_os.py | 8 +++++++- 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/micropython/examples/badger2040w/examples/badge.py b/micropython/examples/badger2040w/examples/badge.py index 86ccc3ac..3377d79c 100644 --- a/micropython/examples/badger2040w/examples/badge.py +++ b/micropython/examples/badger2040w/examples/badge.py @@ -119,6 +119,7 @@ def draw_badge(): display = badger2040w.Badger2040W() display.led(128) display.set_update_speed(badger2040w.UPDATE_NORMAL) +display.set_thickness(2) jpeg = jpegdec.JPEG(display.display) diff --git a/micropython/examples/badger2040w/examples/ebook.py b/micropython/examples/badger2040w/examples/ebook.py index 0091af84..31fa27b0 100644 --- a/micropython/examples/badger2040w/examples/ebook.py +++ b/micropython/examples/badger2040w/examples/ebook.py @@ -20,6 +20,7 @@ TEXT_PADDING = 4 TEXT_WIDTH = WIDTH - TEXT_PADDING - TEXT_PADDING - ARROW_WIDTH FONTS = ["sans", "gothic", "cursive", "serif"] +THICKNESSES = [2, 1, 1, 2] # ------------------------------ # Drawing functions # ------------------------------ @@ -91,6 +92,7 @@ def render_page(): next_pos = pos add_newline = False display.set_font(FONTS[state["font_idx"]]) + display.set_thickness(THICKNESSES[state["font_idx"]]) while True: # Read a full line and split it into words diff --git a/micropython/examples/badger2040w/examples/help.py b/micropython/examples/badger2040w/examples/help.py index 8e08a8c8..f51b0403 100644 --- a/micropython/examples/badger2040w/examples/help.py +++ b/micropython/examples/badger2040w/examples/help.py @@ -6,6 +6,7 @@ LINE_HEIGHT = 20 display = badger2040w.Badger2040W() display.led(128) +display.set_thickness(2) # Clear to white display.set_pen(15) diff --git a/micropython/examples/badger2040w/examples/list.py b/micropython/examples/badger2040w/examples/list.py index f74298ad..01137a7c 100644 --- a/micropython/examples/badger2040w/examples/list.py +++ b/micropython/examples/badger2040w/examples/list.py @@ -181,6 +181,7 @@ items_per_page = 0 display = badger2040w.Badger2040W() display.led(128) display.set_font("sans") +display.set_thickness(2) if changed: display.set_update_speed(badger2040w.UPDATE_FAST) else: diff --git a/micropython/examples/badger2040w/lib/badger_os.py b/micropython/examples/badger2040w/lib/badger_os.py index 98a14fa3..3eaaec63 100644 --- a/micropython/examples/badger2040w/lib/badger_os.py +++ b/micropython/examples/badger2040w/lib/badger_os.py @@ -145,7 +145,7 @@ def launch(file): # Draw an overlay box with a given message within it -def warning(display, message, width=badger2040.WIDTH - 40, height=badger2040.HEIGHT - 40, line_spacing=20, text_size=0.6): +def warning(display, message, width=badger2040.WIDTH - 20, height=badger2040.HEIGHT - 20, line_spacing=20, text_size=0.6): print(message) if display is None: @@ -156,6 +156,12 @@ def warning(display, message, width=badger2040.WIDTH - 40, height=badger2040.HEI display.set_pen(12) display.rectangle((badger2040.WIDTH - width) // 2, (badger2040.HEIGHT - height) // 2, width, height) + width -= 20 + height -= 20 + + display.set_pen(15) + display.rectangle((badger2040.WIDTH - width) // 2, (badger2040.HEIGHT - height) // 2, width, height) + # Take the provided message and split it up into # lines that fit within the specified width words = message.split(" ") From 2952fd760e7ed4febb23c23064401c02846d2f69 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 7 Feb 2023 15:41:40 +0000 Subject: [PATCH 41/46] Badger2040W: Fix news text wrapping and URLs. --- micropython/examples/badger2040w/examples/news.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/micropython/examples/badger2040w/examples/news.py b/micropython/examples/badger2040w/examples/news.py index e4ba7045..4f280c08 100644 --- a/micropython/examples/badger2040w/examples/news.py +++ b/micropython/examples/badger2040w/examples/news.py @@ -7,8 +7,8 @@ import qrcode import badger_os # URLS to use (Entertainment, Science and Technology) -URL = ["http://feeds.bbci.co.uk/news/video_and_audio/entertainment_and_arts/rss.xml", - "http://feeds.bbci.co.uk/news/video_and_audio/science_and_environment/rss.xml", +URL = ["http://feeds.bbci.co.uk/news/entertainment_and_arts/rss.xml", + "http://feeds.bbci.co.uk/news/science_and_environment/rss.xml", "http://feeds.bbci.co.uk/news/technology/rss.xml"] code = qrcode.QRCode() @@ -161,7 +161,7 @@ def draw_page(): if feed: page = state["current_page"] display.set_pen(0) - display.text(feed[page]["title"], 2, 40, WIDTH - 105, 2) + display.text(feed[page]["title"], 2, 30, WIDTH - 130, 2) code.set_text(feed[page]["guid"]) draw_qr_code(WIDTH - 100, 25, 100, code) From cb82878cd27e96bfbf48e1df49392e0d7d4f6b6a Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Feb 2023 13:41:56 +0000 Subject: [PATCH 42/46] Badger2040W: Add README.md for MicroPython. --- micropython/modules/badger2040w/README.md | 258 ++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 micropython/modules/badger2040w/README.md diff --git a/micropython/modules/badger2040w/README.md b/micropython/modules/badger2040w/README.md new file mode 100644 index 00000000..8a2588a6 --- /dev/null +++ b/micropython/modules/badger2040w/README.md @@ -0,0 +1,258 @@ +# Badger 2040 WW + +Badger 2040 WW is a Raspberry Pi Pico W powered E Ink badge. + +- [Summary](#summary) + - [Differences between Badger 2040 W and Badger 2040](#differences-between-badger-2040-w-and-badger-2040) + - [Getting Started](#getting-started) + - [Constants](#constants) + - [Screen Size](#screen-size) + - [E Ink Pins](#e-ink-pins) + - [Power Pins](#power-pins) + - [Activity LED Pin](#activity-led-pin) +- [Function Reference](#function-reference) + - [Basic Drawing Settings](#basic-drawing-settings) + - [Pen Colour](#pen-colour) + - [Pen Thickness](#pen-thickness) + - [Displaying Images](#displaying-images) + - [Updating The Display](#updating-the-display) + - [Update](#update) + - [Clear](#clear) + - [Partial Update](#partial-update) + - [Update Speed](#update-speed) + - [LED](#led) + - [Buttons](#buttons) + - [Waking From Sleep](#waking-from-sleep) + - [Button Presses](#button-presses) + - [Real-time Clock](#real-time-clock) + - [Update Speed](#update-speed-1) + - [System speed](#system-speed) + +# Summary + +## Differences between Badger 2040 W and Badger 2040 + +Badger 2040 W switches from the Badger-specific drawing library of Badger 2040, to our generic PicoGraphics library. + +PicoGraphics brings some great improvements, such as JPEG support with ditering and cross-compatibility between all of our other display products. + +We've tried to make the transition as simple as possible, but there are a few breaking changes you'll need to be aware of: + +* `pen()` is now `set_pen()` +* `update_speed()` is now `set_update_speed()` +* `thickness()` is now `set_thickness()` and *only* applies to Hershey fonts +* `image()` and `icon()` are deprecated, use JPEGs instead. +* `invert()` is not supported. + +See the [PicoGraphics function reference](../picographics/README.md) for more information on how to draw to the display. + +Additionally Badger 2040 W does not have a "user" button since the bootsel (which originally doubled as "user") is aboard the attached Pico W. + +## Getting Started + +:warning: If you're using the examples-included firmware you're good to go, otherwise you'll need to copy `examples/badger2040w/lib/badger2040w.py` and `examples/badger2040w/lib/network_manager.py` over to your Badger 2040 W. + +To start coding your Badger 2040 W, you will need to add the following lines of code to the start of your code file. + +```python +import badger2040w +badger = badger2040w.Badger2040W() +``` + +This will create a `Badger2040W` class called `badger` that will be used in the rest of the examples going forward. + +## Constants + +Below is a list of other constants that have been made available, to help with the creation of more advanced programs. + +### Screen Size +* `WIDTH` = `296` +* `HEIGHT` = `128` + +### E Ink Pins +* `BUSY` = `26` + +### Power Pins +* `ENABLE_3V3` = `10` + +### Activity LED Pin +* `LED` = `22` + +# Function Reference + +## Basic Drawing Settings + +Since Badger 2040 W is based upon PicoGraphics you should read the [PicoGraphics function reference](../picographics/README.md) for more information about how to draw to the display. + +### Pen Colour + +There are 16 pen colours - or "shades of grey" - to choose, from 0 (black) to 15 (white). + +Since Badger2040W cannot display colours other than black and white, any value from 1 to 14 will apply dithering when drawn, to simulate a shade of grey. + +```python +pen( + colour # int: colour from 0 to 15 +) +``` + +### Pen Thickness + +:warning: Applies to Hershey fonts only. + +Thickness affects Hershey text and governs how thick the component lines should be, making it appear bolder: + +```python +set_thickness( + value # int: thickness in pixels +) +``` + +## Displaying Images + +Badger 2040 W can display basic JPEG images. They must not be progressive. It will attempt to dither them to the black/white display. + +To display a JPEG, import and set up the `jpegdec` module like so: + +```python +import badger2040w +import jpegdec + +badger = badger2040w.Badger2040W() +jpeg = jpegdec.JPEG(badger.display) +``` + +`badger.display` points to the PicoGraphics instance that the Badger2040W class manages for you. + +You can open and display a JPEG file like so: + +```python +jpeg.open_file("/image.jpg") +jpeg.decode(x, y) +``` + +Where `x, y` is the position at which you want to display the JPEG. + +## Updating The Display + +### Update + +Starts a full update of the screen. Will block until the update has finished. + +Update takes no parameters, but the update time will vary depending on which update speed you've selected. + +```python +badger.update() +``` + +### Clear + +Before drawing again it can be useful to `clear` your display. + +`clear` fills the drawing buffer with the pen colour, giving you a clean slate: + +```python +badger.clear() +``` + +### Partial Update + +Starts a partial update of the screen. Will block until the update has finished. + +A partial update allows you to update a portion of the screen rather than the whole thing. + +That portion *must* be a multiple of 8 pixels tall, but can be any number of pixels wide. + +```python +partial_update( + x, # int: x coordinate of the update region + y, # int: y coordinate of the update region (must be a multiple of 8) + w, # int: width of the update region + h # int: height of the update region (must be a multiple of 8) +) +``` + +### Update Speed + +Badger 2040 W is capable of updating the display at multiple different speeds. + +These offer a tradeoff between the quality of the final image and the speed of the update. + +There are currently four constants naming the different update speeds from 0 to 3: + +* `UPDATE_NORMAL` - a normal update, great for display the first screen of your application and ensuring good contrast and no ghosting +* `UPDATE_MEDIUM` - a good balance of speed and clarity, you probably want this most of the time +* `UPDATE_FAST` - a fast update, good for stepping through screens such as the pages of a book or the launcher +* `UPDATE_TURBO` - a super fast update, prone to ghosting, great for making minor changes such as moving a cursor through a menu + +```python +update_speed( + speed # int: one of the update constants +) +``` + +## LED + +The white indicator LED can be controlled, with brightness ranging from 0 (off) to 255: + +```python +led( + brightness # int: 0 (off) to 255 (full) +) +``` + +## Buttons + +Badger 2040 W features five buttons on its front, labelled A, B, C, ↑ (up) and ↓ (down). These can be read using the `pressed(button)` method, which accepts the button's pin number. For convenience, each button can be referred to using these constants: + +* `BUTTON_A` = `12` +* `BUTTON_B` = `13` +* `BUTTON_C` = `14` +* `BUTTON_UP` = `15` +* `BUTTON_DOWN` = `11` + +Additionally you can use `pressed_any()` to see if _any_ button has been pressed. + +## Waking From Sleep + +### Button Presses + +When running on battery, pressing a button on Badger 2040 W will power the unit on. It will automatically be latched on and `main.py` will be executed. + +There are some useful functions to determine if Badger 2040 W has been woken by a button, and figure out which one: + +* `badger2040w.woken_by_button()` - determine if any button was pressed during power-on. +* `badger2040w.pressed_to_wake(button)` - determine if the given button was pressed during power-on. +* `badger2040w.reset_pressed_to_wake()` - clear the wakeup GPIO state. +* `badger2040w.pressed_to_wake_get_once(button)` - returns `True` if the given button was pressed to wake Badger, and then clears the state of that pin. + +### Real-time Clock + +Badger 2040 W includes a PCF85063a RTC which continues to run from battery when the Badger is off. It can be used to wake the Badger on a schedule. + + +## Update Speed + +The E Ink display on Badger 2040 W supports several update speeds. These can be set using `set_update_speed(speed)` where `speed` is a value from `0` to `3`. For convenience these speeds have been given the following constants: + +* `UPDATE_NORMAL` = `0` +* `UPDATE_MEDIUM` = `1` +* `UPDATE_FAST` = `2` +* `UPDATE_TURBO` = `3` + +## System speed + +The system clock speed of the RP2040 can be controlled, allowing power to be saved if on battery, or faster computations to be performed. Use `badger2040w.system_speed(speed)` where `speed` is one of the following constants: + +* `SYSTEM_VERY_SLOW` = `0` _4 MHz if on battery, 48 MHz if connected to USB_ +* `SYSTEM_SLOW` = `1` _12 MHz if on battery, 48 MHz if connected to USB_ +* `SYSTEM_NORMAL` = `2` _48 MHz_ +* `SYSTEM_FAST` = `3` _133 MHz_ +* `SYSTEM_TURBO` = `4` _250 MHz_ + +On USB, the system will not run slower than 48MHz, as that is the minimum clock speed required to keep the USB connection stable. + +It is best to set the clock speed as the first thing in your program, and you must not change it after initializing any drivers for any I2C hardware connected to the qwiic port. To allow you to set the speed at the top of your program, this method is on the `badger2040w` module, rather than the `badger` instance, although we have made sure that it is safe to call it after creating a `badger` instance. + +Note that `SYSTEM_TURBO` overclocks the RP2040 to 250MHz, and applies a small over voltage to ensure this is stable. We've found that every RP2040 we've tested is happy to run at this speed without any issues. + From 9bba17cc47e15bb38300779d411e6d9aaa2417d6 Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Mon, 13 Feb 2023 17:39:13 +0000 Subject: [PATCH 43/46] add missing .py --- micropython/examples/badger2040w/lib/badger2040w.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/examples/badger2040w/lib/badger2040w.py b/micropython/examples/badger2040w/lib/badger2040w.py index 7c2057e1..8b733503 100644 --- a/micropython/examples/badger2040w/lib/badger2040w.py +++ b/micropython/examples/badger2040w/lib/badger2040w.py @@ -174,7 +174,7 @@ class Badger2040W(): def connect(self): if WIFI_CONFIG.COUNTRY == "": - raise RuntimeError("You must populate WIFI_CONFIG for networking.") + raise RuntimeError("You must populate WIFI_CONFIG.py for networking.") self.display.set_update_speed(2) network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=self.status_handler) uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK)) From 8a420ca0e4c5344865346b29e4612c6f5271e4ff Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Tue, 14 Feb 2023 15:21:46 +0000 Subject: [PATCH 44/46] update qrcode.py with badger w details --- micropython/examples/badger2040w/examples/qrgen.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/micropython/examples/badger2040w/examples/qrgen.py b/micropython/examples/badger2040w/examples/qrgen.py index 451e430d..d4617989 100644 --- a/micropython/examples/badger2040w/examples/qrgen.py +++ b/micropython/examples/badger2040w/examples/qrgen.py @@ -15,15 +15,16 @@ try: text = open("/qrcodes/qrcode.txt", "r") except OSError: text = open("/qrcodes/qrcode.txt", "w") - text.write("""https://pimoroni.com/badger2040 -Badger 2040 + text.write("""https://pimoroni.com/badger2040w +Badger 2040 W * 296x128 1-bit e-ink -* six user buttons +* 2.4GHz wireless +* five user buttons * user LED * 2MB QSPI flash Scan this code to learn -more about Badger 2040. +more about Badger 2040 W. """) text.flush() text.seek(0) @@ -125,7 +126,7 @@ while True: if display.pressed(badger2040w.BUTTON_B) or display.pressed(badger2040w.BUTTON_C): display.set_pen(15) display.clear() - badger_os.warning(display, "To add QR codes, connect Badger2040W to a PC, load up Thonny, and see qrgen.py.") + badger_os.warning(display, "To add QR codes, connect Badger 2040 W to a PC, load up Thonny, and add files to /qrcodes directory.") time.sleep(4) changed = True From 2bdb05ce68ecddd3d7886207d235334a02b23f19 Mon Sep 17 00:00:00 2001 From: helgibbons <50950368+helgibbons@users.noreply.github.com> Date: Wed, 15 Feb 2023 11:18:45 +0000 Subject: [PATCH 45/46] fix a couple of typos --- micropython/modules/badger2040w/README.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/micropython/modules/badger2040w/README.md b/micropython/modules/badger2040w/README.md index 8a2588a6..fd399cd1 100644 --- a/micropython/modules/badger2040w/README.md +++ b/micropython/modules/badger2040w/README.md @@ -1,6 +1,6 @@ -# Badger 2040 WW +# Badger 2040 W -Badger 2040 WW is a Raspberry Pi Pico W powered E Ink badge. +Badger 2040 W is a Raspberry Pi Pico W powered E Ink badge. - [Summary](#summary) - [Differences between Badger 2040 W and Badger 2040](#differences-between-badger-2040-w-and-badger-2040) @@ -34,7 +34,7 @@ Badger 2040 WW is a Raspberry Pi Pico W powered E Ink badge. Badger 2040 W switches from the Badger-specific drawing library of Badger 2040, to our generic PicoGraphics library. -PicoGraphics brings some great improvements, such as JPEG support with ditering and cross-compatibility between all of our other display products. +PicoGraphics brings some great improvements, such as JPEG support with dithering and cross-compatibility between all of our other display products. We've tried to make the transition as simple as possible, but there are a few breaking changes you'll need to be aware of: @@ -46,7 +46,7 @@ We've tried to make the transition as simple as possible, but there are a few br See the [PicoGraphics function reference](../picographics/README.md) for more information on how to draw to the display. -Additionally Badger 2040 W does not have a "user" button since the bootsel (which originally doubled as "user") is aboard the attached Pico W. +Additionally Badger 2040 W does not have a "user" button since the BOOTSEL button (which originally doubled as "user") is now aboard the attached Pico W. ## Getting Started @@ -66,16 +66,20 @@ This will create a `Badger2040W` class called `badger` that will be used in the Below is a list of other constants that have been made available, to help with the creation of more advanced programs. ### Screen Size + * `WIDTH` = `296` * `HEIGHT` = `128` ### E Ink Pins + * `BUSY` = `26` ### Power Pins + * `ENABLE_3V3` = `10` ### Activity LED Pin + * `LED` = `22` # Function Reference @@ -88,7 +92,7 @@ Since Badger 2040 W is based upon PicoGraphics you should read the [PicoGraphics There are 16 pen colours - or "shades of grey" - to choose, from 0 (black) to 15 (white). -Since Badger2040W cannot display colours other than black and white, any value from 1 to 14 will apply dithering when drawn, to simulate a shade of grey. +Since Badger 2040 W cannot display colours other than black and white, any value from 1 to 14 will apply dithering when drawn, to simulate a shade of grey. ```python pen( @@ -230,7 +234,6 @@ There are some useful functions to determine if Badger 2040 W has been woken by Badger 2040 W includes a PCF85063a RTC which continues to run from battery when the Badger is off. It can be used to wake the Badger on a schedule. - ## Update Speed The E Ink display on Badger 2040 W supports several update speeds. These can be set using `set_update_speed(speed)` where `speed` is a value from `0` to `3`. For convenience these speeds have been given the following constants: @@ -252,7 +255,6 @@ The system clock speed of the RP2040 can be controlled, allowing power to be sav On USB, the system will not run slower than 48MHz, as that is the minimum clock speed required to keep the USB connection stable. -It is best to set the clock speed as the first thing in your program, and you must not change it after initializing any drivers for any I2C hardware connected to the qwiic port. To allow you to set the speed at the top of your program, this method is on the `badger2040w` module, rather than the `badger` instance, although we have made sure that it is safe to call it after creating a `badger` instance. +It is best to set the clock speed as the first thing in your program, and you must not change it after initializing any drivers for any I2C hardware connected to the Qwiic port. To allow you to set the speed at the top of your program, this method is on the `badger2040w` module, rather than the `badger` instance, although we have made sure that it is safe to call it after creating a `badger` instance. Note that `SYSTEM_TURBO` overclocks the RP2040 to 250MHz, and applies a small over voltage to ensure this is stable. We've found that every RP2040 we've tested is happy to run at this speed without any issues. - From 5a62a79a93bee02ced6f9172bad42db3eb59677a Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Thu, 16 Feb 2023 10:28:07 +0000 Subject: [PATCH 46/46] Renamed thick_line --- libraries/pico_graphics/pico_graphics.cpp | 4 ++-- libraries/pico_graphics/pico_graphics.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index df3a9175..6541ae53 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -170,7 +170,7 @@ namespace pimoroni { }, t, p.x, p.y, s, a); } else { hershey::text(hershey_font, [this](int32_t x1, int32_t y1, int32_t x2, int32_t y2) { - thicc_line(Point(x1, y1), Point(x2, y2), thickness); + thick_line(Point(x1, y1), Point(x2, y2), thickness); }, t, p.x, p.y, s, a); } return; @@ -298,7 +298,7 @@ namespace pimoroni { } } - void PicoGraphics::thicc_line(Point p1, Point p2, uint thickness) { + void PicoGraphics::thick_line(Point p1, Point p2, uint thickness) { // general purpose line // lines are either "shallow" or "steep" based on whether the x delta // is greater than the y delta diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 8e6a0df8..88474e23 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -266,7 +266,7 @@ namespace pimoroni { void triangle(Point p1, Point p2, Point p3); void line(Point p1, Point p2); void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b); - void thicc_line(Point p1, Point p2, uint thickness); + void thick_line(Point p1, Point p2, uint thickness); protected: void frame_convert_rgb565(conversion_callback_func callback, next_pixel_func get_next_pixel);