Skip to content

Commit

Permalink
Merge https://github.com/zmkfirmware/zmk into soft-off-clarity
Browse files Browse the repository at this point in the history
  • Loading branch information
Nick-Munnich committed Aug 8, 2024
2 parents a146242 + 2eff266 commit 733f215
Show file tree
Hide file tree
Showing 17 changed files with 200 additions and 43 deletions.
107 changes: 82 additions & 25 deletions app/module/drivers/kscan/kscan_composite.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define DT_DRV_COMPAT zmk_kscan_composite

#include <zephyr/device.h>
#include <zephyr/pm/device.h>
#include <zephyr/drivers/kscan.h>
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
Expand All @@ -26,10 +27,10 @@ struct kscan_composite_child_config {
.row_offset = DT_PROP(inst, row_offset), \
.column_offset = DT_PROP(inst, column_offset)},

const struct kscan_composite_child_config kscan_composite_children[] = {
DT_FOREACH_CHILD(MATRIX_NODE_ID, CHILD_CONFIG)};

struct kscan_composite_config {};
struct kscan_composite_config {
const struct kscan_composite_child_config *children;
size_t children_len;
};

struct kscan_composite_data {
kscan_callback_t callback;
Expand All @@ -38,51 +39,80 @@ struct kscan_composite_data {
};

static int kscan_composite_enable_callback(const struct device *dev) {
for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) {
const struct kscan_composite_child_config *cfg = &kscan_composite_children[i];
const struct kscan_composite_config *cfg = dev->config;

for (int i = 0; i < cfg->children_len; i++) {
const struct kscan_composite_child_config *child_cfg = &cfg->children[i];

#if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)
if (!pm_device_runtime_is_enabled(dev) && pm_device_runtime_is_enabled(child_cfg->child)) {
pm_device_runtime_get(child_cfg->child);
}
#elif IS_ENABLED(CONFIG_PM_DEVICE)
pm_device_action_run(child_cfg->child, PM_DEVICE_ACTION_RESUME);
#endif // IS_ENABLED(CONFIG_PM_DEVICE)

kscan_enable_callback(cfg->child);
kscan_enable_callback(child_cfg->child);
}
return 0;
}

static int kscan_composite_disable_callback(const struct device *dev) {
for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) {
const struct kscan_composite_child_config *cfg = &kscan_composite_children[i];
const struct kscan_composite_config *cfg = dev->config;
for (int i = 0; i < cfg->children_len; i++) {
const struct kscan_composite_child_config *child_cfg = &cfg->children[i];

kscan_disable_callback(child_cfg->child);

kscan_disable_callback(cfg->child);
#if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)
if (!pm_device_runtime_is_enabled(dev) && pm_device_runtime_is_enabled(child_cfg->child)) {
pm_device_runtime_put(child_cfg->child);
}
#elif IS_ENABLED(CONFIG_PM_DEVICE)
pm_device_action_run(child_cfg->child, PM_DEVICE_ACTION_SUSPEND);
#endif // IS_ENABLED(CONFIG_PM_DEVICE)
}
return 0;
}

#define KSCAN_COMP_INST_DEV(n) DEVICE_DT_GET(DT_DRV_INST(n)),

static const struct device *all_instances[] = {DT_INST_FOREACH_STATUS_OKAY(KSCAN_COMP_INST_DEV)};

static void kscan_composite_child_callback(const struct device *child_dev, uint32_t row,
uint32_t column, bool pressed) {
// TODO: Ideally we can get this passed into our callback!
const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0));
struct kscan_composite_data *data = dev->data;
for (int i = 0; i < ARRAY_SIZE(all_instances); i++) {

for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) {
const struct kscan_composite_child_config *cfg = &kscan_composite_children[i];
const struct device *dev = all_instances[i];
const struct kscan_composite_config *cfg = dev->config;
struct kscan_composite_data *data = dev->data;

if (cfg->child != child_dev) {
continue;
}
for (int c = 0; c < cfg->children_len; c++) {
const struct kscan_composite_child_config *child_cfg = &cfg->children[c];

if (child_cfg->child != child_dev) {
continue;
}

data->callback(dev, row + cfg->row_offset, column + cfg->column_offset, pressed);
data->callback(dev, row + child_cfg->row_offset, column + child_cfg->column_offset,
pressed);
}
}
}

