Merge branch 'zmkfirmware:main' into main
This commit is contained in:
commit
cb103a9f35
22 changed files with 421 additions and 178 deletions
120
.github/workflows/build-user-config.yml
vendored
Normal file
120
.github/workflows/build-user-config.yml
vendored
Normal 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
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
38
docs/docs/features/battery.md
Normal file
38
docs/docs/features/battery.md
Normal 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";
|
||||
};
|
||||
}
|
||||
```
|
|
@ -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).
|
||||
:::
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
122
docs/package-lock.json
generated
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -17,6 +17,7 @@ module.exports = {
|
|||
"features/encoders",
|
||||
"features/underglow",
|
||||
"features/backlight",
|
||||
"features/battery",
|
||||
"features/beta-testing",
|
||||
],
|
||||
Behaviors: [
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
70
docs/src/components/hardware-utils.ts
Normal file
70
docs/src/components/hardware-utils.ts
Normal 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: {} }
|
||||
);
|
||||
}
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue