Merge branch 'zmkfirmware:main' into main

This commit is contained in:
WSTRN 2022-04-20 00:29:50 +08:00 committed by GitHub
commit cb103a9f35
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 421 additions and 178 deletions

120
.github/workflows/build-user-config.yml vendored Normal file
View file

@ -0,0 +1,120 @@
name: Reusable user config build
on:
workflow_call:
inputs:
build_matrix_path:
description: 'Path to the build matrix file'
default: 'build.yaml'
required: false
type: string
config_path:
description: 'Path to the config directory'
default: 'config'
required: false
type: string
fallback_binary:
description: 'Fallback binary format, if no *.uf2 file was built'
default: 'bin'
required: false
type: string
jobs:
matrix:
runs-on: ubuntu-latest
name: Fetch Build Keyboards
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install yaml2json
run: python3 -m pip install remarshal
- id: set-matrix
name: Fetch Build Matrix
run: |
matrix=$(yaml2json ${{ inputs.build_matrix_path }} | jq -c .)
yaml2json ${{ inputs.build_matrix_path }}
echo "::set-output name=matrix::${matrix}"
build:
runs-on: ubuntu-latest
container:
image: zmkfirmware/zmk-build-arm:stable
needs: matrix
name: Build
strategy:
fail-fast: false
matrix: ${{fromJson(needs.matrix.outputs.matrix)}}
steps:
- name: Prepare variables
id: variables
run: |
if [ -n "${{ matrix.shield }}" ]; then
EXTRA_CMAKE_ARGS="-DSHIELD=${{ matrix.shield }}"
ARTIFACT_NAME="${{ matrix.shield }}-${{ matrix.board }}-zmk"
DISPLAY_NAME="${{ matrix.shield }} - ${{ matrix.board }}"
else
EXTRA_CMAKE_ARGS=
DISPLAY_NAME="${{ matrix.board }}"
ARTIFACT_NAME="${{ matrix.board }}-zmk"
fi
echo ::set-output name=extra-cmake-args::${EXTRA_CMAKE_ARGS}
echo ::set-output name=artifact-name::${ARTIFACT_NAME}
echo ::set-output name=display-name::${DISPLAY_NAME}
echo ::set-output name=zephyr-version::${ZEPHYR_VERSION}
- name: Checkout
uses: actions/checkout@v2
- name: Cache west modules
uses: actions/cache@v3.0.1
env:
cache-name: cache-zephyr-${{ steps.variables.outputs.zephyr-version }}-modules
with:
path: |
modules/
tools/
zephyr/
bootloader/
zmk/
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/west.yml', '**/build.yaml') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: West Init
run: west init -l ${{ inputs.config_path }}
- name: West Update
run: west update
- name: West Zephyr export
run: west zephyr-export
- name: West Build (${{ steps.variables.outputs.display-name }})
run: |
west build -s zmk/app -b ${{ matrix.board }} -- -DZMK_CONFIG=${GITHUB_WORKSPACE}/${{ inputs.config_path }} ${{ steps.variables.outputs.extra-cmake-args }} ${{ matrix.cmake-args }}
- name: ${{ steps.variables.outputs.display-name }} Kconfig file
run: cat build/zephyr/.config | grep -v "^#" | grep -v "^$" | sort
- name: Rename artifacts
run: |
mkdir build/artifacts
if [ -f build/zephyr/zmk.uf2 ]
then
cp build/zephyr/zmk.uf2 "build/artifacts/${{ steps.variables.outputs.artifact-name }}.uf2"
elif [ -f build/zephyr/zmk.${{ inputs.fallback_binary }} ]
then
cp build/zephyr/zmk.${{ inputs.fallback_binary }} "build/artifacts/${{ steps.variables.outputs.artifact-name }}.${{ inputs.fallback_binary }}"
fi
- name: Archive (${{ steps.variables.outputs.display-name }})
uses: actions/upload-artifact@v2
with:
name: firmware
path: build/artifacts