static int kscan_composite_configure(const struct device *dev, kscan_callback_t callback) {
const struct kscan_composite_config *cfg = dev->config;
struct kscan_composite_data *data = dev->data;

if (!callback) {
return -EINVAL;
}

for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) {
const struct kscan_composite_child_config *cfg = &kscan_composite_children[i];
for (int i = 0; i < cfg->children_len; i++) {
const struct kscan_composite_child_config *child_cfg = &cfg->children[i];

kscan_config(cfg->child, &kscan_composite_child_callback);
kscan_config(child_cfg->child, &kscan_composite_child_callback);
}

data->callback = callback;
Expand All @@ -95,6 +125,10 @@ static int kscan_composite_init(const struct device *dev) {

data->dev = dev;

#if IS_ENABLED(CONFIG_PM_DEVICE)
pm_device_init_suspended(dev);
#endif

return 0;
}

Expand All @@ -104,9 +138,32 @@ static const struct kscan_driver_api mock_driver_api = {
.disable_callback = kscan_composite_disable_callback,
};

static const struct kscan_composite_config kscan_composite_config = {};
#if IS_ENABLED(CONFIG_PM_DEVICE)

static struct kscan_composite_data kscan_composite_data;
static int kscan_composite_pm_action(const struct device *dev, enum pm_device_action action) {
switch (action) {
case PM_DEVICE_ACTION_SUSPEND:
return kscan_composite_disable_callback(dev);
case PM_DEVICE_ACTION_RESUME:
return kscan_composite_enable_callback(dev);
default:
return -ENOTSUP;
}
}

DEVICE_DT_INST_DEFINE(0, kscan_composite_init, NULL, &kscan_composite_data, &kscan_composite_config,
POST_KERNEL, CONFIG_ZMK_KSCAN_COMPOSITE_INIT_PRIORITY, &mock_driver_api);
#endif // IS_ENABLED(CONFIG_PM_DEVICE)

#define KSCAN_COMP_DEV(n) \
static const struct kscan_composite_child_config kscan_composite_children_##n[] = { \
DT_INST_FOREACH_CHILD(n, CHILD_CONFIG)}; \
static const struct kscan_composite_config kscan_composite_config_##n = { \
.children = kscan_composite_children_##n, \
.children_len = ARRAY_SIZE(kscan_composite_children_##n), \
}; \
static struct kscan_composite_data kscan_composite_data_##n; \
PM_DEVICE_DT_INST_DEFINE(n, kscan_composite_pm_action); \
DEVICE_DT_INST_DEFINE(n, kscan_composite_init, PM_DEVICE_DT_INST_GET(n), \
&kscan_composite_data_##n, &kscan_composite_config_##n, POST_KERNEL, \
CONFIG_ZMK_KSCAN_COMPOSITE_INIT_PRIORITY, &mock_driver_api);

DT_INST_FOREACH_STATUS_OKAY(KSCAN_COMP_DEV)
2 changes: 1 addition & 1 deletion docs/docs/behaviors/backlight.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNC

## Split Keyboards

