Skip to content

Commit

Permalink
Initial commit nice_oled
Browse files Browse the repository at this point in the history
  • Loading branch information
mctechnology17 committed Nov 27, 2024
1 parent 30dfe0f commit 2a90780
Show file tree
Hide file tree
Showing 51 changed files with 9,287 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
on: [push, pull_request, workflow_dispatch]

jobs:
build:
uses: zmkfirmware/zmk/.github/workflows/build-user-config.yml@main
90 changes: 90 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# nice_oled

![Banner](./assets/banner.JPG)

nice_oled vertical widgets for oled screens in 128x32 portrait orientation with
zmk software.

Inspired/forked by the work of @M165437 with his [nice-view-gem](https://github.com/M165437/nice-view-gem).
All credits to him for the original design and implementation.

Shields supported:
- nice_oled

The nice_oled is a ZMK module:
- **Vertical layout**
- **Compact**
- **Prevents your neck from hurting when looking at the keyboard**
- **Easy to read in the dark**

## Gallery

![Animation Preview](./assets/animation.gif)
![Preview #2](./assets/preview1.JPG)
![Preview #3](./assets/preview2.JPG)

## Installation

Only small changes are needed to your keyboard configuration's build setup. Then, you'll need to rebuild and flash your keyboard firmware.

1. In the `config/west.yml` file, add a new remote and its related project.

```diff
manifest:
remotes:
- name: zmkfirmware
url-base: https://github.com/zmkfirmware
+ - name: mctechnology17
+ url-base: https://github.com/mctechnology17
projects:
- name: zmk
remote: zmkfirmware
revision: main
import: app/west.yml
+ - name: zmk-nice-oled
+ remote: mctechnology17
+ revision: main
self:
path: config
```

2. In the `build.yaml` file, add the `nice_oled` shield.

```diff
---
include:
- board: nice_nano_v2
- shield: corne_left
+ shield: corne_left nice_oled
- board: nice_nano_v2
- shield: corne_right
+ shield: corne_right nice_oled
```

3. Build the firmware, flash it to your keyboard, and enjoy!

# Configuration
> [!IMPORTANT]
> Make sure to enable the custom status screen in your ZMK configuration:
Make sure to enable the custom status screen in your ZMK configuration:

```conf
CONFIG_ZMK_DISPLAY=y
CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y
```

## Configuration

Modify the behavior of this shield by adjusting these options in your personal configuration files. For a more detailed explanation, refer to [Configuration in the ZMK documentation](https://zmk.dev/docs/config).

| Option | Type | Description | Default |
| ------------------------------------------ | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `CONFIG_NICE_OLED_GEM_WPM_FIXED_RANGE` | bool | This shield uses a fixed range for the chart and gauge deflection. If you set this option to `n`, it will switch to a dynamic range, like the default nice!view shield, which dynamically adjusts based on the last 10 WPM values provided by ZMK. | y |
| `CONFIG_NICE_OLED_GEM_WPM_FIXED_RANGE_MAX` | int | You can adjust the maximum value of the fixed range to align with your current goal. | 100 |
| `CONFIG_NICE_OLED_GEM_ANIMATION` | bool | If you find the animation distracting (or want to save on battery usage), you can turn it off by setting this option to `n`. It will instead pick a random frame of the animation every time you restart your keyboard. | y |
| `CONFIG_NICE_OLED_GEM_ANIMATION_MS` | int | Alternatively, you can slow down the animation. A high value, such as 96000, slows the animation considerably, showing the next frame every couple of seconds. The animation consists of 16 frames, and the default value of 960 milliseconds plays it at 60 fps. | 960 |

## Inspiration
- [nice-view-gem](https://github.com/M165437/nice-view-gem) by @M165437
- [nice-view-elemental](https://github.com/kevinpastor/nice-view-elemental) by @kevinpastor
Binary file added assets/animation.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/banner.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/preview1.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/preview2.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added boards/shields/.gitkeep
Empty file.
23 changes: 23 additions & 0 deletions boards/shields/nice_oled/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
if(CONFIG_ZMK_DISPLAY AND CONFIG_NICE_VIEW_WIDGET_STATUS)
zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include)
zephyr_library_sources(custom_status_screen.c)
zephyr_library_sources(assets/images.c)
zephyr_library_sources(widgets/battery.c)
zephyr_library_sources(widgets/output.c)
zephyr_library_sources(widgets/util.c)

if(NOT CONFIG_ZMK_SPLIT OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
zephyr_library_sources(widgets/layer.c)
zephyr_library_sources(widgets/profile.c)
zephyr_library_sources(widgets/screen.c)
zephyr_library_sources(assets/bongo_cat_images.c)
zephyr_library_sources(widgets/wpm.c)
else()
zephyr_library_sources(assets/vim.c)
zephyr_library_sources(assets/vip_marcos.c)
zephyr_library_sources(assets/crystal.c)
zephyr_library_sources(assets/pokemon.c)
zephyr_library_sources(widgets/animation.c)
zephyr_library_sources(widgets/screen_peripheral.c)
endif()
endif()
81 changes: 81 additions & 0 deletions boards/shields/nice_oled/Kconfig.defconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
if SHIELD_NICE_OLED

config LV_Z_VDB_SIZE
default 64
# default 100

config LV_DPI_DEF
default 148
# default 161

config LV_Z_BITS_PER_PIXEL
default 1

choice LV_COLOR_DEPTH
default LV_COLOR_DEPTH_1
endchoice

choice ZMK_DISPLAY_WORK_QUEUE
default ZMK_DISPLAY_WORK_QUEUE_DEDICATED
endchoice

choice ZMK_DISPLAY_STATUS_SCREEN
default ZMK_DISPLAY_STATUS_SCREEN_CUSTOM
endchoice

config LV_Z_MEM_POOL_SIZE
default 4096 if ZMK_DISPLAY_STATUS_SCREEN_CUSTOM

config ZMK_DISPLAY_STATUS_SCREEN_CUSTOM
imply NICE_VIEW_WIDGET_STATUS

config NICE_OLED_GEM_ANIMATION_WPM_FIXED_RANGE
bool "Enable fixed range for WPM gauge/chart"
default y

config NICE_OLED_GEM_ANIMATION_WPM_FIXED_RANGE_MAX
int "Fixed range maximum for WPM gauge/chart"
default 100

config NICE_OLED_GEM_ANIMATION
bool "Enable animation on peripheral"
default y

config NICE_OLED_GEM_ANIMATION_MS
int "Animation length in milliseconds"
default 960

config NICE_OLED_POKEMON_ANIMATION
bool "Enable animation on peripheral"
default n

config NICE_OLED_POKEMON_ANIMATION_MS
int "Animation length in milliseconds"
default 4800

config NICE_OLED_VIM
bool "Enable static vim on peripheral"
default n

config NICE_OLED_VIP_MARCOS
bool "Enable static vim_marcos on peripheral"
default n

config NICE_VIEW_WIDGET_STATUS
select LV_USE_LABEL
select LV_USE_IMG
select LV_USE_CANVAS
select LV_USE_ANIMIMG
select LV_USE_ANIMATION

config NICE_VIEW_WIDGET_INVERTED
bool "Invert display colors"

if !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL

config NICE_VIEW_WIDGET_STATUS
select ZMK_WPM

endif # !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL

endif # SHIELD_NICE_OLED
2 changes: 2 additions & 0 deletions boards/shields/nice_oled/Kconfig.shield
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
config SHIELD_NICE_OLED
def_bool $(shields_list_contains,nice_oled)
Binary file not shown.
148 changes: 148 additions & 0 deletions boards/shields/nice_oled/assets/bongo_cat.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* Copyright (c) 2024 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#include <zephyr/kernel.h>
#include <zephyr/bluetooth/services/bas.h>

#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

#include <zmk/display.h>
#include <zmk/event_manager.h>
#include <zmk/events/wpm_state_changed.h>
#include <zmk/wpm.h>

#include "bongo_cat.h"

#define SRC(array) (const void **)array, sizeof(array) / sizeof(lv_img_dsc_t *)

static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets);

LV_IMG_DECLARE(bongo_cat_none);
LV_IMG_DECLARE(bongo_cat_left1);
LV_IMG_DECLARE(bongo_cat_left2);
LV_IMG_DECLARE(bongo_cat_right1);
LV_IMG_DECLARE(bongo_cat_right2);
LV_IMG_DECLARE(bongo_cat_both1);
LV_IMG_DECLARE(bongo_cat_both1_open);
LV_IMG_DECLARE(bongo_cat_both2);

#define ANIMATION_SPEED_IDLE 10000
const lv_img_dsc_t *idle_imgs[] = {
&bongo_cat_both1_open,
&bongo_cat_both1_open,
&bongo_cat_both1_open,
&bongo_cat_both1,
};

#define ANIMATION_SPEED_SLOW 2000
const lv_img_dsc_t *slow_imgs[] = {
&bongo_cat_left1,
&bongo_cat_both1,
&bongo_cat_both1,
&bongo_cat_right1,
&bongo_cat_both1,
&bongo_cat_both1,
&bongo_cat_left1,
&bongo_cat_both1,
&bongo_cat_both1,
};

#define ANIMATION_SPEED_MID 500
const lv_img_dsc_t *mid_imgs[] = {
&bongo_cat_left2,
&bongo_cat_left1,
&bongo_cat_none,
&bongo_cat_right2,
&bongo_cat_right1,
&bongo_cat_none,
};

#define ANIMATION_SPEED_FAST 200
const lv_img_dsc_t *fast_imgs[] = {
&bongo_cat_both2,
&bongo_cat_both1,
&bongo_cat_none,
&bongo_cat_none,
};

struct bongo_cat_wpm_status_state {
uint8_t wpm;
};

enum anim_state {
anim_state_none,
anim_state_idle,
anim_state_slow,
anim_state_mid,
anim_state_fast
} current_anim_state;

static void set_animation(lv_obj_t *animing, struct bongo_cat_wpm_status_state state) {
if (state.wpm < 5) {
if (current_anim_state != anim_state_idle) {
lv_animimg_set_src(animing, SRC(idle_imgs));
lv_animimg_set_duration(animing, ANIMATION_SPEED_IDLE);
lv_animimg_set_repeat_count(animing, LV_ANIM_REPEAT_INFINITE);
lv_animimg_start(animing);
current_anim_state = anim_state_idle;
}
} else if (state.wpm < 30) {
if (current_anim_state != anim_state_slow) {
lv_animimg_set_src(animing, SRC(slow_imgs));
lv_animimg_set_duration(animing, ANIMATION_SPEED_SLOW);
lv_animimg_set_repeat_count(animing, LV_ANIM_REPEAT_INFINITE);
lv_animimg_start(animing);
current_anim_state = anim_state_slow;
}
} else if (state.wpm < 70) {
if (current_anim_state != anim_state_mid) {
lv_animimg_set_src(animing, SRC(mid_imgs));
lv_animimg_set_duration(animing, ANIMATION_SPEED_MID);
lv_animimg_set_repeat_count(animing, LV_ANIM_REPEAT_INFINITE);
lv_animimg_start(animing);
current_anim_state = anim_state_mid;
}
} else {
if (current_anim_state != anim_state_fast) {
lv_animimg_set_src(animing, SRC(fast_imgs));
lv_animimg_set_duration(animing, ANIMATION_SPEED_FAST);
lv_animimg_set_repeat_count(animing, LV_ANIM_REPEAT_INFINITE);
lv_animimg_start(animing);
current_anim_state = anim_state_fast;
}
}
}

struct bongo_cat_wpm_status_state bongo_cat_wpm_status_get_state(const zmk_event_t *eh) {
struct zmk_wpm_state_changed *ev = as_zmk_wpm_state_changed(eh);
return (struct bongo_cat_wpm_status_state) { .wpm = ev->state };
};

void bongo_cat_wpm_status_update_cb(struct bongo_cat_wpm_status_state state) {
struct zmk_widget_bongo_cat *widget;
SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_animation(widget->obj, state); }
}

ZMK_DISPLAY_WIDGET_LISTENER(widget_bongo_cat, struct bongo_cat_wpm_status_state,
bongo_cat_wpm_status_update_cb, bongo_cat_wpm_status_get_state)

ZMK_SUBSCRIPTION(widget_bongo_cat, zmk_wpm_state_changed);

int zmk_widget_bongo_cat_init(struct zmk_widget_bongo_cat *widget, lv_obj_t *parent) {
widget->obj = lv_animimg_create(parent);
lv_obj_center(widget->obj);

sys_slist_append(&widgets, &widget->node);

widget_bongo_cat_init();

return 0;
}

lv_obj_t *zmk_widget_bongo_cat_obj(struct zmk_widget_bongo_cat *widget) {
return widget->obj;
}
Loading

0 comments on commit 2a90780

Please sign in to comment.