View file

@ -17,6 +17,7 @@
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,console = &cdc_acm_uart;
zmk,battery = &vbatt;
};
leds {
@ -34,7 +35,7 @@
control-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
};
vbatt {
vbatt: vbatt {
compatible = "zmk,battery-voltage-divider";
label = "BATTERY";
io-channels = <&adc 7>;

View file

@ -17,6 +17,7 @@
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,console = &cdc_acm_uart;
zmk,battery = &vbatt;
zmk,kscan = &kscan0;
zmk,matrix_transform = &default_transform;
};
@ -46,7 +47,7 @@
};
};
vbatt {
vbatt: vbatt {
compatible = "zmk,battery-voltage-divider";
label = "BATTERY";
io-channels = <&adc 2>;

View file

@ -17,6 +17,7 @@
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,console = &cdc_acm_uart;
zmk,battery = &vbatt;
};
leds {
@ -34,7 +35,7 @@
init-delay-ms = <50>;
};
vbatt {
vbatt: vbatt {
compatible = "zmk,battery-voltage-divider";
label = "BATTERY";
io-channels = <&adc 2>;

View file

@ -19,6 +19,7 @@
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,console = &cdc_acm_uart;
zmk,battery = &vbatt;
zmk,kscan = &kscan0;
zmk,matrix_transform = &default_transform;
zmk,underglow = &led_strip;
@ -81,7 +82,7 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,5) R
control-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
};
vbatt {
vbatt: vbatt {
compatible = "zmk,battery-voltage-divider";
label = "BATTERY";
io-channels = <&adc 2>;

View file

@ -8,13 +8,17 @@
#include "nice_nano.dtsi"
/ {
chosen {
zmk,battery = &vbatt;
};
ext-power {
compatible = "zmk,ext-power-generic";
label = "EXT_POWER";
control-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
};
vbatt {
vbatt: vbatt {
compatible = "zmk,battery-voltage-divider";
label = "BATTERY";
io-channels = <&adc 2>;

View file

@ -8,6 +8,10 @@
#include "nice_nano.dtsi"
/ {
chosen {
zmk,battery = &vbatt;
};
ext-power {
compatible = "zmk,ext-power-generic";
label = "EXT_POWER";
@ -15,7 +19,7 @@
init-delay-ms = <50>;
};
vbatt {
vbatt: vbatt {
compatible = "zmk,battery-nrf-vddh";
label = "BATTERY";
};

View file

@ -17,6 +17,7 @@
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,console = &cdc_acm_uart;
zmk,battery = &vbatt;
};
leds {
@ -33,7 +34,7 @@
control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
};
vbatt {
vbatt: vbatt {
compatible = "zmk,battery-voltage-divider";
label = "BATTERY";
io-channels = <&adc 2>;

View file

@ -17,6 +17,7 @@
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,console = &cdc_acm_uart;
zmk,battery = &vbatt;
zmk,kscan = &kscan0;
zmk,matrix_transform = &default_transform;
};
@ -69,7 +70,7 @@
};
};
vbatt {
vbatt: vbatt {
compatible = "zmk,battery-voltage-divider";
label = "BATTERY";
io-channels = <&adc 2>;

View file

@ -3,6 +3,7 @@ CONFIG_CONSOLE=n
CONFIG_SERIAL=n
CONFIG_UART_CONSOLE=n
CONFIG_UART_INTERRUPT_DRIVEN=n
CONFIG_ZMK_BATTERY_VOLTAGE_DIVIDER=y
CONFIG_ZMK_USB=y
CONFIG_ZMK_BLE=y

View file

@ -8,9 +8,10 @@
/ {
chosen {
zephyr,console = &cdc_acm_uart;
zmk,battery = &vbatt;
};
vbatt {
vbatt: vbatt {
compatible = "zmk,battery-voltage-divider";
label = "BATTERY";
io-channels = <&adc 7>;

View file

@ -5,6 +5,7 @@
*/
#include <device.h>
#include <devicetree.h>
#include <init.h>
#include <kernel.h>
#include <drivers/sensor.h>
@ -18,12 +19,18 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/battery.h>
#include <zmk/events/battery_state_changed.h>
const struct device *battery;
static uint8_t last_state_of_charge = 0;
uint8_t zmk_battery_state_of_charge() { return last_state_of_charge; }
#if DT_HAS_CHOSEN(zmk_battery)
static const struct device *const battery = DEVICE_DT_GET(DT_CHOSEN(zmk_battery));
#else
#warning \
"Using a node labeled BATTERY for the battery sensor is deprecated. Set a zmk,battery chosen node instead. (Ignore this if you don't have a battery sensor.)"
static const struct device *battery;
#endif
static int zmk_battery_update(const struct device *battery) {
struct sensor_value state_of_charge;
@ -75,10 +82,18 @@ static void zmk_battery_timer(struct k_timer *timer) { k_work_submit(&battery_wo
K_TIMER_DEFINE(battery_timer, zmk_battery_timer, NULL);
static int zmk_battery_init(const struct device *_arg) {
#if !DT_HAS_CHOSEN(zmk_battery)
battery = device_get_binding("BATTERY");
if (battery == NULL) {
LOG_DBG("No battery device labelled BATTERY found.");
return -ENODEV;
}
LOG_WRN("Finding battery device labeled BATTERY is deprecated. Use zmk,battery chosen node.");
#endif
if (!device_is_ready(battery)) {
LOG_ERR("Battery device \"%s\" is not ready", battery->name);
return -ENODEV;
}

View file

@ -0,0 +1,38 @@
---
title: Battery Level
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.
:::note
Windows may not properly ask the keyboard to notify it of changes in battery level, so the level shown may be out of date.
:::
## Adding a Battery Sensor to a Board
To enable a battery sensor on a new board, add the driver for the sensor to your board's `.dts` file. ZMK provides two drivers for estimating the battery level using its voltage:
- `zmk,battery-voltage-divider`: Reads the voltage on an analog input pin.
- `zmk,battery-nrf-vddh`: Reads the power supply voltage on a Nordic nRF52's VDDH pin.
Zephyr also provides some drivers for fuel gauge ICs such as the TI bq274xx series and Maxim MAX17xxx series. If you use a battery sensor that does not have an existing driver, you will need to write a new driver that supports the `SENSOR_CHAN_GAUGE_STATE_OF_CHARGE` sensor channel and contribute it to Zephyr or ZMK.
Once you have the sensor driver defined, add a `zmk,battery` property to the `chosen` node and set it to reference the sensor node. For example:
```
/ {
chosen {
zmk,battery = &vbatt;
};
vbatt: vbatt {
compatible = "zmk,battery-nrf-vddh";
label = "VBATT";
};
}
```

View file

@ -1,6 +1,10 @@
---
title: OLED Displays
sidebar_label: OLED Displays
title: Displays
sidebar_label: Displays
---
TODO: Documentation on OLED displays.
Displays in ZMK are currently a proof of concept and official support is coming soon.
:::info
Although ZMK-powered keyboards _are_ capable of utilizing OLED and ePaper displays, the Displays feature is not yet considered production-ready due to an issue where the display remains blank after resuming from [external power cutoff](../behaviors/power.md#external-power-control). This issue can be tracked on GitHub at [zmkfirmware/zmk #674](https://github.com/zmkfirmware/zmk/issues/674).
:::

View file

@ -6,12 +6,48 @@ sidebar_label: Supported Hardware
import HardwareList from "@site/src/components/hardware-list";
import Metadata from "@site/src/data/hardware-metadata.json";
import Heading from "@theme/Heading";
import { groupedMetadata } from "@site/src/components/hardware-utils";
export const toc = [
{
value: "Onboard Controller Keyboards",
id: "onboard",
level: 2,
},
{
value: "Composite Keyboards",
id: "composite",
level: 2,
},
...Object.values(groupedMetadata(Metadata).interconnects).map(
({ interconnect }) => ({
value: `${interconnect.name} Interconnect`,
id: interconnect.id,
level: 3,
})
),
{
value: "Other Hardware",
id: "other-hardware",
level: 2,
},
{
value: "Contributing",
id: "contributing",
level: 2,
},
];
With the solid technical foundation of Zephyr™ RTOS, ZMK can support a wide diversity of hardware targets.
That being said, there are currently only a few specific [boards](/docs/faq#what-is-a-board)/[shields](faq.md#what-is-a-shield) that have been implemented and tested by the ZMK contributors.
<HardwareList items={Metadata} />
## Other Hardware
<Heading as="h2" id="other-hardware">
Other Hardware
</Heading>
In addition to the basic keyboard functionality, there is some initial support for additional keyboard hardware:
@ -22,6 +58,8 @@ In addition to the basic keyboard functionality, there is some initial support f
Until detailed documentation is available, feel free to ask questions about how these are supported in the [Discord server](https://zmk.dev/community/discord/invite).
## Contributing
<Heading as="h2" id="contributing">
Contributing
</Heading>
If you'd like to add support for a new keyboard shield, head over to the [New Keyboard Shield](development/new-shield.md) documentation.

View file

@ -32,7 +32,7 @@ ZMK is currently missing some features found in other popular firmware. This tab
| [Backlight](features/backlight.md) | ✅ | ✅ | ✅ |
| One Shot Keys | ✅ | ✅ | ✅ |
| [Combo Keys](features/combos.md) | ✅ | | ✅ |
| [Macros](behaviors/macros) | ✅ | ✅ | ✅ |
| [Macros](behaviors/macros.md) | ✅ | ✅ | ✅ |
| Mouse Keys | 🚧 | ✅ | ✅ |
| Low Active Power Usage | ✅ | | |
| Low Power Sleep States | ✅ | ✅ | |

122
docs/package-lock.json generated
View file

@ -4825,11 +4825,23 @@
}
},
"@fortawesome/react-fontawesome": {
"version": "0.1.16",
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.16.tgz",
"integrity": "sha512-aLmzDwC9rEOAJv2UJdMns89VZR5Ry4IHu5dQQh24Z/lWKEm44lfQr1UNalZlkUaQN8d155tNh+CS7ntntj1VMA==",
"version": "0.1.18",
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.18.tgz",
"integrity": "sha512-RwLIB4TZw0M9gvy5u+TusAA0afbwM4JQIimNH/j3ygd6aIvYPQLqXMhC9ErY26J23rDPyDZldIfPq/HpTTJ/tQ==",
"requires": {
"prop-types": "^15.7.2"
"prop-types": "^15.8.1"
},
"dependencies": {
"prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
}
}
},
"@hapi/hoek": {
@ -5858,9 +5870,9 @@
"dev": true
},
"async": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"requires": {
"lodash": "^4.17.14"
}
@ -7569,21 +7581,29 @@
"dev": true
},
"eslint-mdx": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/eslint-mdx/-/eslint-mdx-1.13.0.tgz",
"integrity": "sha512-Yqc5mnh2JMEm9yTp6NUnfOg1wXGLibCqQTjvb5+EQH4LtQEmWG0DtqWUXWHRy0gmy/3lBdN9Zkc5KGwAizaTrQ==",
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/eslint-mdx/-/eslint-mdx-1.17.0.tgz",
"integrity": "sha512-O8+JRfwCzpoR2P6zUI1GDAAM/bsuzcoBS1ArvpQrgQO/E2Km0vBmM15ukiJxZ+YUh5d+qDlrqha0fZB50MojJQ==",
"dev": true,
"requires": {
"cosmiconfig": "^7.0.1",
"remark-mdx": "^1.6.22",
"remark-parse": "^8.0.3",
"tslib": "^2.2.0",
"unified": "^9.2.1"
"remark-stringify": "^8.1.1",
"tslib": "^2.3.1",
"unified": "^9.2.2"
},
"dependencies": {
"tslib": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
"dev": true
},
"unified": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/unified/-/unified-9.2.1.tgz",
"integrity": "sha512-juWjuI8Z4xFg8pJbnEZ41b5xjGUWGHqXALmBZ3FC3WX0PIx1CZBIIJ6mXbYMcf6Yw4Fi0rFUTA1cdz/BglbOhA==",
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz",
"integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==",
"dev": true,
"requires": {
"bail": "^1.0.0",
@ -7597,58 +7617,32 @@
}
},
"eslint-plugin-markdown": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-2.2.0.tgz",
"integrity": "sha512-Ctuc7aP1tU92qnFwVO1wDLEzf1jqMxwRkcSTw7gjbvnEqfh5CKUcTXM0sxg8CB2KDXrqpTuMZPgJ1XE9Olr7KA==",
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-2.2.1.tgz",
"integrity": "sha512-FgWp4iyYvTFxPwfbxofTvXxgzPsDuSKHQy2S+a8Ve6savbujey+lgrFFbXQA0HPygISpRYWYBjooPzhYSF81iA==",
"dev": true,
"requires": {
"mdast-util-from-markdown": "^0.8.5"
}
},
"eslint-plugin-mdx": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-mdx/-/eslint-plugin-mdx-1.13.0.tgz",
"integrity": "sha512-oZ/R9OmSx1gZs52CO58HTHlJXRKoZtF6ZMaWP+sOcSGMFxoddoPr9PDgpP52ab5TWu5yVl5guR9D+GMfzkR2Uw==",
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-mdx/-/eslint-plugin-mdx-1.17.0.tgz",
"integrity": "sha512-Kicizy+fbfsB2UxTDXP92qTtFqITApu4v4DRQUfXMoPwBHeQRvZnaEtXu2S9aia51GYRYsMSqUvoPPih/5oB+g==",
"dev": true,
"requires": {
"cosmiconfig": "^7.0.0",
"eslint-mdx": "^1.13.0",
"eslint-plugin-markdown": "^2.1.0",
"remark-mdx": "^1.6.22",
"remark-parse": "^8.0.3",
"remark-stringify": "^8.1.1",
"synckit": "^0.1.5",
"tslib": "^2.2.0",
"unified": "^9.2.1",
"eslint-mdx": "^1.17.0",
"eslint-plugin-markdown": "^2.2.1",
"synckit": "^0.4.1",
"tslib": "^2.3.1",
"vfile": "^4.2.1"
},
"dependencies": {
"cosmiconfig": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
"integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==",
"dev": true,
"requires": {
"@types/parse-json": "^4.0.0",
"import-fresh": "^3.2.1",
"parse-json": "^5.0.0",
"path-type": "^4.0.0",
"yaml": "^1.10.0"
}
},
"unified": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/unified/-/unified-9.2.1.tgz",
"integrity": "sha512-juWjuI8Z4xFg8pJbnEZ41b5xjGUWGHqXALmBZ3FC3WX0PIx1CZBIIJ6mXbYMcf6Yw4Fi0rFUTA1cdz/BglbOhA==",
"dev": true,
"requires": {
"bail": "^1.0.0",
"extend": "^3.0.0",
"is-buffer": "^2.0.0",
"is-plain-obj": "^2.0.0",
"trough": "^1.0.0",
"vfile": "^4.0.0"
}
"tslib": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
"dev": true
}
}
},
@ -12815,19 +12809,19 @@
}
},
"synckit": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.1.5.tgz",
"integrity": "sha512-s9rDbMJAF5SDEwBGH/DvbN/fb5N1Xu1boL4Uv66idbCbtosNX3ikUsFvGhROmPXsvlMYMcT5ksmkU5RSnkFi9Q==",
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.4.1.tgz",
"integrity": "sha512-ngUh0+s+DOqEc0sGnrLaeNjbXp0CWHjSGFBqPlQmQ+oN/OfoDoYDBXPh+b4qs1M5QTk5nuQ3AmVz9+2xiY/ldw==",
"dev": true,
"requires": {
"tslib": "^2.2.0",
"tslib": "^2.3.1",
"uuid": "^8.3.2"
},
"dependencies": {
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"tslib": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
"dev": true
}
}

View file

@ -19,7 +19,7 @@
"@docusaurus/preset-classic": "^2.0.0-beta.18",
"@fortawesome/fontawesome-svg-core": "^1.2.32",
"@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/react-fontawesome": "^0.1.16",
"@fortawesome/react-fontawesome": "^0.1.18",
"@mdx-js/react": "^1.6.22",
"classnames": "^2.2.6",
"js-yaml": "^4.1.0",
@ -52,7 +52,7 @@
"@types/react-router-dom": "^5.1.7",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-mdx": "^1.13.0",
"eslint-plugin-mdx": "^1.17.0",
"eslint-plugin-react": "^7.28.0",
"json-schema-to-typescript": "^10.1.5",
"mustache": "^4.2.0",

View file

@ -17,6 +17,7 @@ module.exports = {
"features/encoders",
"features/underglow",
"features/backlight",
"features/battery",
"features/beta-testing",
],
Behaviors: [

View file

@ -1,11 +1,9 @@
import React from "react";
import {
Board,
HardwareMetadata,
Interconnect,
Shield,
} from "../hardware-metadata";
import Heading from "@theme/Heading";
import { HardwareMetadata } from "../hardware-metadata";
import { groupedMetadata, InterconnectDetails } from "./hardware-utils";
interface HardwareListProps {
items: HardwareMetadata[];
@ -53,12 +51,6 @@ function HardwareLineItem({ item }: { item: HardwareMetadata }) {
);
}
interface InterconnectDetails {
interconnect?: Interconnect;
boards: Board[];
shields: Shield[];
}
function mapInterconnect({
interconnect,
boards,
@ -70,15 +62,17 @@ function mapInterconnect({
return (
<div key={interconnect.id}>
<h4>{interconnect.name} Interconnect</h4>
<Heading as="h3" id={interconnect.id}>
{interconnect.name} Interconnect
</Heading>
{interconnect.description && <p>{interconnect.description}</p>}
<h5>Boards</h5>
<Heading as="h4">Boards</Heading>
<ul>
{boards.map((s) => (
<HardwareLineItem key={s.id} item={s} />
))}
</ul>
<h5>Shields</h5>
<Heading as="h4">Shields</Heading>
<ul>
{shields.map((s) => (
<HardwareLineItem key={s.id} item={s} />
@ -88,70 +82,18 @@ function mapInterconnect({
);
}
interface GroupedMetadata {
onboard: Board[];
interconnects: Record<string, InterconnectDetails>;
}
function groupedBoard(agg: GroupedMetadata, board: Board) {
if (board.features?.includes("keys")) {
agg.onboard.push(board);
} else if (board.exposes) {
board.exposes.forEach((element) => {
let ic = agg.interconnects[element] ?? {
boards: [],
shields: [],
};
ic.boards.push(board);
agg.interconnects[element] = ic;
});
} else {
console.error("Board without keys or interconnect");
}
return agg;
}
function groupedShield(agg: GroupedMetadata, shield: Shield) {
shield.requires.forEach((id) => {
let ic = agg.interconnects[id] ?? { boards: [], shields: [] };
ic.shields.push(shield);
agg.interconnects[id] = ic;
});
return agg;
}
function groupedInterconnect(agg: GroupedMetadata, item: Interconnect) {
let ic = agg.interconnects[item.id] ?? { boards: [], shields: [] };
ic.interconnect = item;
agg.interconnects[item.id] = ic;
return agg;
}
function HardwareList({ items }: HardwareListProps) {
let grouped = items.reduce<GroupedMetadata>(
(agg, hm) => {
switch (hm.type) {
case "board":
return groupedBoard(agg, hm);
case "shield":
return groupedShield(agg, hm);
case "interconnect":
return groupedInterconnect(agg, hm);
}
},
{ onboard: [] as Board[], interconnects: {} }
);
let grouped = groupedMetadata(items);
return (
<>
<h2>Keyboards</h2>
<h3>Onboard Controller Keyboards</h3>
<section>
<Heading as="h2" id="onboard">
Onboard Controller Keyboards
</Heading>
<p>
Keyboards with onboard controllers are single PCBs that contain all the
components of a keyboard, including the controller chip, switch
Keyboards with onboard controllers are single PCBs that contain all
the components of a keyboard, including the controller chip, switch
footprints, etc.
</p>
<ul>
@ -161,7 +103,11 @@ function HardwareList({ items }: HardwareListProps) {
<HardwareLineItem key={s.id} item={s} />
))}
</ul>
<h3>Composite Keyboards</h3>
</section>
<section>
<Heading as="h2" id="composite">
Composite Keyboards
</Heading>
<p>
Composite keyboards are composed of two main PCBs: a small controller
board with exposed pads, and a larger keyboard PCB (a shield, in ZMK
@ -170,6 +116,7 @@ function HardwareList({ items }: HardwareListProps) {
can be found below.
</p>
{Object.values(grouped.interconnects).map(mapInterconnect)}
</section>
</>
);
}

View file

@ -0,0 +1,70 @@
import {
Board,
HardwareMetadata,
Interconnect,
Shield,
} from "../hardware-metadata";
export interface InterconnectDetails {
interconnect?: Interconnect;
boards: Board[];
shields: Shield[];
}
export interface GroupedMetadata {
onboard: Board[];
interconnects: Record<string, InterconnectDetails>;
}
function groupedBoard(agg: GroupedMetadata, board: Board) {
if (board.features?.includes("keys")) {
agg.onboard.push(board);
} else if (board.exposes) {
board.exposes.forEach((element) => {
let ic = agg.interconnects[element] ?? {
boards: [],
shields: [],
};
ic.boards.push(board);
agg.interconnects[element] = ic;
});
} else {
console.error("Board without keys or interconnect");
}
return agg;
}
function groupedShield(agg: GroupedMetadata, shield: Shield) {
shield.requires.forEach((id) => {
let ic = agg.interconnects[id] ?? { boards: [], shields: [] };
ic.shields.push(shield);
agg.interconnects[id] = ic;
});
return agg;
}
function groupedInterconnect(agg: GroupedMetadata, item: Interconnect) {
let ic = agg.interconnects[item.id] ?? { boards: [], shields: [] };
ic.interconnect = item;
agg.interconnects[item.id] = ic;
return agg;
}
export function groupedMetadata(items: HardwareMetadata[]) {
return items.reduce<GroupedMetadata>(
(agg, hm) => {
switch (hm.type) {
case "board":
return groupedBoard(agg, hm);
case "shield":
return groupedShield(agg, hm);
case "interconnect":
return groupedInterconnect(agg, hm);
}
},
{ onboard: [] as Board[], interconnects: {} }
);
}

View file

@ -2,7 +2,7 @@
"extends": "@tsconfig/docusaurus/tsconfig.json",
"include": ["src/"],
"compilerOptions": {
"jsx": "react",
"types": ["node", "@docusaurus/theme-classic"],
"moduleResolution": "Node",
"esModuleInterop": true,
"resolveJsonModule": true,