Backlight behaviors are global: This means that when triggered, they affect both the central and peripheral side of split keyboards.
Backlight behaviors are [global](../features/split-keyboards.md#global-locality-behaviors): This means that when triggered, they affect both the central and peripheral side of split keyboards.
2 changes: 1 addition & 1 deletion docs/docs/behaviors/power.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,4 @@ However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../con

## Split Keyboards

Power management behaviors are global: This means that when triggered, they affects both the central and peripheral side of split keyboards.
Power management behaviors are [global](../features/split-keyboards.md#global-locality-behaviors): This means that when triggered, they affects both the central and peripheral side of split keyboards.
6 changes: 1 addition & 5 deletions docs/docs/behaviors/reset.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,4 @@ Example:

## Split Keyboards

Both basic and bootloader reset behaviors are source-specific: This means that it affects the side of the keyboard that contains the behavior binding for split keyboards. For example if you press a key with the `&sys_reset` binding on the left half of the keyboard, the left half will be reset. If you want to be able to reset both sides you can put the bindings on both sides of the keyboard and activate it on the side you would like to reset.

:::note[Peripheral invocation]
The peripheral side of the keyboard has to be paired and connected to the central side in order to be able to activate these behaviors, even if it is possible to trigger the behavior using only keys on that side. This is because the key bindings are processed on the central side which would then instruct the peripheral side to reset.
:::
Both basic and bootloader reset behaviors are [source-specific](../features/split-keyboards.md##source-locality-behaviors): This means that it affects the side of the keyboard that contains the behavior binding for split keyboards. For example if you press a key with the `&sys_reset` binding on the left half of the keyboard, the left half will be reset. If you want to be able to reset both sides you can put the bindings on both sides of the keyboard and activate it on the side you would like to reset.
2 changes: 1 addition & 1 deletion docs/docs/behaviors/underglow.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,4 @@ However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNC

## Split Keyboards

RGB underglow behaviors are global: This means that when triggered, they affect both the central and peripheral side of split keyboards.
RGB underglow behaviors are [global](../features/split-keyboards.md#global-locality-behaviors): This means that when triggered, they affect both the central and peripheral side of split keyboards.
2 changes: 1 addition & 1 deletion docs/docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ When building with a `zmk-config` folder, ZMK will search the `zmk-config/config

These files hold your personal settings for the keyboard. All files are optional. If present, they override any configuration set in the board or shield folders. Otherwise, the default configuration and/or keymap is used.

When using a split keyboard, you can use a single file without the `_left` or `_right` suffix to configure both sides. For example, `corne.conf` and `corne.keymap` will apply to both `corne_left` and `corne_right`. If a shared config file exists, any left or right files will be ignored.
When using a [split keyboard](../features/split-keyboards.md), you can use a single file without the `_left` or `_right` suffix to configure both sides. For example, `corne.conf` and `corne.keymap` will apply to both `corne_left` and `corne_right`. If a shared config file exists, any left or right files will be ignored.

### Board Folder

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/config/system.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Note that `CONFIG_BT_MAX_CONN` and `CONFIG_BT_MAX_PAIRED` should be set to the s

### Split keyboards

Following split keyboard settings are defined in [zmk/app/src/split/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/split/Kconfig) (generic) and [zmk/app/src/split/bluetooth/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/split/bluetooth/Kconfig) (bluetooth).
Following [split keyboard](../features/split-keyboards.md) settings are defined in [zmk/app/src/split/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/split/Kconfig) (generic) and [zmk/app/src/split/bluetooth/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/split/bluetooth/Kconfig) (bluetooth).

| Config | Type | Description | Default |
| ------------------------------------------------------- | ---- | -------------------------------------------------------------------------- | ------------------------------------------ |
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ It is also possible to build firmware locally on your computer by following the

For normal keyboards, follow the same flashing instructions as before to flash your updated firmware.

For split keyboards, only the central (left) side will need to be reflashed if you are just updating your keymap.
For [split keyboards](features/split-keyboards.md#building-and-flashing-firmware), only the central (left) side will need to be reflashed if you are just updating your keymap.
More troubleshooting information for split keyboards can be found [here](troubleshooting/connection-issues.mdx#split-keyboard-halves-unable-to-pair).

## Building Additional Keyboards
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/development/new-behavior.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
endif()
```

For behaviors that do not require central locality, the following options for updating `app/CmakeLists.txt` also exist:
For behaviors that do not require [central locality](../features/split-keyboards.md#behaviors-with-locality), the following options for updating `app/CMakeLists.txt` also exist:

- Behavior applies to unibody, or central or peripheral half of keyboard: place `target_sources(app PRIVATE <behavior_name>.c)` line _before_ `if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)`
- Behavior applies to _only_ central half of split keyboard: place `target_sources(app PRIVATE <behavior_name>.c)` after `if (CONFIG_ZMK_SPLIT AND CONFIG_ZMK_SPLIT_ROLE_CENTRAL)`
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/development/new-shield.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The high level steps are:
It may be helpful to review the upstream [shields documentation](https://docs.zephyrproject.org/3.5.0/hardware/porting/shields.html#shields) to get a proper understanding of the underlying system before continuing.

:::note
ZMK support for split keyboards requires a few more files than single boards to ensure proper connectivity between the central and peripheral units. Check the following guides thoroughly to ensure that all the files are in place.
ZMK support for [split keyboards](../features/split-keyboards.md) requires a few more files than single boards to ensure proper connectivity between the central and peripheral units. Check the following guides thoroughly to ensure that all the files are in place.
:::

## New Zephyr Module Repository
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/features/battery.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sidebar_label: Battery Level

If your keyboard has a battery sensor, ZMK will report its battery level to the connected bluetooth host and show it on the keyboard's display, if it has one.

For split keyboards, only the battery level of the central (usually left) side is reported over bluetooth by default. ZMK can be [configured to report the battery levels for peripherals](../config/battery.md#peripheral-battery-monitoring), but not many host systems will display this information without additional configuration or the use of third party utilities.
For [split keyboards](split-keyboards.md), only the battery level of the central (usually left) side is reported over bluetooth by default. ZMK can be [configured to report the battery levels for peripherals](../config/battery.md#peripheral-battery-monitoring), but not many host systems will display this information without additional configuration or the use of third party utilities.

:::note

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/features/bluetooth.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: Bluetooth
sidebar_label: Bluetooth
---

ZMK's bluetooth functionality allows users to connect their keyboards to hosts using Bluetooth Low Energy (BLE) technology. It also is used for split keyboards to connect the two halves wirelessly.
ZMK's bluetooth functionality allows users to connect their keyboards to hosts using Bluetooth Low Energy (BLE) technology. It also is used for [split keyboards](split-keyboards.md) to connect the two halves wirelessly.

:::note

Expand Down
4 changes: 2 additions & 2 deletions docs/docs/features/combos.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Key positions are numbered like the keys in your keymap, starting at 0. So, if t
- You are not limited to `&kp` bindings. You can use all ZMK behaviors there, like `&mo`, `&bt`, `&mt`, `&lt` etc.

:::note[Source-specific behaviors on split keyboards]
Invoking a source-specific behavior such as one of the [reset behaviors](behaviors/reset.md) using a combo will always trigger it on the central side of the keyboard, regardless of the side that the keys corresponding to `key-positions` are on.
Invoking a [source-specific behavior](split-keyboards.md#source-locality-behaviors) such as one of the [reset behaviors](behaviors/reset.md) using a combo will always trigger it on the central side of the keyboard, regardless of the side that the keys corresponding to `key-positions` are on.
:::

See [combo configuration](/docs/config/combos) for advanced configuration options.
See [combo configuration](../config/combos.md) for advanced configuration options.
Loading

0 comments on commit 733f215

Please sign in to comment.