summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'app/src')
-rw-r--r--app/src/behaviors/behavior_bt.c2
-rw-r--r--app/src/behaviors/behavior_ext_power.c57
-rw-r--r--app/src/behaviors/behavior_key_press.c2
-rw-r--r--app/src/ble.c146
-rw-r--r--app/src/events/ble_active_profile_changed.c2
-rw-r--r--app/src/hog.c12
-rw-r--r--app/src/rgb_underglow.c95
-rw-r--r--app/src/settings.c8
8 files changed, 268 insertions, 56 deletions
diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c
index 922c157..066c437 100644
--- a/app/src/behaviors/behavior_bt.c
+++ b/app/src/behaviors/behavior_bt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
+ * Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
diff --git a/app/src/behaviors/behavior_ext_power.c b/app/src/behaviors/behavior_ext_power.c
new file mode 100644
index 0000000..825f983
--- /dev/null
+++ b/app/src/behaviors/behavior_ext_power.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#define DT_DRV_COMPAT zmk_behavior_ext_power
+
+#include <device.h>
+#include <devicetree.h>
+#include <drivers/behavior.h>
+#include <drivers/ext_power.h>
+
+#include <dt-bindings/zmk/ext_power.h>
+
+#include <logging/log.h>
+LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+
+static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
+ struct zmk_behavior_binding_event event) {
+ struct device *ext_power = device_get_binding("EXT_POWER");
+ if (ext_power == NULL) {
+ LOG_ERR("Unable to retrieve ext_power device: %d", binding->param1);
+ return -EIO;
+ }
+
+ switch (binding->param1) {
+ case EXT_POWER_OFF_CMD:
+ return ext_power_disable(ext_power);
+ case EXT_POWER_ON_CMD:
+ return ext_power_enable(ext_power);
+ case EXT_POWER_TOGGLE_CMD:
+ if (ext_power_get(ext_power) > 0)
+ return ext_power_disable(ext_power);
+ else
+ return ext_power_enable(ext_power);
+ default:
+ LOG_ERR("Unknown ext_power command: %d", binding->param1);
+ }
+
+ return -ENOTSUP;
+}
+
+static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
+ struct zmk_behavior_binding_event event) {
+ return 0;
+}
+
+static int behavior_ext_power_init(struct device *dev) { return 0; };
+
+static const struct behavior_driver_api behavior_ext_power_driver_api = {
+ .binding_pressed = on_keymap_binding_pressed,
+ .binding_released = on_keymap_binding_released,
+};
+
+DEVICE_AND_API_INIT(behavior_ext_power, DT_INST_LABEL(0), behavior_ext_power_init, NULL, NULL,
+ APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, &behavior_ext_power_driver_api);
diff --git a/app/src/behaviors/behavior_key_press.c b/app/src/behaviors/behavior_key_press.c
index d691e9f..923b098 100644
--- a/app/src/behaviors/behavior_key_press.c
+++ b/app/src/behaviors/behavior_key_press.c
@@ -54,4 +54,4 @@ static const struct behavior_driver_api behavior_key_press_driver_api = {
&behavior_key_press_data_##n, &behavior_key_press_config_##n, APPLICATION, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_press_driver_api);
-DT_INST_FOREACH_STATUS_OKAY(KP_INST) \ No newline at end of file
+DT_INST_FOREACH_STATUS_OKAY(KP_INST)
diff --git a/app/src/ble.c b/app/src/ble.c
index 49e2b3b..9090582 100644
--- a/app/src/ble.c
+++ b/app/src/ble.c
@@ -45,10 +45,29 @@ static u8_t passkey_digit = 0;
#define PROFILE_COUNT CONFIG_BT_MAX_PAIRED
#endif
+enum advertising_type {
+ ZMK_ADV_NONE,
+ ZMK_ADV_DIR,
+ ZMK_ADV_CONN,
+} advertising_status;
+
+#define CURR_ADV(adv) (adv << 4)
+
+#define ZMK_ADV_CONN_NAME \
+ BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, BT_GAP_ADV_FAST_INT_MIN_2, \
+ BT_GAP_ADV_FAST_INT_MAX_2, NULL)
+
static struct zmk_ble_profile profiles[PROFILE_COUNT];
static u8_t active_profile;
+#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
+#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
+
static const struct bt_data zmk_ble_ad[] = {
+#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
+ BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
+ BT_DATA_BYTES(BT_DATA_GAP_APPEARANCE, 0xC1, 0x03),
+#endif
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID16_SOME,
#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
@@ -92,29 +111,101 @@ void set_profile_address(u8_t index, const bt_addr_le_t *addr) {
raise_profile_changed_event();
}
-int zmk_ble_adv_pause() {
- int err = bt_le_adv_stop();
- if (err) {
- LOG_ERR("Failed to stop advertising (err %d)", err);
- return err;
+bool active_profile_is_connected() {
+ struct bt_conn *conn;
+ 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) {
+ return false;
}
- return 0;
-};
+ bt_conn_unref(conn);
-int zmk_ble_adv_resume() {
- LOG_DBG("active_profile %d, directed? %s", active_profile,
- active_profile_is_open() ? "no" : "yes");
+ return true;
+}
- int err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0);
- if (err) {
- LOG_ERR("Advertising failed to start (err %d)", err);
- return err;
+#define CHECKED_ADV_STOP() \
+ err = bt_le_adv_stop(); \
+ advertising_status = ZMK_ADV_NONE; \
+ if (err) { \
+ LOG_ERR("Failed to stop advertising (err %d)", err); \
+ return err; \
+ }
+
+#define CHECKED_DIR_ADV() \
+ addr = zmk_ble_active_profile_addr(); \
+ conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); \
+ if (conn != NULL) { /* TODO: Check status of connection */ \
+ LOG_DBG("Skipping advertising, profile host is already connected"); \
+ bt_conn_unref(conn); \
+ return 0; \
+ } \
+ err = bt_le_adv_start(BT_LE_ADV_CONN_DIR_LOW_DUTY(addr), zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), \
+ NULL, 0); \
+ if (err) { \
+ LOG_ERR("Advertising failed to start (err %d)", err); \
+ return err; \
+ } \
+ advertising_status = ZMK_ADV_DIR;
+
+#define CHECKED_OPEN_ADV() \
+ err = bt_le_adv_start(ZMK_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); \
+ if (err) { \
+ LOG_ERR("Advertising failed to start (err %d)", err); \
+ return err; \
+ } \
+ advertising_status = ZMK_ADV_CONN;
+
+int update_advertising() {
+ int err = 0;
+ bt_addr_le_t *addr;
+ struct bt_conn *conn;
+ enum advertising_type desired_adv = ZMK_ADV_NONE;
+
+ if (active_profile_is_open() || !active_profile_is_connected()) {
+ desired_adv = ZMK_ADV_CONN;
+ } else if (!active_profile_is_connected()) {
+ desired_adv = ZMK_ADV_CONN;
+ // Need to fix directed advertising for privacy centrals. See
+ // https://github.com/zephyrproject-rtos/zephyr/pull/14984 char
+ // addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(zmk_ble_active_profile_addr(), addr_str,
+ // sizeof(addr_str));
+
+ // LOG_DBG("Directed advertising to %s", log_strdup(addr_str));
+ // desired_adv = ZMK_ADV_DIR;
+ }
+ LOG_DBG("advertising from %d to %d", advertising_status, desired_adv);
+
+ switch (desired_adv + CURR_ADV(advertising_status)) {
+ case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_DIR):
+ case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_CONN):
+ CHECKED_ADV_STOP();
+ break;
+ case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_DIR):
+ case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_CONN):
+ CHECKED_ADV_STOP();
+ CHECKED_DIR_ADV();
+ break;
+ case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_NONE):
+ CHECKED_DIR_ADV();
+ break;
+ case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_DIR):
+ CHECKED_ADV_STOP();
+ CHECKED_OPEN_ADV();
+ break;
+ case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_NONE):
+ CHECKED_OPEN_ADV();
+ break;
}
return 0;
};
+static void update_advertising_callback(struct k_work *work) { update_advertising(); }
+
+K_WORK_DEFINE(update_advertising_work, update_advertising_callback);
+
int zmk_ble_clear_bonds() {
LOG_DBG("");
@@ -124,6 +215,8 @@ int zmk_ble_clear_bonds() {
set_profile_address(active_profile, BT_ADDR_LE_ANY);
}
+ update_advertising();
+
return 0;
};
@@ -134,9 +227,13 @@ int zmk_ble_prof_select(u8_t index) {
}
active_profile = index;
- return settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile));
+ settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile));
+
+ update_advertising();
raise_profile_changed_event();
+
+ return 0;
};
int zmk_ble_prof_next() {
@@ -234,8 +331,11 @@ static void connected(struct bt_conn *conn, u8_t err) {
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+ advertising_status = ZMK_ADV_NONE;
+
if (err) {
LOG_WRN("Failed to connect to %s (%u)", log_strdup(addr), err);
+ update_advertising();
return;
}
@@ -250,6 +350,8 @@ static void connected(struct bt_conn *conn, u8_t err) {
if (bt_conn_set_security(conn, BT_SECURITY_L2)) {
LOG_ERR("Failed to set security");
}
+
+ update_advertising();
}
static void disconnected(struct bt_conn *conn, u8_t reason) {
@@ -259,14 +361,9 @@ static void disconnected(struct bt_conn *conn, u8_t reason) {
LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr), reason);
-#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
- // if (bt_addr_le_cmp(&peripheral_addr, BT_ADDR_LE_ANY) && bt_addr_le_cmp(&peripheral_addr,
- // bt_conn_get_dst(conn))) {
- // zmk_ble_adv_resume();
- // }
-#else
- // zmk_ble_adv_resume();
-#endif
+ // We need to do this in a work callback, otherwise the advertising update will still see the
+ // connection for a profile as active, and not start advertising yet.
+ k_work_submit(&update_advertising_work);
}
static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) {
@@ -361,6 +458,7 @@ static void auth_pairing_complete(struct bt_conn *conn, bool bonded) {
#endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */
set_profile_address(active_profile, dst);
+ update_advertising();
};
static struct bt_conn_auth_cb zmk_ble_auth_cb_display = {
@@ -383,7 +481,7 @@ static void zmk_ble_ready(int err) {
return;
}
- zmk_ble_adv_resume();
+ update_advertising();
}
static int zmk_ble_init(struct device *_arg) {
diff --git a/app/src/events/ble_active_profile_changed.c b/app/src/events/ble_active_profile_changed.c
index a270a14..06988e2 100644
--- a/app/src/events/ble_active_profile_changed.c
+++ b/app/src/events/ble_active_profile_changed.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
+ * Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
diff --git a/app/src/hog.c b/app/src/hog.c
index 11349ac..bcd652d 100644
--- a/app/src/hog.c
+++ b/app/src/hog.c
@@ -164,8 +164,10 @@ int zmk_hog_send_keypad_report(struct zmk_hid_keypad_report_body *report) {
LOG_DBG("Sending to NULL? %s", conn == NULL ? "yes" : "no");
- return bt_gatt_notify(conn, &hog_svc.attrs[5], report,
- sizeof(struct zmk_hid_keypad_report_body));
+ int err =
+ bt_gatt_notify(conn, &hog_svc.attrs[5], report, sizeof(struct zmk_hid_keypad_report_body));
+ bt_conn_unref(conn);
+ return err;
};
int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) {
@@ -174,6 +176,8 @@ int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) {
return -ENOTCONN;
}
- return bt_gatt_notify(conn, &hog_svc.attrs[10], report,
- sizeof(struct zmk_hid_consumer_report_body));
+ int err = bt_gatt_notify(conn, &hog_svc.attrs[10], report,
+ sizeof(struct zmk_hid_consumer_report_body));
+ bt_conn_unref(conn);
+ return err;
};
diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c
index 13912e3..b371c94 100644
--- a/app/src/rgb_underglow.c
+++ b/app/src/rgb_underglow.c
@@ -7,6 +7,7 @@
#include <device.h>
#include <init.h>
#include <kernel.h>
+#include <settings/settings.h>
#include <math.h>
#include <stdlib.h>
@@ -14,7 +15,6 @@
#include <logging/log.h>
#include <drivers/led_strip.h>
-#include <device.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@@ -45,12 +45,36 @@ struct rgb_underglow_state {
bool on;
};
-struct rgb_underglow_state state;
-
struct device *led_strip;
struct led_rgb pixels[STRIP_NUM_PIXELS];
+struct rgb_underglow_state state;
+
+#if IS_ENABLED(CONFIG_SETTINGS)
+static int rgb_settings_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) {
+ const char *next;
+ int rc;
+
+ if (settings_name_steq(name, "state", &next) && !next) {
+ if (len != sizeof(state)) {
+ return -EINVAL;
+ }
+
+ rc = read_cb(cb_arg, &state, sizeof(state));
+ if (rc >= 0) {
+ return 0;
+ }
+
+ return rc;
+ }
+
+ return -ENOENT;
+}
+
+struct settings_handler rgb_conf = {.name = "rgb/underglow", .h_set = rgb_settings_set};
+#endif
+
static struct led_rgb hsb_to_rgb(struct led_hsb hsb) {
double r, g, b;
@@ -100,6 +124,14 @@ static struct led_rgb hsb_to_rgb(struct led_hsb hsb) {
return rgb;
}
+static void zmk_rgb_underglow_off() {
+ for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
+ pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
+ }
+
+ led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS);
+}
+
static void zmk_rgb_underglow_effect_solid() {
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
int hue = state.hue;
@@ -182,6 +214,14 @@ static void zmk_rgb_underglow_tick(struct k_work *work) {
K_WORK_DEFINE(underglow_work, zmk_rgb_underglow_tick);
static void zmk_rgb_underglow_tick_handler(struct k_timer *timer) {
+ if (!state.on) {
+ zmk_rgb_underglow_off();
+
+ k_timer_stop(timer);
+
+ return;
+ }
+
k_work_submit(&underglow_work);
}
@@ -197,20 +237,32 @@ static int zmk_rgb_underglow_init(struct device *_arg) {
}
state = (struct rgb_underglow_state){
- hue : 0,
- saturation : 100,
- brightness : 100,
- animation_speed : 3,
- current_effect : 0,
+ hue : CONFIG_ZMK_RGB_UNDERGLOW_HUE_START,
+ saturation : CONFIG_ZMK_RGB_UNDERGLOW_SAT_START,
+ brightness : CONFIG_ZMK_RGB_UNDERGLOW_BRT_START,
+ animation_speed : CONFIG_ZMK_RGB_UNDERGLOW_SPD_START,
+ current_effect : CONFIG_ZMK_RGB_UNDERGLOW_EFF_START,
animation_step : 0,
- on : true
+ on : IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_ON_START)
};
+#if IS_ENABLED(CONFIG_SETTINGS)
+ settings_register(&rgb_conf);
+#endif
+
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50));
return 0;
}
+int zmk_rgb_underglow_save_state() {
+#if IS_ENABLED(CONFIG_SETTINGS)
+ return settings_save_one("rgb/underglow/state", &state, sizeof(state));
+#else
+ return 0;
+#endif
+}
+
int zmk_rgb_underglow_cycle_effect(int direction) {
if (!led_strip)
return -ENODEV;
@@ -228,7 +280,7 @@ int zmk_rgb_underglow_cycle_effect(int direction) {
state.animation_step = 0;
- return 0;
+ return zmk_rgb_underglow_save_state();
}
int zmk_rgb_underglow_toggle() {
@@ -241,17 +293,12 @@ int zmk_rgb_underglow_toggle() {
state.animation_step = 0;
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50));
} else {
-
- for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
- pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
- }
-
- led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS);
+ zmk_rgb_underglow_off();
k_timer_stop(&underglow_tick);
}
- return 0;
+ return zmk_rgb_underglow_save_state();
}
int zmk_rgb_underglow_change_hue(int direction) {
@@ -259,17 +306,15 @@ int zmk_rgb_underglow_change_hue(int direction) {
return -ENODEV;
if (state.hue == 0 && direction < 0) {
- state.hue = 350;
+ state.hue = 360 - CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP;
return 0;
}
state.hue += direction * CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP;
- if (state.hue > 350) {
- state.hue = 0;
- }
+ state.hue = state.hue % 360;
- return 0;
+ return zmk_rgb_underglow_save_state();
}
int zmk_rgb_underglow_change_sat(int direction) {
@@ -286,7 +331,7 @@ int zmk_rgb_underglow_change_sat(int direction) {
state.saturation = 100;
}
- return 0;
+ return zmk_rgb_underglow_save_state();
}
int zmk_rgb_underglow_change_brt(int direction) {
@@ -303,7 +348,7 @@ int zmk_rgb_underglow_change_brt(int direction) {
state.brightness = 100;
}
- return 0;
+ return zmk_rgb_underglow_save_state();
}
int zmk_rgb_underglow_change_spd(int direction) {
@@ -320,7 +365,7 @@ int zmk_rgb_underglow_change_spd(int direction) {
state.animation_speed = 5;
}
- return 0;
+ return zmk_rgb_underglow_save_state();
}
SYS_INIT(zmk_rgb_underglow_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
diff --git a/app/src/settings.c b/app/src/settings.c
new file mode 100644
index 0000000..8914ccc
--- /dev/null
+++ b/app/src/settings.c
@@ -0,0 +1,8 @@
+#include <device.h>
+#include <init.h>
+#include <kernel.h>
+#include <settings/settings.h>
+
+static int zmk_settings_init(struct device *_arg) { return settings_load(); }
+
+SYS_INIT(zmk_settings_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);