From 0fa37422a7483e9fb3b5db5be281cec0ddb4b962 Mon Sep 17 00:00:00 2001 From: snoyer Date: Tue, 9 Apr 2024 12:31:48 +0400 Subject: [PATCH] track and display individual profile status --- app/boards/shields/nice_view/README.md | 14 +++++++- app/boards/shields/nice_view/widgets/status.c | 33 +++++++++++++++---- app/boards/shields/nice_view/widgets/util.h | 6 +++- app/include/zmk/ble.h | 5 ++- app/src/ble.c | 24 ++++++++++++-- 5 files changed, 70 insertions(+), 12 deletions(-) diff --git a/app/boards/shields/nice_view/README.md b/app/boards/shields/nice_view/README.md index 00abfbfa..0d0c04db 100644 --- a/app/boards/shields/nice_view/README.md +++ b/app/boards/shields/nice_view/README.md @@ -4,9 +4,21 @@ The nice!view is a low-power, high refresh rate display meant to replace I2C OLE This shield requires that an `&nice_view_spi` labeled SPI bus is provided with _at least_ MOSI, SCK, and CS pins defined. +## Custom widget + +The nice!view shield includes a custom vertical widget. + +Profile indicators show the status of the first five BLE profiles using numbers from 1 to 5. +The number corresponding to the currently selected profile is drawn in a filled disk +and the circle outline around each profile number correspond to the following states: + +- solid outline: connected +- dashed outline: not connected +- no outline: not bound + ## Disable custom widget -The nice!view shield includes a custom vertical widget. To use the built-in ZMK one, add the following item to your `.conf` file: +To use the built-in ZMK widget instead of the custom nice!view one, add the following item to your `.conf` file: ``` CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN=y diff --git a/app/boards/shields/nice_view/widgets/status.c b/app/boards/shields/nice_view/widgets/status.c index 061b7127..5afb98fb 100644 --- a/app/boards/shields/nice_view/widgets/status.c +++ b/app/boards/shields/nice_view/widgets/status.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 The ZMK Contributors + * Copyright (c) 2024 The ZMK Contributors * SPDX-License-Identifier: MIT * */ @@ -33,6 +33,8 @@ struct output_status_state { int active_profile_index; bool active_profile_connected; bool active_profile_bonded; + bool profiles_connected[NICEVIEW_PROFILE_COUNT]; + bool profiles_bonded[NICEVIEW_PROFILE_COUNT]; }; struct layer_status_state { @@ -142,15 +144,24 @@ static void draw_middle(lv_obj_t *widget, lv_color_t cbuf[], const struct status lv_canvas_draw_rect(canvas, 0, 0, CANVAS_SIZE, CANVAS_SIZE, &rect_black_dsc); // Draw circles - int circle_offsets[5][2] = { + int circle_offsets[NICEVIEW_PROFILE_COUNT][2] = { {13, 13}, {55, 13}, {34, 34}, {13, 55}, {55, 55}, }; - for (int i = 0; i < 5; i++) { + for (int i = 0; i < NICEVIEW_PROFILE_COUNT; i++) { bool selected = i == state->active_profile_index; - lv_canvas_draw_arc(canvas, circle_offsets[i][0], circle_offsets[i][1], 13, 0, 360, - &arc_dsc); + if (state->profiles_connected[i]) { + lv_canvas_draw_arc(canvas, circle_offsets[i][0], circle_offsets[i][1], 13, 0, 360, + &arc_dsc); + } else if (state->profiles_bonded[i]) { + const int segments = 8; + const int gap = 20; + for (int j = 0; j < segments; ++j) + lv_canvas_draw_arc(canvas, circle_offsets[i][0], circle_offsets[i][1], 13, + 360. / segments * j + gap / 2.0, + 360. / segments * (j + 1) - gap / 2.0, &arc_dsc); + } if (selected) { lv_canvas_draw_arc(canvas, circle_offsets[i][0], circle_offsets[i][1], 9, 0, 359, @@ -234,6 +245,10 @@ static void set_output_status(struct zmk_widget_status *widget, widget->state.active_profile_index = state->active_profile_index; widget->state.active_profile_connected = state->active_profile_connected; widget->state.active_profile_bonded = state->active_profile_bonded; + for (int i = 0; i < NICEVIEW_PROFILE_COUNT; ++i) { + widget->state.profiles_connected[i] = state->profiles_connected[i]; + widget->state.profiles_bonded[i] = state->profiles_bonded[i]; + } draw_top(widget->obj, widget->cbuf, &widget->state); draw_middle(widget->obj, widget->cbuf2, &widget->state); @@ -245,12 +260,18 @@ static void output_status_update_cb(struct output_status_state state) { } static struct output_status_state output_status_get_state(const zmk_event_t *_eh) { - return (struct output_status_state){ + struct output_status_state state = { .selected_endpoint = zmk_endpoints_selected(), .active_profile_index = zmk_ble_active_profile_index(), .active_profile_connected = zmk_ble_active_profile_is_connected(), .active_profile_bonded = !zmk_ble_active_profile_is_open(), }; + for (int i = 0; i < MIN(NICEVIEW_PROFILE_COUNT, ZMK_BLE_PROFILE_COUNT); ++i) { + const bt_addr_le_t *addr = zmk_ble_profile_address(i); + state.profiles_connected[i] = zmk_ble_profile_is_connected(addr); + state.profiles_bonded[i] = !zmk_ble_profile_is_open(addr); + } + return state; } ZMK_DISPLAY_WIDGET_LISTENER(widget_output_status, struct output_status_state, diff --git a/app/boards/shields/nice_view/widgets/util.h b/app/boards/shields/nice_view/widgets/util.h index fbcb616f..b2a773e5 100644 --- a/app/boards/shields/nice_view/widgets/util.h +++ b/app/boards/shields/nice_view/widgets/util.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 The ZMK Contributors + * Copyright (c) 2024 The ZMK Contributors * SPDX-License-Identifier: MIT * */ @@ -8,6 +8,8 @@ #include #include +#define NICEVIEW_PROFILE_COUNT 5 + #define CANVAS_SIZE 68 #define LVGL_BACKGROUND \ @@ -23,6 +25,8 @@ struct status_state { int active_profile_index; bool active_profile_connected; bool active_profile_bonded; + bool profiles_connected[NICEVIEW_PROFILE_COUNT]; + bool profiles_bonded[NICEVIEW_PROFILE_COUNT]; uint8_t layer_index; const char *layer_label; uint8_t wpm[10]; diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h index 773323c1..911f0a0e 100644 --- a/app/include/zmk/ble.h +++ b/app/include/zmk/ble.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The ZMK Contributors + * Copyright (c) 2024 The ZMK Contributors * * SPDX-License-Identifier: MIT */ @@ -29,8 +29,11 @@ int zmk_ble_prof_disconnect(uint8_t index); int zmk_ble_active_profile_index(void); int zmk_ble_profile_index(const bt_addr_le_t *addr); +bt_addr_le_t *zmk_ble_profile_address(uint8_t index); bt_addr_le_t *zmk_ble_active_profile_addr(void); +bool zmk_ble_profile_is_open(const bt_addr_le_t *addr); bool zmk_ble_active_profile_is_open(void); +bool zmk_ble_profile_is_connected(const bt_addr_le_t *addr); bool zmk_ble_active_profile_is_connected(void); char *zmk_ble_active_profile_name(void); diff --git a/app/src/ble.c b/app/src/ble.c index 7e1ae7d4..7d94cc00 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The ZMK Contributors + * Copyright (c) 2024 The ZMK Contributors * * SPDX-License-Identifier: MIT */ @@ -94,7 +94,11 @@ static void raise_profile_changed_event_callback(struct k_work *work) { K_WORK_DEFINE(raise_profile_changed_event_work, raise_profile_changed_event_callback); bool zmk_ble_active_profile_is_open(void) { - return !bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY); + return zmk_ble_profile_is_open(zmk_ble_active_profile_addr()); +} + +bool zmk_ble_profile_is_open(const bt_addr_le_t *addr) { + return !bt_addr_le_cmp(addr, BT_ADDR_LE_ANY); } void set_profile_address(uint8_t index, const bt_addr_le_t *addr) { @@ -113,9 +117,12 @@ void set_profile_address(uint8_t index, const bt_addr_le_t *addr) { } bool zmk_ble_active_profile_is_connected(void) { + return zmk_ble_profile_is_connected(zmk_ble_active_profile_addr()); +} + +bool zmk_ble_profile_is_connected(const bt_addr_le_t *addr) { struct bt_conn *conn; struct bt_conn_info info; - bt_addr_le_t *addr = zmk_ble_active_profile_addr(); if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) { return false; } else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) { @@ -248,6 +255,13 @@ int zmk_ble_profile_index(const bt_addr_le_t *addr) { return -ENODEV; } +bt_addr_le_t *zmk_ble_profile_address(uint8_t index) { + if (index >= ZMK_BLE_PROFILE_COUNT) { + return (bt_addr_le_t *)(BT_ADDR_LE_NONE); + } + return &profiles[index].peer; +} + #if IS_ENABLED(CONFIG_SETTINGS) static void ble_save_profile_work(struct k_work *work) { settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile)); @@ -312,6 +326,10 @@ int zmk_ble_prof_disconnect(uint8_t index) { result = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); LOG_DBG("Disconnected from profile %d: %d", index, result); + raise_profile_changed_event(); + // `raise_profile_changed_event` actually does `raise_zmk_ble_active_profile_changed` + // should `profile_changed` and `active_profile_changed` be two separate events? + bt_conn_unref(conn); return result; }