├── boards └── shields │ └── nice_shield_base │ ├── nice_shield_base.conf │ ├── Kconfig.shield │ ├── assets │ ├── custom_fonts.h │ ├── left_image.c │ ├── right_image.c │ ├── images.c │ └── pixel_operator_mono.c │ ├── widgets │ ├── left_animation.h │ ├── right_animation.h │ ├── draw_left_image.h │ ├── profile.h │ ├── draw_right_image.h │ ├── battery.h │ ├── draw_left_image.c │ ├── draw_right_image.c │ ├── screen_peripheral.h │ ├── screen.h │ ├── output.h │ ├── left_animation.c │ ├── right_animation.c │ ├── profile.c │ ├── util.h │ ├── battery.c │ ├── util.c │ ├── output.c │ ├── screen_peripheral.c │ └── screen.c │ ├── nice_shield_base.zmk.yml │ ├── README.md │ ├── nice_shield_base.overlay │ ├── custom_status_screen.c │ ├── CMakeLists.txt │ └── Kconfig.defconfig ├── zephyr └── module.yml ├── LICENSE └── README.md /boards/shields/nice_shield_base/nice_shield_base.conf: -------------------------------------------------------------------------------- 1 | CONFIG_ZMK_DISPLAY=y 2 | CONFIG_ZMK_DISPLAY_BLANK_ON_IDLE=n -------------------------------------------------------------------------------- /zephyr/module.yml: -------------------------------------------------------------------------------- 1 | name: "zmk-shield-nice!view-shield-base" 2 | build: 3 | settings: 4 | board_root: . 5 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/Kconfig.shield: -------------------------------------------------------------------------------- 1 | config SHIELD_NICE_VIEW_SHIELD_BASE 2 | def_bool $(shields_list_contains,nice_shield_base) 3 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/assets/custom_fonts.h: -------------------------------------------------------------------------------- 1 | #ifndef CUSTOM_FONTS_H 2 | #define CUSTOM_FONTS_H 3 | 4 | LV_FONT_DECLARE(pixel_operator_mono); 5 | 6 | #endif -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/left_animation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "util.h" 5 | 6 | void draw_left_animation(lv_obj_t *canvas); 7 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/right_animation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "util.h" 5 | 6 | void draw_right_animation(lv_obj_t *canvas); 7 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/draw_left_image.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "util.h" 5 | #include "screen.h" 6 | 7 | void draw_left_image(lv_obj_t *canvas); 8 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/profile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "util.h" 5 | 6 | void draw_profile_status(lv_obj_t *canvas, const struct status_state *state); -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/draw_right_image.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "util.h" 5 | #include "screen_peripheral.h" 6 | 7 | void draw_right_image(lv_obj_t *canvas); 8 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/nice_shield_base.zmk.yml: -------------------------------------------------------------------------------- 1 | file_format: "1" 2 | id: nice-shield-base 3 | name: nice!view_shield_base 4 | type: shield 5 | url: https://nicekeyboards.com/nice-view 6 | requires: [nice_view_header] 7 | features: 8 | - display 9 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/README.md: -------------------------------------------------------------------------------- 1 | # A nice!view 2 | 3 | The nice!view is a low-power, high refresh rate display meant to replace I2C OLEDs traditionally used. 4 | 5 | This shield requires that an `&nice_view_spi` labeled SPI bus is provided with _at least_ MOSI, SCK, and CS pins defined. 6 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/battery.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "util.h" 5 | 6 | struct battery_status_state { 7 | uint8_t level; 8 | #if IS_ENABLED(CONFIG_USB_DEVICE_STACK) 9 | bool usb_present; 10 | #endif 11 | }; 12 | 13 | void draw_battery_status(lv_obj_t *canvas, const struct status_state *state); 14 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/draw_left_image.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "draw_left_image.h" 4 | 5 | LV_IMG_DECLARE(left_image); 6 | 7 | void draw_left_image(lv_obj_t *canvas) { 8 | lv_obj_t *art = lv_img_create(canvas); 9 | 10 | lv_img_set_src(art, &left_image); 11 | 12 | lv_obj_align(art, LV_ALIGN_TOP_LEFT, 36, 0); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/draw_right_image.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "draw_right_image.h" 4 | 5 | LV_IMG_DECLARE(right_image); 6 | 7 | void draw_right_image(lv_obj_t *canvas) { 8 | lv_obj_t *art = lv_img_create(canvas); 9 | 10 | lv_img_set_src(art, &right_image); 11 | 12 | lv_obj_align(art, LV_ALIGN_TOP_LEFT, 36, 0); 13 | } 14 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/screen_peripheral.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "util.h" 6 | 7 | struct zmk_widget_screen { 8 | sys_snode_t node; 9 | lv_obj_t *obj; 10 | lv_color_t cbuf[BUFFER_SIZE * BUFFER_SIZE]; 11 | struct status_state state; 12 | }; 13 | 14 | int zmk_widget_screen_init(struct zmk_widget_screen *widget, lv_obj_t *parent); 15 | lv_obj_t *zmk_widget_screen_obj(struct zmk_widget_screen *widget); -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/nice_shield_base.overlay: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 The ZMK Contributors 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | &nice_view_spi { 8 | status = "okay"; 9 | nice_view: ls0xx@0 { 10 | compatible = "sharp,ls0xx"; 11 | spi-max-frequency = <1000000>; 12 | reg = <0>; 13 | width = <160>; 14 | height = <68>; 15 | }; 16 | }; 17 | 18 | / { 19 | chosen { 20 | zephyr,display = &nice_view; 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/screen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "util.h" 6 | 7 | struct zmk_widget_screen { 8 | sys_snode_t node; 9 | lv_obj_t *obj; 10 | lv_color_t cbuf[BUFFER_SIZE * BUFFER_SIZE]; 11 | lv_color_t cbuf3[BUFFER_SIZE * BUFFER_SIZE]; 12 | struct status_state state; 13 | }; 14 | 15 | int zmk_widget_screen_init(struct zmk_widget_screen *widget, lv_obj_t *parent); 16 | lv_obj_t *zmk_widget_screen_obj(struct zmk_widget_screen *widget); 17 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/output.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "util.h" 6 | 7 | #if !IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) 8 | struct output_status_state { 9 | struct zmk_endpoint_instance selected_endpoint; 10 | int active_profile_index; 11 | bool active_profile_connected; 12 | bool active_profile_bonded; 13 | }; 14 | #else 15 | struct peripheral_status_state { 16 | bool connected; 17 | }; 18 | #endif 19 | 20 | void draw_output_status(lv_obj_t *canvas, const struct status_state *state); -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/custom_status_screen.c: -------------------------------------------------------------------------------- 1 | #include "widgets/screen.h" 2 | 3 | #include 4 | LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); 5 | 6 | #include "assets/pixel_operator_mono.c" 7 | #include "assets/custom_fonts.h" 8 | 9 | #if IS_ENABLED(CONFIG_NICE_VIEW_WIDGET_STATUS) 10 | static struct zmk_widget_screen screen_widget; 11 | #endif 12 | 13 | lv_obj_t *zmk_display_status_screen() { 14 | lv_obj_t *screen; 15 | screen = lv_obj_create(NULL); 16 | 17 | #if IS_ENABLED(CONFIG_NICE_VIEW_WIDGET_STATUS) 18 | zmk_widget_screen_init(&screen_widget, screen); 19 | lv_obj_align(zmk_widget_screen_obj(&screen_widget), LV_ALIGN_TOP_LEFT, 0, 0); 20 | #endif 21 | 22 | return screen; 23 | } 24 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/left_animation.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "left_animation.h" 4 | 5 | LV_IMG_DECLARE(left_image); 6 | 7 | const lv_img_dsc_t *anim_imgs[] = { 8 | &left_image, 9 | }; 10 | 11 | void draw_left_animation(lv_obj_t *canvas) { 12 | #if IS_ENABLED(CONFIG_NICE_LEFT_ANIMATION) 13 | lv_obj_t *art = lv_animimg_create(canvas); 14 | lv_obj_center(art); 15 | 16 | lv_animimg_set_src(art, (const void **)anim_imgs, 16); 17 | lv_animimg_set_duration(art, CONFIG_NICE_LEFT_ANIMATION_MS); 18 | lv_animimg_set_repeat_count(art, LV_ANIM_REPEAT_INFINITE); 19 | lv_animimg_start(art); 20 | #else 21 | lv_obj_t *art = lv_img_create(canvas); 22 | 23 | lv_img_set_src(art, &left_image); 24 | #endif 25 | 26 | lv_obj_align(art, LV_ALIGN_TOP_LEFT, 36, 0); 27 | } 28 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/right_animation.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "right_animation.h" 4 | 5 | LV_IMG_DECLARE(right_image); 6 | 7 | const lv_img_dsc_t *anim_imgs[] = { 8 | &right_image, 9 | }; 10 | 11 | void draw_right_animation(lv_obj_t *canvas) { 12 | #if IS_ENABLED(CONFIG_NICE_RIGHT_ANIMATION) 13 | lv_obj_t *art = lv_animimg_create(canvas); 14 | lv_obj_center(art); 15 | 16 | lv_animimg_set_src(art, (const void **)anim_imgs, 16); 17 | lv_animimg_set_duration(art, CONFIG_NICE_RIGHT_ANIMATION_MS); 18 | lv_animimg_set_repeat_count(art, LV_ANIM_REPEAT_INFINITE); 19 | lv_animimg_start(art); 20 | #else 21 | lv_obj_t *art = lv_img_create(canvas); 22 | 23 | lv_img_set_src(art, &right_image); 24 | #endif 25 | 26 | lv_obj_align(art, LV_ALIGN_TOP_LEFT, 36, 0); 27 | } 28 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/profile.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "profile.h" 3 | 4 | LV_IMG_DECLARE(profiles); 5 | 6 | static void draw_inactive_profiles(lv_obj_t *canvas, const struct status_state *state) { 7 | lv_draw_img_dsc_t img_dsc; 8 | lv_draw_img_dsc_init(&img_dsc); 9 | 10 | lv_canvas_draw_img(canvas, 18, 145 + BUFFER_OFFSET_BOTTOM, &profiles, &img_dsc); 11 | } 12 | 13 | static void draw_active_profile(lv_obj_t *canvas, const struct status_state *state) { 14 | lv_draw_rect_dsc_t rect_white_dsc; 15 | init_rect_dsc(&rect_white_dsc, LVGL_FOREGROUND); 16 | 17 | int offset = state->active_profile_index * 7; 18 | 19 | lv_canvas_draw_rect(canvas, 18 + offset, 145 + BUFFER_OFFSET_BOTTOM, 3, 3, &rect_white_dsc); 20 | } 21 | 22 | void draw_profile_status(lv_obj_t *canvas, const struct status_state *state) { 23 | draw_inactive_profiles(canvas, state); 24 | draw_active_profile(canvas, state); 25 | } 26 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(CONFIG_ZMK_DISPLAY AND CONFIG_NICE_VIEW_WIDGET_STATUS) 2 | zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) 3 | zephyr_library_sources(custom_status_screen.c) 4 | zephyr_library_sources(assets/images.c) 5 | zephyr_library_sources(widgets/battery.c) 6 | zephyr_library_sources(widgets/output.c) 7 | zephyr_library_sources(widgets/util.c) 8 | 9 | if(NOT CONFIG_ZMK_SPLIT OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) 10 | zephyr_library_sources(widgets/profile.c) 11 | zephyr_library_sources(widgets/screen.c) 12 | zephyr_library_sources(assets/left_image.c) 13 | zephyr_library_sources(widgets/draw_left_image.c) 14 | zephyr_library_sources(widgets/left_animation.c) 15 | else() 16 | zephyr_library_sources(assets/right_image.c) 17 | zephyr_library_sources(widgets/draw_right_image.c) 18 | zephyr_library_sources(widgets/right_animation.c) 19 | zephyr_library_sources(widgets/screen_peripheral.c) 20 | endif() 21 | endif() 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 whoop-t 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define SCREEN_WIDTH 68 7 | #define SCREEN_HEIGHT 160 8 | 9 | #define BUFFER_SIZE 68 10 | #define BUFFER_OFFSET_BOTTOM -129 11 | 12 | #define LVGL_BACKGROUND \ 13 | IS_ENABLED(CONFIG_NICE_VIEW_WIDGET_INVERTED) ? lv_color_black() : lv_color_white() 14 | #define LVGL_FOREGROUND \ 15 | IS_ENABLED(CONFIG_NICE_VIEW_WIDGET_INVERTED) ? lv_color_white() : lv_color_black() 16 | 17 | struct status_state { 18 | uint8_t battery; 19 | bool charging; 20 | #if !IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) 21 | struct zmk_endpoint_instance selected_endpoint; 22 | int active_profile_index; 23 | bool active_profile_connected; 24 | bool active_profile_bonded; 25 | #else 26 | bool connected; 27 | #endif 28 | }; 29 | 30 | void to_uppercase(char *str); 31 | void rotate_canvas(lv_obj_t *canvas, lv_color_t cbuf[]); 32 | void fill_background(lv_obj_t *canvas); 33 | void init_rect_dsc(lv_draw_rect_dsc_t *rect_dsc, lv_color_t bg_color); 34 | void init_line_dsc(lv_draw_line_dsc_t *line_dsc, lv_color_t color, uint8_t width); 35 | void init_label_dsc(lv_draw_label_dsc_t *label_dsc, lv_color_t color, const lv_font_t *font, 36 | lv_text_align_t align); 37 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/battery.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "battery.h" 3 | #include "../assets/custom_fonts.h" 4 | 5 | LV_IMG_DECLARE(bolt); 6 | 7 | static void draw_level(lv_obj_t *canvas, const struct status_state *state) { 8 | lv_draw_label_dsc_t label_right_dsc; 9 | init_label_dsc(&label_right_dsc, LVGL_FOREGROUND, &pixel_operator_mono, LV_TEXT_ALIGN_RIGHT); 10 | 11 | char text[10] = {}; 12 | 13 | sprintf(text, "%i%%", state->battery); 14 | lv_canvas_draw_text(canvas, 26, 19, 42, &label_right_dsc, text); 15 | } 16 | 17 | static void draw_charging_level(lv_obj_t *canvas, const struct status_state *state) { 18 | lv_draw_img_dsc_t img_dsc; 19 | lv_draw_img_dsc_init(&img_dsc); 20 | lv_draw_label_dsc_t label_right_dsc; 21 | init_label_dsc(&label_right_dsc, LVGL_FOREGROUND, &pixel_operator_mono, LV_TEXT_ALIGN_RIGHT); 22 | 23 | char text[10] = {}; 24 | 25 | sprintf(text, "%i%%", state->battery); 26 | lv_canvas_draw_text(canvas, 26, 19, 35, &label_right_dsc, text); 27 | lv_canvas_draw_img(canvas, 62, 21, &bolt, &img_dsc); 28 | } 29 | 30 | void draw_battery_status(lv_obj_t *canvas, const struct status_state *state) { 31 | lv_draw_label_dsc_t label_left_dsc; 32 | init_label_dsc(&label_left_dsc, LVGL_FOREGROUND, &pixel_operator_mono, LV_TEXT_ALIGN_LEFT); 33 | lv_canvas_draw_text(canvas, 0, 19, 25, &label_left_dsc, "BAT"); 34 | 35 | if (state->charging) { 36 | draw_charging_level(canvas, state); 37 | } else { 38 | draw_level(canvas, state); 39 | } 40 | } -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/Kconfig.defconfig: -------------------------------------------------------------------------------- 1 | if SHIELD_NICE_VIEW_SHIELD_BASE 2 | 3 | config LV_Z_VDB_SIZE 4 | default 100 5 | 6 | config LV_DPI_DEF 7 | default 161 8 | 9 | config LV_Z_BITS_PER_PIXEL 10 | default 1 11 | 12 | choice LV_COLOR_DEPTH 13 | default LV_COLOR_DEPTH_1 14 | endchoice 15 | 16 | choice ZMK_DISPLAY_WORK_QUEUE 17 | default ZMK_DISPLAY_WORK_QUEUE_DEDICATED 18 | endchoice 19 | 20 | choice ZMK_DISPLAY_STATUS_SCREEN 21 | default ZMK_DISPLAY_STATUS_SCREEN_CUSTOM 22 | endchoice 23 | 24 | config LV_Z_MEM_POOL_SIZE 25 | default 4096 if ZMK_DISPLAY_STATUS_SCREEN_CUSTOM 26 | 27 | config ZMK_DISPLAY_STATUS_SCREEN_CUSTOM 28 | imply NICE_VIEW_WIDGET_STATUS 29 | 30 | config NICE_RIGHT_ANIMATION 31 | bool "Enable animation on peripheral" 32 | default y 33 | 34 | config NICE_LEFT_ANIMATION 35 | bool "Enable animation on peripheral" 36 | default y 37 | 38 | config NICE_RIGHT_ANIMATION_MS 39 | int "Animation length in milliseconds" 40 | default 2400 41 | 42 | config NICE_LEFT_ANIMATION_MS 43 | int "Animation length in milliseconds" 44 | default 2400 45 | 46 | config NICE_VIEW_WIDGET_STATUS 47 | select LV_USE_LABEL 48 | select LV_USE_IMG 49 | select LV_USE_CANVAS 50 | select LV_USE_ANIMIMG 51 | select LV_USE_ANIMATION 52 | 53 | config NICE_VIEW_WIDGET_INVERTED 54 | bool "Invert display colors" 55 | 56 | if !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL 57 | 58 | endif # !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL 59 | 60 | endif # SHIELD_NICE_VIEW_SHIELD_BASE 61 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "util.h" 3 | #include 4 | 5 | void to_uppercase(char *str) { 6 | for (int i = 0; str[i] != '\0'; i++) { 7 | str[i] = toupper(str[i]); 8 | } 9 | } 10 | 11 | void rotate_canvas(lv_obj_t *canvas, lv_color_t cbuf[]) { 12 | static lv_color_t cbuf_tmp[BUFFER_SIZE * BUFFER_SIZE]; 13 | memcpy(cbuf_tmp, cbuf, sizeof(cbuf_tmp)); 14 | 15 | lv_img_dsc_t img; 16 | img.data = (void *)cbuf_tmp; 17 | img.header.cf = LV_IMG_CF_TRUE_COLOR; 18 | img.header.w = BUFFER_SIZE; 19 | img.header.h = BUFFER_SIZE; 20 | 21 | lv_canvas_fill_bg(canvas, LVGL_BACKGROUND, LV_OPA_COVER); 22 | lv_canvas_transform(canvas, &img, 900, LV_IMG_ZOOM_NONE, -1, 0, BUFFER_SIZE / 2, 23 | BUFFER_SIZE / 2, false); 24 | } 25 | 26 | void fill_background(lv_obj_t *canvas) { 27 | lv_draw_rect_dsc_t rect_black_dsc; 28 | init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); 29 | 30 | lv_canvas_draw_rect(canvas, 0, 0, BUFFER_SIZE, BUFFER_SIZE, &rect_black_dsc); 31 | } 32 | 33 | void init_label_dsc(lv_draw_label_dsc_t *label_dsc, lv_color_t color, const lv_font_t *font, 34 | lv_text_align_t align) { 35 | lv_draw_label_dsc_init(label_dsc); 36 | label_dsc->color = color; 37 | label_dsc->font = font; 38 | label_dsc->align = align; 39 | } 40 | 41 | void init_rect_dsc(lv_draw_rect_dsc_t *rect_dsc, lv_color_t bg_color) { 42 | lv_draw_rect_dsc_init(rect_dsc); 43 | rect_dsc->bg_color = bg_color; 44 | } 45 | 46 | void init_line_dsc(lv_draw_line_dsc_t *line_dsc, lv_color_t color, uint8_t width) { 47 | lv_draw_line_dsc_init(line_dsc); 48 | line_dsc->color = color; 49 | line_dsc->width = width; 50 | } -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/output.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "output.h" 3 | #include "../assets/custom_fonts.h" 4 | 5 | LV_IMG_DECLARE(bt_no_signal); 6 | LV_IMG_DECLARE(bt_unbonded); 7 | LV_IMG_DECLARE(bt); 8 | LV_IMG_DECLARE(usb); 9 | 10 | #if !IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) 11 | static void draw_usb_connected(lv_obj_t *canvas) { 12 | lv_draw_img_dsc_t img_dsc; 13 | lv_draw_img_dsc_init(&img_dsc); 14 | 15 | lv_canvas_draw_img(canvas, 45, 2, &usb, &img_dsc); 16 | } 17 | 18 | static void draw_ble_unbonded(lv_obj_t *canvas) { 19 | lv_draw_img_dsc_t img_dsc; 20 | lv_draw_img_dsc_init(&img_dsc); 21 | 22 | lv_canvas_draw_img(canvas, 44, 0, &bt_unbonded, &img_dsc); 23 | } 24 | #endif 25 | 26 | static void draw_ble_disconnected(lv_obj_t *canvas) { 27 | lv_draw_img_dsc_t img_dsc; 28 | lv_draw_img_dsc_init(&img_dsc); 29 | 30 | lv_canvas_draw_img(canvas, 49, 0, &bt_no_signal, &img_dsc); 31 | } 32 | 33 | static void draw_ble_connected(lv_obj_t *canvas) { 34 | lv_draw_img_dsc_t img_dsc; 35 | lv_draw_img_dsc_init(&img_dsc); 36 | 37 | lv_canvas_draw_img(canvas, 49, 0, &bt, &img_dsc); 38 | } 39 | 40 | void draw_output_status(lv_obj_t *canvas, const struct status_state *state) { 41 | lv_draw_label_dsc_t label_dsc; 42 | init_label_dsc(&label_dsc, LVGL_FOREGROUND, &pixel_operator_mono, LV_TEXT_ALIGN_LEFT); 43 | lv_canvas_draw_text(canvas, 0, 1, 25, &label_dsc, "SIG"); 44 | 45 | lv_draw_rect_dsc_t rect_white_dsc; 46 | init_rect_dsc(&rect_white_dsc, LVGL_FOREGROUND); 47 | lv_canvas_draw_rect(canvas, 43, 0, 24, 15, &rect_white_dsc); 48 | 49 | #if !IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) 50 | switch (state->selected_endpoint.transport) { 51 | case ZMK_TRANSPORT_USB: 52 | draw_usb_connected(canvas); 53 | break; 54 | 55 | case ZMK_TRANSPORT_BLE: 56 | if (state->active_profile_bonded) { 57 | if (state->active_profile_connected) { 58 | draw_ble_connected(canvas); 59 | } else { 60 | draw_ble_disconnected(canvas); 61 | } 62 | } else { 63 | draw_ble_unbonded(canvas); 64 | } 65 | break; 66 | } 67 | #else 68 | if (state->connected) { 69 | draw_ble_connected(canvas); 70 | } else { 71 | draw_ble_disconnected(canvas); 72 | } 73 | #endif 74 | } -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/screen_peripheral.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "draw_right_image.h" 17 | // #include "right_animation.h" 18 | #include "battery.h" 19 | #include "output.h" 20 | #include "screen_peripheral.h" 21 | 22 | static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); 23 | 24 | /** 25 | * Draw buffers 26 | **/ 27 | 28 | static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], const struct status_state *state) { 29 | lv_obj_t *canvas = lv_obj_get_child(widget, 0); 30 | fill_background(canvas); 31 | 32 | // Draw widgets 33 | draw_output_status(canvas, state); 34 | draw_battery_status(canvas, state); 35 | 36 | // Rotate for horizontal display 37 | rotate_canvas(canvas, cbuf); 38 | } 39 | 40 | /** 41 | * Battery status 42 | **/ 43 | 44 | static void set_battery_status(struct zmk_widget_screen *widget, 45 | struct battery_status_state state) { 46 | #if IS_ENABLED(CONFIG_USB_DEVICE_STACK) 47 | widget->state.charging = state.usb_present; 48 | #endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ 49 | 50 | widget->state.battery = state.level; 51 | 52 | draw_top(widget->obj, widget->cbuf, &widget->state); 53 | } 54 | 55 | static void battery_status_update_cb(struct battery_status_state state) { 56 | struct zmk_widget_screen *widget; 57 | SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_battery_status(widget, state); } 58 | } 59 | 60 | static struct battery_status_state battery_status_get_state(const zmk_event_t *eh) { 61 | const struct zmk_battery_state_changed *ev = as_zmk_battery_state_changed(eh); 62 | 63 | return (struct battery_status_state){ 64 | .level = (ev != NULL) ? ev->state_of_charge : zmk_battery_state_of_charge(), 65 | #if IS_ENABLED(CONFIG_USB_DEVICE_STACK) 66 | .usb_present = zmk_usb_is_powered(), 67 | #endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ 68 | }; 69 | } 70 | 71 | ZMK_DISPLAY_WIDGET_LISTENER(widget_battery_status, struct battery_status_state, 72 | battery_status_update_cb, battery_status_get_state); 73 | 74 | ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); 75 | #if IS_ENABLED(CONFIG_USB_DEVICE_STACK) 76 | ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); 77 | #endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ 78 | 79 | /** 80 | * Peripheral status 81 | **/ 82 | 83 | static struct peripheral_status_state get_state(const zmk_event_t *_eh) { 84 | return (struct peripheral_status_state){.connected = zmk_split_bt_peripheral_is_connected()}; 85 | } 86 | 87 | static void set_connection_status(struct zmk_widget_screen *widget, 88 | struct peripheral_status_state state) { 89 | widget->state.connected = state.connected; 90 | 91 | draw_top(widget->obj, widget->cbuf, &widget->state); 92 | } 93 | 94 | static void output_status_update_cb(struct peripheral_status_state state) { 95 | struct zmk_widget_screen *widget; 96 | SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_connection_status(widget, state); } 97 | } 98 | 99 | ZMK_DISPLAY_WIDGET_LISTENER(widget_peripheral_status, struct peripheral_status_state, 100 | output_status_update_cb, get_state) 101 | ZMK_SUBSCRIPTION(widget_peripheral_status, zmk_split_peripheral_status_changed); 102 | 103 | /** 104 | * Initialization 105 | **/ 106 | 107 | int zmk_widget_screen_init(struct zmk_widget_screen *widget, lv_obj_t *parent) { 108 | widget->obj = lv_obj_create(parent); 109 | lv_obj_set_size(widget->obj, SCREEN_HEIGHT, SCREEN_WIDTH); 110 | 111 | lv_obj_t *top = lv_canvas_create(widget->obj); 112 | lv_obj_align(top, LV_ALIGN_TOP_RIGHT, 0, 0); 113 | lv_canvas_set_buffer(top, widget->cbuf, BUFFER_SIZE, BUFFER_SIZE, LV_IMG_CF_TRUE_COLOR); 114 | 115 | draw_right_image(widget->obj); 116 | // draw_right_animation(widget->obj); 117 | 118 | sys_slist_append(&widgets, &widget->node); 119 | widget_battery_status_init(); 120 | widget_peripheral_status_init(); 121 | 122 | return 0; 123 | } 124 | 125 | lv_obj_t *zmk_widget_screen_obj(struct zmk_widget_screen *widget) { return widget->obj; } 126 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/assets/left_image.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef LV_ATTRIBUTE_MEM_ALIGN 4 | #define LV_ATTRIBUTE_MEM_ALIGN 5 | #endif 6 | 7 | #ifndef LV_ATTRIBUTE_IMG_LEFT_IMAGE 8 | #define LV_ATTRIBUTE_IMG_LEFT_IMAGE 9 | #endif 10 | 11 | const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_LEFT_IMAGE uint8_t 12 | left_image_map[] = { 13 | #if CONFIG_NICE_VIEW_WIDGET_INVERTED 14 | 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ 15 | 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ 16 | #else 17 | 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ 18 | 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ 19 | #endif 20 | // REPLACE THESE BYTES 21 | 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 22 | 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 24 | 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0xc0, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 25 | 0x00, 0xa8, 0x82, 0x80, 0x80, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe3, 0xe3, 0x00, 0x00, 26 | 0xaa, 0x00, 0x00, 0x00, 0x02, 0xaa, 0xa2, 0xaa, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x07, 0x6d, 27 | 0xb6, 0xde, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x0a, 0xaa, 0xaa, 0xa8, 0x00, 0x00, 0x55, 0x00, 28 | 0x00, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xaa, 0x80, 0x00, 0x00, 0x0a, 0x28, 0xa2, 0xc8, 29 | 0x00, 0x00, 0x55, 0x40, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xaa, 0x80, 0x00, 0x00, 30 | 0x0a, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x55, 0x40, 0x00, 0x00, 0x3b, 0x6d, 0xb6, 0xdb, 0x00, 0x00, 31 | 0xaa, 0xa0, 0x00, 0x00, 0x2a, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x50, 0x00, 0x00, 0x0f, 0xff, 32 | 0xff, 0xff, 0xc0, 0x00, 0x2a, 0x80, 0x00, 0x00, 0x72, 0x29, 0xa2, 0x8a, 0x20, 0x00, 0x55, 0x54, 33 | 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xe0, 0x00, 0xaa, 0xaa, 0x00, 0x01, 0xed, 0xaa, 0xab, 0xaa, 34 | 0xa0, 0x00, 0x55, 0x55, 0x00, 0x03, 0x95, 0x6d, 0xb2, 0xdb, 0x60, 0x00, 0xaa, 0xaa, 0x80, 0x03, 35 | 0x65, 0xaa, 0xaa, 0xaa, 0xa0, 0x00, 0x55, 0x55, 0x40, 0x03, 0x75, 0xff, 0xdb, 0xbf, 0xf8, 0x00, 36 | 0xaa, 0xa8, 0xa0, 0x02, 0xec, 0x28, 0xba, 0x4a, 0x28, 0x00, 0x55, 0x47, 0x40, 0x0f, 0xdb, 0xfe, 37 | 0x76, 0xdf, 0xf8, 0x00, 0xaa, 0x1f, 0x80, 0x7f, 0xf2, 0xa9, 0xf5, 0xca, 0xa8, 0x00, 0x54, 0xdf, 38 | 0xff, 0xff, 0xef, 0x43, 0xf3, 0xdb, 0x68, 0x00, 0xab, 0xbf, 0xff, 0xff, 0x9b, 0x1f, 0xff, 0xca, 39 | 0xa8, 0x00, 0x47, 0xbf, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xdf, 0xf8, 0x00, 0x9f, 0xbf, 0xff, 0xff, 40 | 0xff, 0xff, 0xff, 0xaa, 0x28, 0x00, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xf8, 0x00, 41 | 0xff, 0x7f, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xaa, 0xa8, 0x00, 0xff, 0x7f, 0xff, 0xff, 0xfc, 0xd7, 42 | 0xff, 0x9b, 0x68, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xef, 0xff, 0x2a, 0xa8, 0x00, 0xfe, 0xff, 43 | 0xff, 0xff, 0xfe, 0xef, 0xff, 0x7f, 0xf0, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xf7, 0xff, 0x0a, 44 | 0x20, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x77, 0xff, 0x7f, 0xf0, 0x02, 0xfe, 0xff, 0xff, 0xff, 45 | 0xff, 0x77, 0xff, 0x2a, 0xa0, 0x08, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x77, 0xff, 0x5b, 0x60, 0x7c, 46 | 0xfe, 0xff, 0xff, 0xff, 0xff, 0x77, 0xfe, 0xaa, 0xa2, 0xa8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x47, 47 | 0xfe, 0xff, 0xff, 0xf0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x47, 0xfe, 0x8a, 0x2a, 0xa0, 0xfe, 0xff, 48 | 0xff, 0xff, 0xff, 0x77, 0xfe, 0xff, 0xff, 0xc0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x77, 0xfe, 0xaa, 49 | 0xaa, 0x80, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x77, 0xfd, 0xdb, 0x7f, 0x00, 0xff, 0x9f, 0xff, 0xff, 50 | 0xff, 0x76, 0xfc, 0xaa, 0xaa, 0x00, 0xff, 0x8f, 0xfb, 0xff, 0xff, 0x75, 0xfd, 0xff, 0xfc, 0x00, 51 | 0xf8, 0x27, 0xfd, 0xff, 0xfd, 0x73, 0xfc, 0x8a, 0x28, 0x00, 0x05, 0x51, 0xfd, 0xff, 0xfe, 0x07, 52 | 0xfd, 0xff, 0xf0, 0x08, 0xaa, 0xa8, 0xfd, 0xff, 0xff, 0x77, 0xfd, 0xaa, 0xa0, 0x20, 0x55, 0x50, 53 | 0x7d, 0xff, 0xff, 0x77, 0xfc, 0xdb, 0x60, 0xf0, 0xaa, 0xa0, 0x3d, 0xff, 0xfe, 0x77, 0xfa, 0xaa, 54 | 0xa2, 0xa0, 0x55, 0x40, 0x1d, 0xff, 0xfd, 0x7b, 0xfb, 0xff, 0xff, 0xc0, 0xaa, 0x80, 0x0d, 0xff, 55 | 0xfb, 0x7b, 0xfa, 0x8a, 0xaa, 0x80, 0x55, 0x00, 0x0d, 0xfe, 0xfb, 0x7b, 0xf3, 0xff, 0xff, 0x00, 56 | 0xa8, 0x00, 0x0d, 0xfe, 0xfb, 0x7b, 0xe2, 0xaa, 0xaa, 0x00, 0x44, 0x00, 0x01, 0xfe, 0xfb, 0x7a, 57 | 0xc2, 0xdb, 0xfc, 0x00, 0x28, 0x00, 0x01, 0xfe, 0xfb, 0x4a, 0x82, 0xaa, 0xa8, 0x00, 0x50, 0x00, 58 | 0x01, 0xff, 0x7b, 0x4a, 0x01, 0xff, 0xf0, 0x00, 0xa0, 0x00, 0x01, 0xff, 0x7b, 0x78, 0x00, 0xaa, 59 | 0x80, 0x00, 0x40, 0x00, 0x01, 0xfe, 0x71, 0x70, 0x00, 0x3f, 0x00, 0x00, 0x80, 0x00, 0x01, 0xfc, 60 | 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 | 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 62 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63 | 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 64 | 0x00, 0x00 65 | // END 66 | }; 67 | 68 | const lv_img_dsc_t left_image = { 69 | .header.cf = LV_IMG_CF_INDEXED_1BIT, 70 | .header.always_zero = 0, 71 | .header.reserved = 0, 72 | .header.w = 80, 73 | .header.h = 69, 74 | .data_size = 620, 75 | .data = left_image_map, 76 | }; 77 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/assets/right_image.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef LV_ATTRIBUTE_MEM_ALIGN 4 | #define LV_ATTRIBUTE_MEM_ALIGN 5 | #endif 6 | 7 | #ifndef LV_ATTRIBUTE_IMG_RIGHT_IMAGE 8 | #define LV_ATTRIBUTE_IMG_RIGHT_IMAGE 9 | #endif 10 | 11 | const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_RIGHT_IMAGE uint8_t 12 | right_image_map[] = { 13 | #if CONFIG_NICE_VIEW_WIDGET_INVERTED 14 | 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ 15 | 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ 16 | #else 17 | 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ 18 | 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ 19 | #endif 20 | // REPLACE THESE BYTES 21 | 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 22 | 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 23 | 0x00, 0x00, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xca, 0x60, 0x00, 0x00, 24 | 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xbf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x01, 25 | 0x2a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x01, 0x7f, 0xb0, 0x00, 0x00, 0x00, 0x00, 26 | 0xa8, 0x00, 0x00, 0x01, 0x2a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x02, 0xff, 0xd0, 27 | 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x02, 0xaa, 0x90, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 28 | 0x00, 0x02, 0xff, 0xd0, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x02, 0x80, 0x90, 0x00, 0x00, 29 | 0x00, 0x00, 0x55, 0x00, 0x00, 0x02, 0xbe, 0xd0, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x02, 30 | 0x7f, 0x10, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x0a, 0xff, 0x90, 0x00, 0x00, 0x00, 0x00, 31 | 0xaa, 0x00, 0x00, 0x0a, 0xff, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x51, 0x54, 0x00, 0xfa, 0xff, 0xd7, 32 | 0xc0, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0xfa, 0xcf, 0xd7, 0xf8, 0x00, 0x00, 0x00, 0x55, 0x55, 33 | 0x00, 0xfa, 0xcf, 0xd7, 0xfc, 0x00, 0x00, 0x00, 0x8a, 0xaa, 0x00, 0xfa, 0xff, 0xd7, 0xfe, 0x00, 34 | 0x00, 0x00, 0x55, 0x54, 0x00, 0xfa, 0xff, 0xd7, 0xff, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xb7, 0x7a, 35 | 0xff, 0xd7, 0xff, 0x80, 0x00, 0x00, 0x10, 0x05, 0xb7, 0x7a, 0xff, 0x97, 0xff, 0xc0, 0x00, 0x00, 36 | 0xaa, 0xa9, 0xb7, 0x7a, 0xff, 0x17, 0xff, 0xe0, 0x00, 0x00, 0x15, 0x55, 0xb7, 0x7a, 0xfe, 0xd7, 37 | 0xff, 0xe0, 0x00, 0x00, 0xaa, 0xa9, 0xb7, 0x7a, 0xfe, 0x97, 0xff, 0xf0, 0x00, 0x00, 0x15, 0x55, 38 | 0xb7, 0x7a, 0xc1, 0xd7, 0xff, 0xf0, 0x00, 0x00, 0xaa, 0xa8, 0x00, 0x7a, 0xbe, 0x97, 0xff, 0xf8, 39 | 0x00, 0x00, 0x15, 0x55, 0xb7, 0x7a, 0x7e, 0xd7, 0xff, 0xf8, 0x00, 0x00, 0xaa, 0xab, 0xb7, 0xba, 40 | 0xff, 0x17, 0xff, 0xf8, 0x00, 0x00, 0x15, 0x53, 0xb7, 0xba, 0xff, 0x97, 0xff, 0xf8, 0x00, 0x00, 41 | 0xaa, 0xab, 0xb7, 0xba, 0xff, 0xd7, 0xff, 0xf8, 0x00, 0x00, 0x10, 0x13, 0xb7, 0xba, 0xff, 0xd7, 42 | 0xff, 0xf8, 0x00, 0x00, 0xaa, 0xab, 0xb7, 0xba, 0xff, 0xd7, 0xff, 0xfa, 0x00, 0x00, 0x15, 0x50, 43 | 0x00, 0x3a, 0xcf, 0xd7, 0xff, 0xfb, 0x00, 0x00, 0xaa, 0xab, 0xb7, 0xba, 0xcf, 0xd7, 0xff, 0xfb, 44 | 0x80, 0x0a, 0x15, 0x53, 0xb7, 0xba, 0xff, 0xd7, 0xff, 0xfb, 0xfe, 0x1e, 0xaa, 0xab, 0xb7, 0xba, 45 | 0xff, 0xd7, 0xff, 0xfa, 0xab, 0xea, 0x15, 0x53, 0xb7, 0xba, 0xff, 0xd7, 0xff, 0xfb, 0xfe, 0x1e, 46 | 0xaa, 0xab, 0xb7, 0xba, 0xff, 0xd7, 0xff, 0xfb, 0x80, 0x0a, 0x15, 0x53, 0xb7, 0xba, 0xff, 0x97, 47 | 0xff, 0xfb, 0x00, 0x00, 0xaa, 0xab, 0xb7, 0xbb, 0x7f, 0xb7, 0xff, 0xfa, 0x00, 0x00, 0x10, 0x10, 48 | 0x00, 0x7b, 0x7f, 0xb7, 0xff, 0xf8, 0x00, 0x00, 0xaa, 0xa9, 0xb7, 0x7b, 0xbf, 0x6f, 0xff, 0xf8, 49 | 0x00, 0x00, 0x15, 0x55, 0xb7, 0x7b, 0xc0, 0xef, 0xff, 0xf8, 0x00, 0x00, 0xaa, 0xa9, 0xb7, 0x7b, 50 | 0xff, 0xef, 0xff, 0xf8, 0x00, 0x00, 0x15, 0x55, 0xb7, 0x7b, 0xff, 0xdf, 0xff, 0xf0, 0x00, 0x00, 51 | 0xaa, 0xa9, 0xb6, 0xfb, 0xff, 0xdf, 0xff, 0xf0, 0x00, 0x00, 0x15, 0x55, 0xb5, 0xfd, 0xff, 0xdf, 52 | 0xff, 0xf0, 0x00, 0x00, 0xaa, 0xa9, 0xb3, 0xfe, 0xff, 0xbf, 0xff, 0xe0, 0x00, 0x00, 0x55, 0x54, 53 | 0x07, 0xff, 0x7f, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x8a, 0x8a, 0xff, 0xff, 0x80, 0xff, 0xff, 0xe0, 54 | 0x00, 0x00, 0x50, 0x55, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xaa, 0xaa, 0x7f, 0xff, 55 | 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x45, 0x55, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 56 | 0xaa, 0xaa, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x45, 0x55, 0x7f, 0xff, 0xff, 0xff, 57 | 0xfc, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0x7f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x45, 0x55, 58 | 0x3f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0x00, 0x00, 0x55, 0x51, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x0a, 0xa0, 0x00, 60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x55, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 | 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x40, 0x00, 0x00, 0x00, 62 | 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 64 | 0x00, 0x00 65 | // END 66 | }; 67 | 68 | const lv_img_dsc_t right_image = { 69 | .header.cf = LV_IMG_CF_INDEXED_1BIT, 70 | .header.always_zero = 0, 71 | .header.reserved = 0, 72 | .header.w = 80, 73 | .header.h = 69, 74 | .data_size = 620, 75 | .data = right_image_map, 76 | }; 77 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/widgets/screen.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "draw_left_image.h" 19 | // #include "left_animation.h" 20 | #include "battery.h" 21 | #include "output.h" 22 | #include "profile.h" 23 | #include "screen.h" 24 | 25 | static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); 26 | 27 | /** 28 | * Draw buffers 29 | **/ 30 | 31 | static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], const struct status_state *state) { 32 | lv_obj_t *canvas = lv_obj_get_child(widget, 0); 33 | fill_background(canvas); 34 | 35 | // Draw widgets 36 | draw_output_status(canvas, state); 37 | draw_battery_status(canvas, state); 38 | 39 | // Rotate for horizontal display 40 | rotate_canvas(canvas, cbuf); 41 | } 42 | 43 | static void draw_bottom(lv_obj_t *widget, lv_color_t cbuf[], const struct status_state *state) { 44 | lv_obj_t *canvas = lv_obj_get_child(widget, 1); 45 | fill_background(canvas); 46 | 47 | // Draw widgets 48 | draw_profile_status(canvas, state); 49 | 50 | // Rotate for horizontal display 51 | rotate_canvas(canvas, cbuf); 52 | } 53 | 54 | /** 55 | * Battery status 56 | **/ 57 | 58 | static void set_battery_status(struct zmk_widget_screen *widget, 59 | struct battery_status_state state) { 60 | #if IS_ENABLED(CONFIG_USB_DEVICE_STACK) 61 | widget->state.charging = state.usb_present; 62 | #endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ 63 | widget->state.battery = state.level; 64 | 65 | draw_top(widget->obj, widget->cbuf, &widget->state); 66 | } 67 | 68 | static void battery_status_update_cb(struct battery_status_state state) { 69 | struct zmk_widget_screen *widget; 70 | SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_battery_status(widget, state); } 71 | } 72 | 73 | static struct battery_status_state battery_status_get_state(const zmk_event_t *eh) { 74 | const struct zmk_battery_state_changed *ev = as_zmk_battery_state_changed(eh); 75 | 76 | return (struct battery_status_state){ 77 | .level = (ev != NULL) ? ev->state_of_charge : zmk_battery_state_of_charge(), 78 | #if IS_ENABLED(CONFIG_USB_DEVICE_STACK) 79 | .usb_present = zmk_usb_is_powered(), 80 | #endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ 81 | }; 82 | } 83 | 84 | ZMK_DISPLAY_WIDGET_LISTENER(widget_battery_status, struct battery_status_state, 85 | battery_status_update_cb, battery_status_get_state); 86 | 87 | ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); 88 | #if IS_ENABLED(CONFIG_USB_DEVICE_STACK) 89 | ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); 90 | #endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ 91 | 92 | /** 93 | * Output status 94 | **/ 95 | 96 | static void set_output_status(struct zmk_widget_screen *widget, 97 | const struct output_status_state *state) { 98 | widget->state.selected_endpoint = state->selected_endpoint; 99 | widget->state.active_profile_index = state->active_profile_index; 100 | widget->state.active_profile_connected = state->active_profile_connected; 101 | widget->state.active_profile_bonded = state->active_profile_bonded; 102 | 103 | draw_top(widget->obj, widget->cbuf, &widget->state); 104 | draw_bottom(widget->obj, widget->cbuf3, &widget->state); 105 | } 106 | 107 | static void output_status_update_cb(struct output_status_state state) { 108 | struct zmk_widget_screen *widget; 109 | SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_output_status(widget, &state); } 110 | } 111 | 112 | static struct output_status_state output_status_get_state(const zmk_event_t *_eh) { 113 | return (struct output_status_state){ 114 | .selected_endpoint = zmk_endpoints_selected(), 115 | .active_profile_index = zmk_ble_active_profile_index(), 116 | .active_profile_connected = zmk_ble_active_profile_is_connected(), 117 | .active_profile_bonded = !zmk_ble_active_profile_is_open(), 118 | }; 119 | } 120 | 121 | ZMK_DISPLAY_WIDGET_LISTENER(widget_output_status, struct output_status_state, 122 | output_status_update_cb, output_status_get_state) 123 | ZMK_SUBSCRIPTION(widget_output_status, zmk_endpoint_changed); 124 | 125 | #if IS_ENABLED(CONFIG_USB_DEVICE_STACK) 126 | ZMK_SUBSCRIPTION(widget_output_status, zmk_usb_conn_state_changed); 127 | #endif 128 | #if defined(CONFIG_ZMK_BLE) 129 | ZMK_SUBSCRIPTION(widget_output_status, zmk_ble_active_profile_changed); 130 | #endif 131 | 132 | /** 133 | * Initialization 134 | **/ 135 | 136 | int zmk_widget_screen_init(struct zmk_widget_screen *widget, lv_obj_t *parent) { 137 | widget->obj = lv_obj_create(parent); 138 | lv_obj_set_size(widget->obj, SCREEN_HEIGHT, SCREEN_WIDTH); 139 | 140 | lv_obj_t *top = lv_canvas_create(widget->obj); 141 | lv_obj_align(top, LV_ALIGN_TOP_RIGHT, 0, 0); 142 | lv_canvas_set_buffer(top, widget->cbuf, BUFFER_SIZE, BUFFER_SIZE, LV_IMG_CF_TRUE_COLOR); 143 | 144 | lv_obj_t *bottom = lv_canvas_create(widget->obj); 145 | lv_obj_align(bottom, LV_ALIGN_TOP_RIGHT, BUFFER_OFFSET_BOTTOM, 0); 146 | lv_canvas_set_buffer(bottom, widget->cbuf3, BUFFER_SIZE, BUFFER_SIZE, LV_IMG_CF_TRUE_COLOR); 147 | 148 | draw_left_image(widget->obj); 149 | // draw_left_animation(widget->obj); 150 | 151 | sys_slist_append(&widgets, &widget->node); 152 | widget_battery_status_init(); 153 | widget_output_status_init(); 154 | 155 | return 0; 156 | } 157 | 158 | lv_obj_t *zmk_widget_screen_obj(struct zmk_widget_screen *widget) { return widget->obj; } 159 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/assets/images.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef LV_ATTRIBUTE_MEM_ALIGN 4 | #define LV_ATTRIBUTE_MEM_ALIGN 5 | #endif 6 | 7 | #ifndef LV_ATTRIBUTE_IMG_BOLT 8 | #define LV_ATTRIBUTE_IMG_BOLT 9 | #endif 10 | 11 | const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BOLT uint8_t bolt_map[] = { 12 | #if CONFIG_NICE_VIEW_WIDGET_INVERTED 13 | 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ 14 | 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ 15 | #else 16 | 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ 17 | 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ 18 | #endif 19 | 20 | 0x08, 0x10, 0x20, 0x40, 0xf8, 0x10, 0x20, 0x40, 0x80, 21 | }; 22 | 23 | const lv_img_dsc_t bolt = { 24 | .header.cf = LV_IMG_CF_INDEXED_1BIT, 25 | .header.always_zero = 0, 26 | .header.reserved = 0, 27 | .header.w = 5, 28 | .header.h = 9, 29 | .data_size = 17, 30 | .data = bolt_map, 31 | }; 32 | 33 | #ifndef LV_ATTRIBUTE_IMG_BT 34 | #define LV_ATTRIBUTE_IMG_BT 35 | #endif 36 | 37 | const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BT uint8_t bt_map[] = { 38 | #if CONFIG_NICE_VIEW_WIDGET_INVERTED 39 | 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ 40 | 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ 41 | #else 42 | 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ 43 | 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ 44 | #endif 45 | 46 | 0xfb, 0xf0, 0xf9, 0xf0, 0xf8, 0xf0, 0xda, 0x70, 0xcb, 0x30, 0xe2, 0x70, 0xf0, 0xf0, 0xf9, 47 | 0xf0, 0xf0, 0xf0, 0xe2, 0x70, 0xcb, 0x30, 0xda, 0x70, 0xf8, 0xf0, 0xf9, 0xf0, 0xfb, 0xf0, 48 | }; 49 | 50 | const lv_img_dsc_t bt = { 51 | .header.cf = LV_IMG_CF_INDEXED_1BIT, 52 | .header.always_zero = 0, 53 | .header.reserved = 0, 54 | .header.w = 12, 55 | .header.h = 15, 56 | .data_size = 38, 57 | .data = bt_map, 58 | }; 59 | 60 | #ifndef LV_ATTRIBUTE_IMG_BT_NO_SIGNAL 61 | #define LV_ATTRIBUTE_IMG_BT_NO_SIGNAL 62 | #endif 63 | 64 | const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BT_NO_SIGNAL uint8_t 65 | bt_no_signal_map[] = { 66 | #if CONFIG_NICE_VIEW_WIDGET_INVERTED 67 | 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ 68 | 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ 69 | #else 70 | 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ 71 | 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ 72 | #endif 73 | 74 | 0xfb, 0xf0, 0x79, 0xf0, 0x38, 0xf0, 0x9a, 0x70, 0xcf, 0x30, 0xe6, 0x70, 0xf3, 0xf0, 0xf9, 75 | 0xf0, 0xfc, 0xf0, 0xe6, 0x70, 0xcb, 0x30, 0xdb, 0x90, 0xf8, 0xc0, 0xf9, 0xe0, 0xfb, 0xf0, 76 | }; 77 | 78 | const lv_img_dsc_t bt_no_signal = { 79 | .header.cf = LV_IMG_CF_INDEXED_1BIT, 80 | .header.always_zero = 0, 81 | .header.reserved = 0, 82 | .header.w = 12, 83 | .header.h = 15, 84 | .data_size = 38, 85 | .data = bt_no_signal_map, 86 | }; 87 | 88 | #ifndef LV_ATTRIBUTE_IMG_BT_UNBONDED 89 | #define LV_ATTRIBUTE_IMG_BT_UNBONDED 90 | #endif 91 | 92 | const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BT_UNBONDED uint8_t 93 | bt_unbonded_map[] = { 94 | #if CONFIG_NICE_VIEW_WIDGET_INVERTED 95 | 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ 96 | 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ 97 | #else 98 | 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ 99 | 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ 100 | #endif 101 | 102 | 0x00, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x38, 0x00, 0x21, 0x2c, 0x10, 0x41, 0xa6, 0x08, 103 | 0x48, 0xec, 0x48, 0x90, 0x78, 0x24, 0x92, 0x31, 0x24, 0x90, 0x78, 0x24, 0x48, 0xec, 0x48, 104 | 0x41, 0xa6, 0x08, 0x21, 0x2c, 0x10, 0x00, 0x38, 0x00, 0x00, 0x30, 0x00, 0x00, 0x20, 0x00, 105 | }; 106 | 107 | const lv_img_dsc_t bt_unbonded = { 108 | .header.cf = LV_IMG_CF_INDEXED_1BIT, 109 | .header.always_zero = 0, 110 | .header.reserved = 0, 111 | .header.w = 22, 112 | .header.h = 15, 113 | .data_size = 53, 114 | .data = bt_unbonded_map, 115 | }; 116 | 117 | #ifndef LV_ATTRIBUTE_IMG_USB 118 | #define LV_ATTRIBUTE_IMG_USB 119 | #endif 120 | 121 | const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_USB uint8_t usb_map[] = { 122 | #if CONFIG_NICE_VIEW_WIDGET_INVERTED 123 | 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ 124 | 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ 125 | #else 126 | 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ 127 | 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ 128 | #endif 129 | 130 | 0xff, 0x9f, 0xf0, 0xfe, 0x0f, 0xf0, 0xfc, 0x9f, 0xf0, 0xf9, 0xff, 131 | 0xb0, 0x1b, 0xff, 0x90, 0x00, 0x00, 0x00, 0x1f, 0x7f, 0x90, 0xff, 132 | 0x3f, 0xb0, 0xff, 0x91, 0xf0, 0xff, 0xc1, 0xf0, 0xff, 0xf1, 0xf0, 133 | }; 134 | 135 | const lv_img_dsc_t usb = { 136 | .header.cf = LV_IMG_CF_INDEXED_1BIT, 137 | .header.always_zero = 0, 138 | .header.reserved = 0, 139 | .header.w = 20, 140 | .header.h = 11, 141 | .data_size = 41, 142 | .data = usb_map, 143 | }; 144 | 145 | #ifndef LV_ATTRIBUTE_IMG_GRID 146 | #define LV_ATTRIBUTE_IMG_GRID 147 | #endif 148 | 149 | const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_GRID uint8_t grid_map[] = { 150 | #if CONFIG_NICE_VIEW_WIDGET_INVERTED 151 | 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ 152 | 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ 153 | #else 154 | 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ 155 | 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ 156 | #endif 157 | 158 | 0xaa, 0x95, 0x52, 0xaa, 0x55, 0x4a, 0xa9, 0x55, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 159 | 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 160 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 161 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 0x20, 0x00, 162 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 163 | 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 164 | 0x00, 0x00, 0x00, 0xaa, 0x95, 0x52, 0xaa, 0x55, 0x4a, 0xa9, 0x55, 0x20, 0x00, 0x00, 0x00, 0x00, 165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 0x20, 0x00, 0x00, 166 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 0x20, 167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, 168 | 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 169 | 0x08, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 170 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x95, 0x52, 0xaa, 0x55, 0x4a, 0xa9, 0x55, 0x20, 0x00, 171 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 172 | 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 173 | 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 174 | 0x40, 0x08, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 175 | 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 176 | 0xaa, 0x95, 0x52, 0xaa, 0x55, 0x4a, 0xa9, 0x55, 0x20, 177 | }; 178 | 179 | const lv_img_dsc_t grid = { 180 | .header.cf = LV_IMG_CF_INDEXED_1BIT, 181 | .header.always_zero = 0, 182 | .header.reserved = 0, 183 | .header.w = 67, 184 | .header.h = 33, 185 | .data_size = 305, 186 | .data = grid_map, 187 | }; 188 | 189 | #ifndef LV_ATTRIBUTE_IMG_PROFILES 190 | #define LV_ATTRIBUTE_IMG_PROFILES 191 | #endif 192 | 193 | const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_PROFILES uint8_t 194 | profiles_map[] = { 195 | #if CONFIG_NICE_VIEW_WIDGET_INVERTED 196 | 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ 197 | 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ 198 | #else 199 | 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ 200 | 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ 201 | #endif 202 | 203 | 0xa1, 0x42, 0x85, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x42, 0x85, 0x0a, 204 | }; 205 | 206 | const lv_img_dsc_t profiles = { 207 | .header.cf = LV_IMG_CF_INDEXED_1BIT, 208 | .header.always_zero = 0, 209 | .header.reserved = 0, 210 | .header.w = 31, 211 | .header.h = 3, 212 | .data_size = 20, 213 | .data = profiles_map, 214 | }; 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nice-shield-base 2 | 3 | This is a base repo to help anyone get started creating their own images/animations for their nice!view. This guides focus is just changing the main image and leaving extras like bluetooth, battery, etc alone. Of course all these are changeable, but getting the repo set up and changing the main image is a good first step in customizing it more. 4 | 5 | > [!IMPORTANT] 6 | > This repo is only for nice!views and zmk with zephyr modules. This will NOT work for OLED/qmk setups. 7 | > Since this is a zephyr module, the shield repo is hosted on github and can be used by anyone. 8 | > 9 | > If you would like OLED/qmk examples, check out my collection of OLED displays for qmk [HERE](https://github.com/whoop-t/qmk-oled-collection) 10 | 11 | > [!NOTE] 12 | > When you have created your own display, consider adding it to [this collection](https://github.com/whoop-t/nice-shield-collection) I started for nice!view displays! 13 | 14 | ## Create locally within your own zmk config 15 | If you would like, you can add/create shields directly to your zmk config rather than host on github. I prefer hosting so that you can share more easily with others. 16 | 17 | That said, all you need to do is copy the directory `board/shields/nice_shield_base` from this repo directly into you zmk config directory `board/shields` 18 | 19 | You can skip the steps of cloning the repo and just alter the newly copied files in you zmk config instead of hosting and pushing to github. 20 | 21 | ## Prerequisite 22 | 1. Have [git](https://git-scm.com/) installed 23 | 2. Have a Github account 24 | 3. A board with nice!views 25 | 4. ZMK setup and you are able to flash your board 26 | 27 | ## Clone the repo 28 | 29 | > [!NOTE] 30 | > A convention I like to do is to name the repo/module starting with `nice` to signify that this is a nice!view module. 31 | > e.g if I was creating displays with star art, I'd name it something like `nice-star-display` or something similar. 32 | 33 | ### Clone the repo(RECOMMENDED) 34 | ``` 35 | git clone git@github.com:whoop-t/nice-shield-base.git your-repo-name 36 | ``` 37 | The above will clone the base repo into a folder of your choice. This should match the repo name you are going to create on github 38 | 39 | 2. Create new repo on github 40 | 41 | On you github, create a new repo with the same name as your folder you cloned too 42 | 43 | 3. Set your locally cloned repo remote to the new repo you created on github 44 | 45 | You need to attach your local clone to the remote repo, do this by running the command below 46 | > [!NOTE] 47 | > You can get the url by using the Code button on your repo on github 48 | ``` 49 | git remote set-url origin git@github.com:YOUR-USER/your-repo-name.git 50 | ``` 51 | 52 | You can verify that it is pointing to the remote repo with `git remote -v` 53 | 54 | 4. Push the local files up to the remote repo 55 | ``` 56 | git push 57 | ``` 58 | Now you should see all the base files in your repo on github 59 | 60 | ## Renaming 61 | 62 | After you have the code, you will need to rename some items to make sure it gets picked up as a module when it is used 63 | 64 | 1. Rename ids/variables in the code 65 | 66 | In `Kconfig.shield`, update `nice_shield_base` to your shield 67 | This will be your repo name but with underscores 68 | 69 | > [!IMPORTANT] 70 | > Do NOT update `SHIELD_NICE_VIEW_SHIELD_BASE`, only `nice_shield_base` in the parenthesis 71 | ``` 72 | config SHIELD_NICE_VIEW_SHIELD_BASE 73 | def_bool $(shields_list_contains,nice_shield_base) 74 | ``` 75 | 76 | > [!IMPORTANT] 77 | > `id:` should be hyphen case, eg if you repo is `your-repo`, make sure you use hyphens for the id 78 | 79 | In `shields/nice_shield_base/nice_shield_base.zmk.yml` rename these to your repo name: 80 | ```yaml 81 | id: nice-shield-base 82 | name: nice!view_shield_base 83 | ``` 84 | 85 | In `zephyr/module.yml` rename this to your repo name: 86 | ```yaml 87 | name: "zmk-shield-nice!view-your-repo" 88 | ``` 89 | > [!NOTE] 90 | > I dont think this one matters, but I like to update it 91 | 92 | 2. Rename files 93 | > [!IMPORTANT] 94 | > Files should be underscore 95 | 96 | - Rename `shields/nice_shield_base` to your repo name 97 | - Rename `shields/nice_shield_base/nice_shield_base.conf` to your repo name 98 | - Rename `shields/nice_shield_base/nice_shield_base.overlay` to your repo name 99 | - Rename `shields/nice_shield_base/nice_shield_base.zmk.yml` to your repo name 100 | 101 | ## Test your repo!!! 102 | 103 | After all the renaming and hooking up to your repo, test everything is working correctly by adding your new repo to your ZMK config. 104 | 105 | The repo already has a base image that can be flashed and tested before adding your own art to make sure the steps were followed correctly. 106 | 107 | ### Add your new module to your ZMK config 108 | 109 | Add your remote repo to `west.yaml` 110 | ```yaml 111 | manifest: 112 | remotes: 113 | - name: zmkfirmware 114 | url-base: https://github.com/zmkfirmware 115 | - name: your-github-user #new entry 116 | url-base: https://github.com/your-github-user #new entry 117 | projects: 118 | - name: zmk 119 | remote: zmkfirmware 120 | revision: main 121 | import: app/west.yml 122 | - name: your-repo-name #new entry 123 | remote: your-github-user #new entry 124 | revision: main #new entry 125 | self: 126 | path: config 127 | ``` 128 | 129 | Add your module to `build.yaml`(this is for corne, but change for your keyboard if needed) 130 | ```yaml 131 | include: 132 | - board: nice_nano_v2 133 | shield: corne_left nice_view_adapter your_repo_name #update entry 134 | - board: nice_nano_v2 135 | shield: corne_right nice_view_adapter your_repo_name #update entry 136 | ``` 137 | 138 | Also make sure to enable the custom status screen in your ZMK configuration, this would be your keyboards .conf file in the config directory: 139 | 140 | ``` 141 | CONFIG_ZMK_DISPLAY=y 142 | CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y 143 | ``` 144 | 145 | Now flash your board and you should see the base image from this repo. If there is an issue, go back and walkthrough the steps again and make sure you did everything correctly. 146 | 147 | ## Create 1-bit art 148 | > [!IMPORTANT] 149 | > ART MUST BE 80x69 150 | > 151 | > You can alter this in the code where you define your image so you can technically change this and make your art a different size, but this is the size I have found to be the best while keeping other information like battery etc 152 | 153 | > [!IMPORTANT] 154 | > WIP 155 | > TODO Add guide to create the pixel art 156 | 157 | > [!IMPORTANT] 158 | > WIP 159 | > TODO Add guide to animations and set in repo 160 | 161 | ## Add images 162 | 163 | > [!NOTE] 164 | > If you want animations, you can skip to the animation section 165 | 166 | > [!NOTE] 167 | > This section also assumes you already have an image created from the previous step 168 | 169 | ### Rotate your image 170 | 171 | This is a horizontal display so you need to rotate the image 90 degrees to the right 172 | 173 | I just use [iloveimg](https://www.iloveimg.com/rotate-image), but feel free to use anything. Just make sure you are rotating it 90 degrees to the right 174 | 175 | ### Image to code conversion 176 | 177 | Take your 1-bit art that you created or found and upload it to 178 | [image2cpp](https://javl.github.io/image2cpp/) 179 | 180 | The only option you need to change is `Code output format`, make sure its set to `Plain bytes` 181 | 182 | Then click `Generate Code` 183 | You will see the code, copy everything in the textfield 184 | 185 | ## Paste to code in repo 186 | 187 | Depending on the image you are setting, you will need to update one of the following files: 188 | 1. `assests/left_image.c` (for your left half) 189 | 2. `assests/right_image.c` (for your right half) 190 | 191 | You should see bytes already there, as well as a comments in the code above and below the bytes. 192 | 193 | Replace the bytes with your bytes from the conversion 194 | ```c 195 | // REPLACE THESE BYTES 196 | ... 197 | ... 198 | // END 199 | ``` 200 | 201 | Save the file 202 | 203 | Thats it! Repeat for your other side if needed 204 | 205 | ## Push the code to you github remote repo 206 | 207 | Once you have done all the changes you want, push the code to your remote github repo 208 | ``` 209 | git add . 210 | git commit -m "Your commit message" 211 | git push 212 | ``` 213 | 214 | Then you just need to adjust your ZMK config to use the module like in the above step(if you havent done so already) and flash your board! 215 | 216 | ## Issues 217 | 218 | If you have issues, raise an issue on github and I will try to help out when I have time. This will also help me tweak the guide with anything I may have missed. 219 | -------------------------------------------------------------------------------- /boards/shields/nice_shield_base/assets/pixel_operator_mono.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Size: 16 px 3 | * Bpp: 1 4 | * Opts: --font PixelOperatorMono.ttf --size 16 --format lvgl --bpp 1 --range 0x20-0x7F 5 | *--no-compress -o pixel_operator_mono.c 6 | * 7 | * Released by Jayvee Enaguas (HarvettFox96) 8 | * licensed under a Creative Commons Zero (CC0) 1.0 9 | * (c) 2009-2018. 10 | ******************************************************************************/ 11 | 12 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 13 | #include "lvgl.h" 14 | #else 15 | #include 16 | #endif 17 | 18 | #ifndef PIXEL_OPERATOR_MONO 19 | #define PIXEL_OPERATOR_MONO 1 20 | #endif 21 | 22 | #if PIXEL_OPERATOR_MONO 23 | 24 | /*----------------- 25 | * BITMAPS 26 | *----------------*/ 27 | 28 | /*Store the image of the glyphs*/ 29 | static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 30 | /* U+0020 " " */ 31 | 0x0, 32 | 33 | /* U+0021 "!" */ 34 | 0xfe, 0x80, 35 | 36 | /* U+0022 "\"" */ 37 | 0xb6, 0x80, 38 | 39 | /* U+0023 "#" */ 40 | 0x49, 0x2f, 0xd2, 0x49, 0x2f, 0xd2, 0x48, 41 | 42 | /* U+0024 "$" */ 43 | 0x21, 0x1d, 0x5a, 0x51, 0xc5, 0x2d, 0x5c, 0x42, 0x0, 44 | 45 | /* U+0025 "%" */ 46 | 0x41, 0x42, 0x92, 0x41, 0x4, 0x92, 0x85, 0x4, 47 | 48 | /* U+0026 "&" */ 49 | 0x74, 0x61, 0x7, 0x46, 0x31, 0x78, 50 | 51 | /* U+0027 "'" */ 52 | 0xe0, 53 | 54 | /* U+0028 "(" */ 55 | 0x2a, 0x49, 0x22, 0x20, 56 | 57 | /* U+0029 ")" */ 58 | 0x88, 0x92, 0x4a, 0x80, 59 | 60 | /* U+002A "*" */ 61 | 0x25, 0x5d, 0x52, 0x0, 62 | 63 | /* U+002B "+" */ 64 | 0x21, 0x3e, 0x42, 0x0, 65 | 66 | /* U+002C "," */ 67 | 0x58, 68 | 69 | /* U+002D "-" */ 70 | 0xf0, 71 | 72 | /* U+002E "." */ 73 | 0x80, 74 | 75 | /* U+002F "/" */ 76 | 0x24, 0xa4, 0xa4, 0x80, 77 | 78 | /* U+0030 "0" */ 79 | 0x74, 0x63, 0x3a, 0xe6, 0x31, 0x70, 80 | 81 | /* U+0031 "1" */ 82 | 0x23, 0x28, 0x42, 0x10, 0x84, 0xf8, 83 | 84 | /* U+0032 "2" */ 85 | 0x74, 0x42, 0x22, 0x22, 0x10, 0xf8, 86 | 87 | /* U+0033 "3" */ 88 | 0x74, 0x42, 0x13, 0x4, 0x31, 0x70, 89 | 90 | /* U+0034 "4" */ 91 | 0x8, 0xca, 0x98, 0xfc, 0x21, 0x8, 92 | 93 | /* U+0035 "5" */ 94 | 0xfc, 0x21, 0xe0, 0x84, 0x31, 0x70, 95 | 96 | /* U+0036 "6" */ 97 | 0x74, 0x61, 0xf, 0x46, 0x31, 0x70, 98 | 99 | /* U+0037 "7" */ 100 | 0xf8, 0x42, 0x22, 0x22, 0x10, 0x80, 101 | 102 | /* U+0038 "8" */ 103 | 0x74, 0x63, 0x17, 0x46, 0x31, 0x70, 104 | 105 | /* U+0039 "9" */ 106 | 0x74, 0x63, 0x17, 0x84, 0x31, 0x70, 107 | 108 | /* U+003A ":" */ 109 | 0x82, 110 | 111 | /* U+003B ";" */ 112 | 0x40, 0x5, 0x80, 113 | 114 | /* U+003C "<" */ 115 | 0x2a, 0x22, 116 | 117 | /* U+003D "=" */ 118 | 0xf0, 0xf0, 119 | 120 | /* U+003E ">" */ 121 | 0x88, 0xa8, 122 | 123 | /* U+003F "?" */ 124 | 0x74, 0x42, 0x22, 0x10, 0x80, 0x20, 125 | 126 | /* U+0040 "@" */ 127 | 0x7d, 0x6, 0x6d, 0x5a, 0xb5, 0x67, 0x40, 0x7c, 128 | 129 | /* U+0041 "A" */ 130 | 0x74, 0x63, 0x18, 0xfe, 0x31, 0x88, 131 | 132 | /* U+0042 "B" */ 133 | 0xf4, 0x63, 0x1f, 0x46, 0x31, 0xf0, 134 | 135 | /* U+0043 "C" */ 136 | 0x74, 0x61, 0x8, 0x42, 0x11, 0x70, 137 | 138 | /* U+0044 "D" */ 139 | 0xf4, 0x63, 0x18, 0xc6, 0x31, 0xf0, 140 | 141 | /* U+0045 "E" */ 142 | 0xfc, 0x21, 0xe, 0x42, 0x10, 0xf8, 143 | 144 | /* U+0046 "F" */ 145 | 0xfc, 0x21, 0xe, 0x42, 0x10, 0x80, 146 | 147 | /* U+0047 "G" */ 148 | 0x74, 0x61, 0x9, 0xc6, 0x31, 0x78, 149 | 150 | /* U+0048 "H" */ 151 | 0x8c, 0x63, 0x1f, 0xc6, 0x31, 0x88, 152 | 153 | /* U+0049 "I" */ 154 | 0xf9, 0x8, 0x42, 0x10, 0x84, 0xf8, 155 | 156 | /* U+004A "J" */ 157 | 0x3c, 0x20, 0x82, 0x8, 0x20, 0xa2, 0x70, 158 | 159 | /* U+004B "K" */ 160 | 0x8c, 0x65, 0x4c, 0x52, 0x51, 0x88, 161 | 162 | /* U+004C "L" */ 163 | 0x84, 0x21, 0x8, 0x42, 0x10, 0xf8, 164 | 165 | /* U+004D "M" */ 166 | 0x83, 0x7, 0x1d, 0x59, 0x30, 0x60, 0xc1, 0x82, 167 | 168 | /* U+004E "N" */ 169 | 0x8c, 0x63, 0x9a, 0xce, 0x31, 0x88, 170 | 171 | /* U+004F "O" */ 172 | 0x74, 0x63, 0x18, 0xc6, 0x31, 0x70, 173 | 174 | /* U+0050 "P" */ 175 | 0xf4, 0x63, 0x1f, 0x42, 0x10, 0x80, 176 | 177 | /* U+0051 "Q" */ 178 | 0x74, 0x63, 0x18, 0xc6, 0xb2, 0x68, 179 | 180 | /* U+0052 "R" */ 181 | 0xf4, 0x63, 0x1f, 0x52, 0x51, 0x88, 182 | 183 | /* U+0053 "S" */ 184 | 0x74, 0x61, 0x7, 0x4, 0x31, 0x70, 185 | 186 | /* U+0054 "T" */ 187 | 0xf9, 0x8, 0x42, 0x10, 0x84, 0x20, 188 | 189 | /* U+0055 "U" */ 190 | 0x8c, 0x63, 0x18, 0xc6, 0x31, 0x70, 191 | 192 | /* U+0056 "V" */ 193 | 0x8c, 0x63, 0x18, 0xc6, 0x2a, 0x20, 194 | 195 | /* U+0057 "W" */ 196 | 0x83, 0x6, 0x4c, 0x99, 0x32, 0x64, 0xc9, 0x6c, 197 | 198 | /* U+0058 "X" */ 199 | 0x8c, 0x62, 0xa2, 0x2a, 0x31, 0x88, 200 | 201 | /* U+0059 "Y" */ 202 | 0x8c, 0x62, 0xa2, 0x10, 0x84, 0x20, 203 | 204 | /* U+005A "Z" */ 205 | 0xf8, 0x42, 0x22, 0x22, 0x10, 0xf8, 206 | 207 | /* U+005B "[" */ 208 | 0xf2, 0x49, 0x24, 0xe0, 209 | 210 | /* U+005C "\\" */ 211 | 0x92, 0x24, 0x89, 0x20, 212 | 213 | /* U+005D "]" */ 214 | 0xe4, 0x92, 0x49, 0xe0, 215 | 216 | /* U+005E "^" */ 217 | 0x22, 0xa2, 218 | 219 | /* U+005F "_" */ 220 | 0xff, 221 | 222 | /* U+0060 "`" */ 223 | 0x90, 224 | 225 | /* U+0061 "a" */ 226 | 0x74, 0x42, 0xf8, 0xc5, 0xe0, 227 | 228 | /* U+0062 "b" */ 229 | 0x84, 0x3d, 0x18, 0xc6, 0x31, 0xf0, 230 | 231 | /* U+0063 "c" */ 232 | 0x74, 0x61, 0x8, 0x45, 0xc0, 233 | 234 | /* U+0064 "d" */ 235 | 0x8, 0x5f, 0x18, 0xc6, 0x31, 0x78, 236 | 237 | /* U+0065 "e" */ 238 | 0x74, 0x63, 0xf8, 0x45, 0xc0, 239 | 240 | /* U+0066 "f" */ 241 | 0x34, 0x4f, 0x44, 0x44, 0x40, 242 | 243 | /* U+0067 "g" */ 244 | 0x7c, 0x63, 0x18, 0xbc, 0x31, 0x70, 245 | 246 | /* U+0068 "h" */ 247 | 0x84, 0x3d, 0x18, 0xc6, 0x31, 0x88, 248 | 249 | /* U+0069 "i" */ 250 | 0x20, 0x38, 0x42, 0x10, 0x84, 0xf8, 251 | 252 | /* U+006A "j" */ 253 | 0x8, 0xe, 0x10, 0x84, 0x21, 0xc, 0x5c, 254 | 255 | /* U+006B "k" */ 256 | 0x84, 0x23, 0x2a, 0x62, 0x92, 0x88, 257 | 258 | /* U+006C "l" */ 259 | 0xe1, 0x8, 0x42, 0x10, 0x84, 0xf8, 260 | 261 | /* U+006D "m" */ 262 | 0xed, 0x26, 0x4c, 0x99, 0x30, 0x60, 0x80, 263 | 264 | /* U+006E "n" */ 265 | 0xf4, 0x63, 0x18, 0xc6, 0x20, 266 | 267 | /* U+006F "o" */ 268 | 0x74, 0x63, 0x18, 0xc5, 0xc0, 269 | 270 | /* U+0070 "p" */ 271 | 0xf4, 0x63, 0x18, 0xc7, 0xd0, 0x80, 272 | 273 | /* U+0071 "q" */ 274 | 0x7c, 0x63, 0x18, 0xc5, 0xe1, 0x8, 275 | 276 | /* U+0072 "r" */ 277 | 0x9d, 0x31, 0x8, 0x42, 0x0, 278 | 279 | /* U+0073 "s" */ 280 | 0x74, 0x60, 0xe0, 0xc5, 0xc0, 281 | 282 | /* U+0074 "t" */ 283 | 0x4f, 0x44, 0x44, 0x43, 284 | 285 | /* U+0075 "u" */ 286 | 0x8c, 0x63, 0x18, 0xc5, 0xc0, 287 | 288 | /* U+0076 "v" */ 289 | 0x8c, 0x63, 0x18, 0xa8, 0x80, 290 | 291 | /* U+0077 "w" */ 292 | 0x83, 0x6, 0x4c, 0x99, 0x32, 0x5b, 0x0, 293 | 294 | /* U+0078 "x" */ 295 | 0x8c, 0x54, 0x45, 0x46, 0x20, 296 | 297 | /* U+0079 "y" */ 298 | 0x8c, 0x63, 0x18, 0xbc, 0x31, 0x70, 299 | 300 | /* U+007A "z" */ 301 | 0xf8, 0x44, 0x44, 0x43, 0xe0, 302 | 303 | /* U+007B "{" */ 304 | 0x34, 0x44, 0x84, 0x44, 0x30, 305 | 306 | /* U+007C "|" */ 307 | 0xff, 0x80, 308 | 309 | /* U+007D "}" */ 310 | 0xc2, 0x22, 0x12, 0x22, 0xc0, 311 | 312 | /* U+007E "~" */ 313 | 0x66, 0x60}; 314 | 315 | /*--------------------- 316 | * GLYPH DESCRIPTION 317 | *--------------------*/ 318 | 319 | static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { 320 | {.bitmap_index = 0, 321 | .adv_w = 0, 322 | .box_w = 0, 323 | .box_h = 0, 324 | .ofs_x = 0, 325 | .ofs_y = 0} /* id = 0 reserved */, 326 | {.bitmap_index = 0, .adv_w = 128, .box_w = 1, .box_h = 1, .ofs_x = 0, .ofs_y = 0}, 327 | {.bitmap_index = 1, .adv_w = 128, .box_w = 1, .box_h = 9, .ofs_x = 3, .ofs_y = 0}, 328 | {.bitmap_index = 3, .adv_w = 128, .box_w = 3, .box_h = 3, .ofs_x = 2, .ofs_y = 6}, 329 | {.bitmap_index = 5, .adv_w = 128, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 330 | {.bitmap_index = 12, .adv_w = 128, .box_w = 5, .box_h = 13, .ofs_x = 1, .ofs_y = -2}, 331 | {.bitmap_index = 21, .adv_w = 128, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, 332 | {.bitmap_index = 29, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 333 | {.bitmap_index = 35, .adv_w = 128, .box_w = 1, .box_h = 3, .ofs_x = 3, .ofs_y = 6}, 334 | {.bitmap_index = 36, .adv_w = 128, .box_w = 3, .box_h = 9, .ofs_x = 3, .ofs_y = 0}, 335 | {.bitmap_index = 40, .adv_w = 128, .box_w = 3, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 336 | {.bitmap_index = 44, .adv_w = 128, .box_w = 5, .box_h = 5, .ofs_x = 1, .ofs_y = 4}, 337 | {.bitmap_index = 48, .adv_w = 128, .box_w = 5, .box_h = 5, .ofs_x = 1, .ofs_y = 2}, 338 | {.bitmap_index = 52, .adv_w = 128, .box_w = 2, .box_h = 3, .ofs_x = 2, .ofs_y = -2}, 339 | {.bitmap_index = 53, .adv_w = 128, .box_w = 4, .box_h = 1, .ofs_x = 2, .ofs_y = 4}, 340 | {.bitmap_index = 54, .adv_w = 128, .box_w = 1, .box_h = 1, .ofs_x = 3, .ofs_y = 0}, 341 | {.bitmap_index = 55, .adv_w = 128, .box_w = 3, .box_h = 9, .ofs_x = 2, .ofs_y = 0}, 342 | {.bitmap_index = 59, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 343 | {.bitmap_index = 65, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 344 | {.bitmap_index = 71, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 345 | {.bitmap_index = 77, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 346 | {.bitmap_index = 83, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 347 | {.bitmap_index = 89, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 348 | {.bitmap_index = 95, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 349 | {.bitmap_index = 101, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 350 | {.bitmap_index = 107, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 351 | {.bitmap_index = 113, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 352 | {.bitmap_index = 119, .adv_w = 128, .box_w = 1, .box_h = 7, .ofs_x = 3, .ofs_y = 0}, 353 | {.bitmap_index = 120, .adv_w = 128, .box_w = 2, .box_h = 9, .ofs_x = 2, .ofs_y = -2}, 354 | {.bitmap_index = 123, .adv_w = 128, .box_w = 3, .box_h = 5, .ofs_x = 2, .ofs_y = 2}, 355 | {.bitmap_index = 125, .adv_w = 128, .box_w = 4, .box_h = 3, .ofs_x = 2, .ofs_y = 3}, 356 | {.bitmap_index = 127, .adv_w = 128, .box_w = 3, .box_h = 5, .ofs_x = 2, .ofs_y = 2}, 357 | {.bitmap_index = 129, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 358 | {.bitmap_index = 135, .adv_w = 128, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, 359 | {.bitmap_index = 143, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 360 | {.bitmap_index = 149, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 361 | {.bitmap_index = 155, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 362 | {.bitmap_index = 161, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 363 | {.bitmap_index = 167, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 364 | {.bitmap_index = 173, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 365 | {.bitmap_index = 179, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 366 | {.bitmap_index = 185, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 367 | {.bitmap_index = 191, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 368 | {.bitmap_index = 197, .adv_w = 128, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 369 | {.bitmap_index = 204, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 370 | {.bitmap_index = 210, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 371 | {.bitmap_index = 216, .adv_w = 128, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, 372 | {.bitmap_index = 224, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 373 | {.bitmap_index = 230, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 374 | {.bitmap_index = 236, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 375 | {.bitmap_index = 242, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 376 | {.bitmap_index = 248, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 377 | {.bitmap_index = 254, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 378 | {.bitmap_index = 260, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 379 | {.bitmap_index = 266, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 380 | {.bitmap_index = 272, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 381 | {.bitmap_index = 278, .adv_w = 128, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, 382 | {.bitmap_index = 286, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 383 | {.bitmap_index = 292, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 384 | {.bitmap_index = 298, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 385 | {.bitmap_index = 304, .adv_w = 128, .box_w = 3, .box_h = 9, .ofs_x = 3, .ofs_y = 0}, 386 | {.bitmap_index = 308, .adv_w = 128, .box_w = 3, .box_h = 9, .ofs_x = 2, .ofs_y = 0}, 387 | {.bitmap_index = 312, .adv_w = 128, .box_w = 3, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 388 | {.bitmap_index = 316, .adv_w = 128, .box_w = 5, .box_h = 3, .ofs_x = 1, .ofs_y = 6}, 389 | {.bitmap_index = 318, .adv_w = 128, .box_w = 8, .box_h = 1, .ofs_x = 0, .ofs_y = -2}, 390 | {.bitmap_index = 319, .adv_w = 128, .box_w = 2, .box_h = 2, .ofs_x = 2, .ofs_y = 7}, 391 | {.bitmap_index = 320, .adv_w = 128, .box_w = 5, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, 392 | {.bitmap_index = 325, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 393 | {.bitmap_index = 331, .adv_w = 128, .box_w = 5, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, 394 | {.bitmap_index = 336, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 395 | {.bitmap_index = 342, .adv_w = 128, .box_w = 5, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, 396 | {.bitmap_index = 347, .adv_w = 128, .box_w = 4, .box_h = 9, .ofs_x = 2, .ofs_y = 0}, 397 | {.bitmap_index = 352, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = -2}, 398 | {.bitmap_index = 358, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 399 | {.bitmap_index = 364, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 400 | {.bitmap_index = 370, .adv_w = 128, .box_w = 5, .box_h = 11, .ofs_x = 1, .ofs_y = -2}, 401 | {.bitmap_index = 377, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 402 | {.bitmap_index = 383, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 403 | {.bitmap_index = 389, .adv_w = 128, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, 404 | {.bitmap_index = 396, .adv_w = 128, .box_w = 5, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, 405 | {.bitmap_index = 401, .adv_w = 128, .box_w = 5, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, 406 | {.bitmap_index = 406, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = -2}, 407 | {.bitmap_index = 412, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = -2}, 408 | {.bitmap_index = 418, .adv_w = 128, .box_w = 5, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, 409 | {.bitmap_index = 423, .adv_w = 128, .box_w = 5, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, 410 | {.bitmap_index = 428, .adv_w = 128, .box_w = 4, .box_h = 8, .ofs_x = 2, .ofs_y = 0}, 411 | {.bitmap_index = 432, .adv_w = 128, .box_w = 5, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, 412 | {.bitmap_index = 437, .adv_w = 128, .box_w = 5, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, 413 | {.bitmap_index = 442, .adv_w = 128, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, 414 | {.bitmap_index = 449, .adv_w = 128, .box_w = 5, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, 415 | {.bitmap_index = 454, .adv_w = 128, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = -2}, 416 | {.bitmap_index = 460, .adv_w = 128, .box_w = 5, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, 417 | {.bitmap_index = 465, .adv_w = 128, .box_w = 4, .box_h = 9, .ofs_x = 2, .ofs_y = 0}, 418 | {.bitmap_index = 470, .adv_w = 128, .box_w = 1, .box_h = 9, .ofs_x = 3, .ofs_y = 0}, 419 | {.bitmap_index = 472, .adv_w = 128, .box_w = 4, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, 420 | {.bitmap_index = 477, .adv_w = 128, .box_w = 6, .box_h = 2, .ofs_x = 1, .ofs_y = 7}}; 421 | 422 | /*--------------------- 423 | * CHARACTER MAPPING 424 | *--------------------*/ 425 | 426 | /*Collect the unicode lists and glyph_id offsets*/ 427 | static const lv_font_fmt_txt_cmap_t cmaps[] = {{.range_start = 32, 428 | .range_length = 95, 429 | .glyph_id_start = 1, 430 | .unicode_list = NULL, 431 | .glyph_id_ofs_list = NULL, 432 | .list_length = 0, 433 | .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY}}; 434 | 435 | /*-------------------- 436 | * ALL CUSTOM DATA 437 | *--------------------*/ 438 | 439 | #if LVGL_VERSION_MAJOR == 8 440 | /*Store all the custom data of the font*/ 441 | static lv_font_fmt_txt_glyph_cache_t cache; 442 | #endif 443 | 444 | #if LVGL_VERSION_MAJOR >= 8 445 | static const lv_font_fmt_txt_dsc_t font_dsc = { 446 | #else 447 | static lv_font_fmt_txt_dsc_t font_dsc = { 448 | #endif 449 | .glyph_bitmap = glyph_bitmap, 450 | .glyph_dsc = glyph_dsc, 451 | .cmaps = cmaps, 452 | .kern_dsc = NULL, 453 | .kern_scale = 0, 454 | .cmap_num = 1, 455 | .bpp = 1, 456 | .kern_classes = 0, 457 | .bitmap_format = 0, 458 | #if LVGL_VERSION_MAJOR == 8 459 | .cache = &cache 460 | #endif 461 | }; 462 | 463 | /*----------------- 464 | * PUBLIC FONT 465 | *----------------*/ 466 | 467 | /*Initialize a public general font descriptor*/ 468 | #if LVGL_VERSION_MAJOR >= 8 469 | const lv_font_t pixel_operator_mono = { 470 | #else 471 | lv_font_t pixel_operator_mono = { 472 | #endif 473 | .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ 474 | .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ 475 | .line_height = 13, /*The maximum line height required by the font*/ 476 | .base_line = 2, /*Baseline measured from the bottom of the line*/ 477 | #if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) 478 | .subpx = LV_FONT_SUBPX_NONE, 479 | #endif 480 | #if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 481 | .underline_position = -3, 482 | .underline_thickness = 1, 483 | #endif 484 | .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ 485 | #if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 486 | .fallback = NULL, 487 | #endif 488 | .user_data = NULL, 489 | }; 490 | 491 | #endif /*#if PIXEL_OPERATOR_MONO*/ 492 | --------------------------------------------------------------------------------