Merge remote-tracking branch 'upstream/develop' into data-repository

This commit is contained in:
Nick Brassel 2024-09-19 11:48:16 +10:00
commit aa2092a06b
No known key found for this signature in database
78 changed files with 2139 additions and 829 deletions

View File

@ -1,6 +1,5 @@
<!--- Provide a general summary of your changes in the title above. --> <!--- Provide a general summary of your changes in the title above. -->
<!--- This template is entirely optional and can be removed, but is here to help both you and us. -->
<!--- Anything on lines wrapped in comments like these will not show up in the final text. --> <!--- Anything on lines wrapped in comments like these will not show up in the final text. -->
## Description ## Description
@ -15,7 +14,7 @@
- [ ] New feature - [ ] New feature
- [ ] Enhancement/optimization - [ ] Enhancement/optimization
- [ ] Keyboard (addition or update) - [ ] Keyboard (addition or update)
- [ ] Keymap/layout/userspace (addition or update) - [ ] Keymap/layout (addition or update)
- [ ] Documentation - [ ] Documentation
## Issues Fixed or Closed by This PR ## Issues Fixed or Closed by This PR

View File

@ -47,7 +47,7 @@ jobs:
git config user.email 'hello@qmk.fm' git config user.email 'hello@qmk.fm'
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@v6 uses: peter-evans/create-pull-request@v7
if: ${{ github.repository == 'qmk/qmk_firmware'}} if: ${{ github.repository == 'qmk/qmk_firmware'}}
with: with:
token: ${{ secrets.QMK_BOT_TOKEN }} token: ${{ secrets.QMK_BOT_TOKEN }}

View File

@ -34,7 +34,7 @@ jobs:
git config user.email 'hello@qmk.fm' git config user.email 'hello@qmk.fm'
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@v6 uses: peter-evans/create-pull-request@v7
if: ${{ github.repository == 'qmk/qmk_firmware'}} if: ${{ github.repository == 'qmk/qmk_firmware'}}
with: with:
token: ${{ secrets.QMK_BOT_TOKEN }} token: ${{ secrets.QMK_BOT_TOKEN }}

View File

@ -1,7 +1,7 @@
{ {
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"devDependencies": { "devDependencies": {
"vite": "^5.2.10", "vite": "^5.2.14",
"vitepress": "^1.1.0", "vitepress": "^1.1.0",
"vitepress-plugin-tabs": "^0.5.0", "vitepress-plugin-tabs": "^0.5.0",
"vue": "^3.4.24" "vue": "^3.4.24"

View File

@ -743,10 +743,10 @@ tabbable@^6.2.0:
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97" resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97"
integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew== integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==
vite@^5.2.10, vite@^5.2.9: vite@^5.2.14, vite@^5.2.9:
version "5.2.10" version "5.2.14"
resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.10.tgz#2ac927c91e99d51b376a5c73c0e4b059705f5bd7" resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.14.tgz#fd5f60facf6b5f90ec7da6323c467a365d380c3d"
integrity sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw== integrity sha512-TFQLuwWLPms+NBNlh0D9LZQ+HXW471COABxw/9TEUBrjuHMo9BrYBPrN/SYAwIuVL+rLerycxiLT41t4f5MZpA==
dependencies: dependencies:
esbuild "^0.20.1" esbuild "^0.20.1"
postcss "^8.4.38" postcss "^8.4.38"

View File

@ -167,7 +167,7 @@
}, },
{ "text": "Audio", "link": "/features/audio" }, { "text": "Audio", "link": "/features/audio" },
{ "text": "Bluetooth", "link": "/features/bluetooth" }, { "text": "Bluetooth", "link": "/features/bluetooth" },
{ "text": "Bootmagic Lite", "link": "/features/bootmagic" }, { "text": "Bootmagic", "link": "/features/bootmagic" },
{ "text": "Converters", "link": "/feature_converters" }, { "text": "Converters", "link": "/feature_converters" },
{ "text": "Custom Matrix", "link": "/custom_matrix" }, { "text": "Custom Matrix", "link": "/custom_matrix" },
{ "text": "DIP Switch", "link": "/features/dip_switch" }, { "text": "DIP Switch", "link": "/features/dip_switch" },

View File

@ -413,7 +413,7 @@ Use these to enable or disable building certain features. The more you have enab
* `MAGIC_ENABLE` * `MAGIC_ENABLE`
* MAGIC actions (BOOTMAGIC without the boot) * MAGIC actions (BOOTMAGIC without the boot)
* `BOOTMAGIC_ENABLE` * `BOOTMAGIC_ENABLE`
* Enable Bootmagic Lite * Enable Bootmagic
* `MOUSEKEY_ENABLE` * `MOUSEKEY_ENABLE`
* Mouse keys * Mouse keys
* `EXTRAKEY_ENABLE` * `EXTRAKEY_ENABLE`

View File

@ -8,8 +8,8 @@ We recommend the use of the [Zadig](https://zadig.akeo.ie/) utility. If you have
## Installation ## Installation
Put your keyboard into bootloader mode, either by hitting the `QK_BOOT` keycode (which may be on a different layer), or by pressing the reset switch that's usually located on the underside of the board. If your keyboard has neither, try holding Escape or Space+`B` as you plug it in (see the [Bootmagic Lite](features/bootmagic) docs for more details). Some boards use [Command](features/command) instead of Bootmagic; in this case, you can enter bootloader mode by hitting Left Shift+Right Shift+`B` or Left Shift+Right Shift+Escape at any point while the keyboard is plugged in. Put your keyboard into bootloader mode, either by hitting the `QK_BOOT` keycode (which may be on a different layer), or by pressing the reset switch that's usually located on the underside of the board. If your keyboard has neither, try holding Escape or Space+`B` as you plug it in (see the [Bootmagic](features/bootmagic) docs for more details). Some boards use [Command](features/command) instead of Bootmagic; in this case, you can enter bootloader mode by hitting Left Shift+Right Shift+`B` or Left Shift+Right Shift+Escape at any point while the keyboard is plugged in.
Some keyboards may have specific instructions for entering the bootloader. For example, the [Bootmagic Lite](features/bootmagic) key (default: Escape) might be on a different key, e.g. Left Control; or the magic combination for Command (default: Left Shift+Right Shift) might require you to hold something else, e.g. Left Control+Right Control. Refer to the board's README file if you are unsure. Some keyboards may have specific instructions for entering the bootloader. For example, the [Bootmagic](features/bootmagic) key (default: Escape) might be on a different key, e.g. Left Control; or the magic combination for Command (default: Left Shift+Right Shift) might require you to hold something else, e.g. Left Control+Right Control. Refer to the board's README file if you are unsure.
To put a device in bootloader mode with USBaspLoader, tap the `RESET` button while holding down the `BOOT` button. To put a device in bootloader mode with USBaspLoader, tap the `RESET` button while holding down the `BOOT` button.
Alternatively, hold `BOOT` while inserting the USB cable. Alternatively, hold `BOOT` while inserting the USB cable.

View File

@ -34,7 +34,7 @@ On first run, the VIA code in the firmware will copy the keymap from flash memor
The simple fix for this is to clear the EEPROM. You can do this in several ways: The simple fix for this is to clear the EEPROM. You can do this in several ways:
* Hold the Bootmagic Lite key (usually top left/Escape) while plugging the board in, which will also place the board into bootloader mode; then unplug and replug the board. * Hold the Bootmagic key (usually top left/Escape) while plugging the board in, which will also place the board into bootloader mode; then unplug and replug the board.
* Press the `QK_CLEAR_EEPROM`/`EE_CLR` keycode if it is accessible on your keymap. * Press the `QK_CLEAR_EEPROM`/`EE_CLR` keycode if it is accessible on your keymap.
* Place the board into bootloader mode and hit the "Clear EEPROM" button. This may not be available for all bootloaders, and you may need to reflash the board afterwards. * Place the board into bootloader mode and hit the "Clear EEPROM" button. This may not be available for all bootloaders, and you may need to reflash the board afterwards.

View File

@ -109,7 +109,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
} }
} }
``` ```
And lastly, you want to add the `eeconfig_init_user` function, so that when the EEPROM is reset, you can specify default values, and even custom actions. To force an EEPROM reset, use the `EE_CLR` keycode or [Bootmagic Lite](features/bootmagic) functionallity. For example, if you want to set rgb layer indication by default, and save the default valued. And lastly, you want to add the `eeconfig_init_user` function, so that when the EEPROM is reset, you can specify default values, and even custom actions. To force an EEPROM reset, use the `EE_CLR` keycode or [Bootmagic](features/bootmagic) functionallity. For example, if you want to set rgb layer indication by default, and save the default valued.
```c ```c
void eeconfig_init_user(void) { // EEPROM is getting reset! void eeconfig_init_user(void) { // EEPROM is getting reset!

View File

@ -307,6 +307,50 @@ bool process_combo_key_release(uint16_t combo_index, combo_t *combo, uint8_t key
return false; return false;
} }
``` ```
### Customizable key repress
By defining `COMBO_PROCESS_KEY_REPRESS` and implementing `bool process_combo_key_repress(uint16_t combo_index, combo_t *combo, uint8_t key_index, uint16_t keycode)` you can run your custom code when you repress just released key of a combo. By combining it with custom `process_combo_event` we can for example make special handling for Alt+Tab to switch windows, which, on combo F+G activation, registers Alt and presses Tab - then we can switch windows forward by releasing G and pressing it again, or backwards with F key. Here's the full example:
```c
enum combos {
CMB_ALTTAB
};
const uint16_t PROGMEM combo_alttab[] = {KC_F, KC_G, COMBO_END};
combo_t key_combos[COMBO_LENGTH] = {
[CMB_ALTTAB] = COMBO(combo_alttab, KC_NO), // KC_NO to leave processing for process_combo_event
};
void process_combo_event(uint16_t combo_index, bool pressed) {
switch (combo_index) {
case CMB_ALTTAB:
if (pressed) {
register_mods(MOD_LALT);
tap_code(KC_TAB);
} else {
unregister_mods(MOD_LALT);
}
break;
}
}
bool process_combo_key_repress(uint16_t combo_index, combo_t *combo, uint8_t key_index, uint16_t keycode) {
switch (combo_index) {
case CMB_ALTTAB:
switch (keycode) {
case KC_F:
tap_code16(S(KC_TAB));
return true;
case KC_G:
tap_code(KC_TAB);
return true;
}
}
return false;
}
```
### Layer independent combos ### Layer independent combos
If you, for example, use multiple base layers for different key layouts, one for QWERTY, and another one for Colemak, you might want your combos to work from the same key positions on all layers. Defining the same combos again for another layout is redundant and takes more memory. The solution is to just check the keycodes from one layer. If you, for example, use multiple base layers for different key layouts, one for QWERTY, and another one for Colemak, you might want your combos to work from the same key positions on all layers. Defining the same combos again for another layout is redundant and takes more memory. The solution is to just check the keycodes from one layer.

View File

@ -1,6 +1,6 @@
# Command # Command
Command, formerly known as Magic, is a way to change your keyboard's behavior without having to flash or unplug it to use [Bootmagic Lite](bootmagic). There is a lot of overlap between this functionality and the [Magic Keycodes](../keycodes_magic). Wherever possible we encourage you to use that feature instead of Command. Command, formerly known as Magic, is a way to change your keyboard's behavior without having to flash or unplug it to use [Bootmagic](bootmagic). There is a lot of overlap between this functionality and the [Magic Keycodes](../keycodes_magic). Wherever possible we encourage you to use that feature instead of Command.
On some keyboards Command is disabled by default. If this is the case, it must be explicitly enabled in your `rules.mk`: On some keyboards Command is disabled by default. If this is the case, it must be explicitly enabled in your `rules.mk`:

View File

@ -53,7 +53,7 @@ QMK maintains [a fork of the LUFA DFU bootloader](https://github.com/qmk/lufa/tr
//#define QMK_LED E6 //#define QMK_LED E6
//#define QMK_SPEAKER C6 //#define QMK_SPEAKER C6
``` ```
Currently we do not recommend making `QMK_ESC` the same key as the one designated for [Bootmagic Lite](features/bootmagic), as holding it down will cause the MCU to loop back and forth between entering and exiting the bootloader. Currently we do not recommend making `QMK_ESC` the same key as the one designated for [Bootmagic](features/bootmagic), as holding it down will cause the MCU to loop back and forth between entering and exiting the bootloader.
The manufacturer and product strings are automatically pulled from `config.h`, with " Bootloader" appended to the product string. The manufacturer and product strings are automatically pulled from `config.h`, with " Bootloader" appended to the product string.
@ -209,7 +209,7 @@ To enable the additional features, add the following defines to your `config.h`:
//#define QMK_SPEAKER C6 //#define QMK_SPEAKER C6
``` ```
Currently we do not recommend making `QMK_ESC` the same key as the one designated for [Bootmagic Lite](features/bootmagic), as holding it down will cause the MCU to loop back and forth between entering and exiting the bootloader. Currently we do not recommend making `QMK_ESC` the same key as the one designated for [Bootmagic](features/bootmagic), as holding it down will cause the MCU to loop back and forth between entering and exiting the bootloader.
The manufacturer and product strings are automatically pulled from `config.h`, with " Bootloader" appended to the product string. The manufacturer and product strings are automatically pulled from `config.h`, with " Bootloader" appended to the product string.

View File

@ -28,6 +28,8 @@ Supported devices:
| ILI9341 | RGB LCD | 240x320 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9341_spi` | | ILI9341 | RGB LCD | 240x320 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9341_spi` |
| ILI9486 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9486_spi` | | ILI9486 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9486_spi` |
| ILI9488 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9488_spi` | | ILI9488 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9488_spi` |
| LD7032 (SPI) | Monochrome OLED | 128x40 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ld7032_spi` |
| LD7032 (I2C) | Monochrome OLED | 128x40 | I2C | `QUANTUM_PAINTER_DRIVERS += ld7032_i2c` |
| SSD1351 | RGB OLED | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ssd1351_spi` | | SSD1351 | RGB OLED | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ssd1351_spi` |
| ST7735 | RGB LCD | 132x162, 80x160 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += st7735_spi` | | ST7735 | RGB LCD | 132x162, 80x160 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += st7735_spi` |
| ST7789 | RGB LCD | 240x320, 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += st7789_spi` | | ST7789 | RGB LCD | 240x320, 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += st7789_spi` |
@ -478,6 +480,40 @@ Native color format mono2 is compatible with SH1106
SSD1306 and SH1106 are almost entirely identical, to the point of being indisinguishable by Quantum Painter. Enable SH1106 support in Quantum Painter and create SH1106 devices in firmware to perform drawing operations on SSD1306 displays. SSD1306 and SH1106 are almost entirely identical, to the point of being indisinguishable by Quantum Painter. Enable SH1106 support in Quantum Painter and create SH1106 devices in firmware to perform drawing operations on SSD1306 displays.
==== LD7032
Enabling support for the LD7032 in Quantum Painter is done by adding the following to `rules.mk`:
```make
QUANTUM_PAINTER_ENABLE = yes
# For SPI:
QUANTUM_PAINTER_DRIVERS += ld7032_spi
# For I2C:
QUANTUM_PAINTER_DRIVERS += ld7032_i2c
```
Creating a SH1106 device in firmware can then be done with the following APIs:
```c
// SPI-based LD7032:
painter_device_t qp_ld7032_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
// I2C-based LD7032:
painter_device_t qp_ld7032_make_i2c_device(uint16_t panel_width, uint16_t panel_height, uint8_t i2c_address);
```
The device handle returned from the `qp_ld7032_make_???_device` function can be used to perform all other drawing operations.
The maximum number of displays of each type can be configured by changing the following in your `config.h` (default is 1):
```c
// 3 SPI displays:
#define LD7032_NUM_SPI_DEVICES 3
// 3 I2C displays:
#define LD7032_NUM_I2C_DEVICES 3
```
Native color format mono2 is compatible with LD7032.
::::: :::::
===== Surface ===== Surface

View File

@ -99,7 +99,7 @@ To reset to the bootloader use `QK_BOOTLOADER` or `QK_BOOT` keycode or `reset_ke
## Wiping the EEPROM (Persistent Storage) ## Wiping the EEPROM (Persistent Storage)
If you're having issues with Audio, RGB Underglow, backlighting or keys acting weird, then you can reset the EEPROM (persistent setting storage). To force an EEPROM reset, use the [`EE_CLR` keycode](quantum_keycodes) or [Bootmagic Lite](features/bootmagic) functionality. If neither of those are an option, then you can use a custom macro to do so. If you're having issues with Audio, RGB Underglow, backlighting or keys acting weird, then you can reset the EEPROM (persistent setting storage). To force an EEPROM reset, use the [`EE_CLR` keycode](quantum_keycodes) or [Bootmagic](features/bootmagic) functionality. If neither of those are an option, then you can use a custom macro to do so.
To wipe the EEPROM, run `eeconfig_init()` from your function or macro to reset most of the settings to default. To wipe the EEPROM, run `eeconfig_init()` from your function or macro to reset most of the settings to default.

View File

@ -55,7 +55,7 @@ Everything below here requires a lot of foundational knowledge. Besides being ab
* **Advanced Features** * **Advanced Features**
* [Unicode](features/unicode) * [Unicode](features/unicode)
* [API](api_overview) * [API](api_overview)
* [Bootmagic Lite](features/bootmagic) * [Bootmagic](features/bootmagic)
* **Hardware** * **Hardware**
* [How Keyboards Work](how_keyboards_work) * [How Keyboards Work](how_keyboards_work)
* [How A Keyboard Matrix Works](how_a_matrix_works) * [How A Keyboard Matrix Works](how_a_matrix_works)

View File

@ -0,0 +1,411 @@
// Copyright 2023 Nick Brassel (@tzarc)
// Copyright 2023 Dasky (@daskygit)
// SPDX-License-Identifier: GPL-2.0-or-later
#include "qp_internal.h"
#include "qp_comms.h"
#include "qp_oled_panel.h"
#include "qp_ld7032.h"
#include "qp_ld7032_opcodes.h"
#include "qp_surface.h"
#include "qp_surface_internal.h"
typedef void (*ld7032_driver_comms_send_command_and_data_func)(painter_device_t device, uint8_t cmd, uint8_t data);
typedef uint32_t (*ld7032_driver_comms_send_command_and_databuf_func)(painter_device_t device, uint8_t cmd, const void *data, uint32_t byte_count);
typedef struct ld7032_comms_with_command_vtable_t {
painter_comms_vtable_t base; // must be first, so this object can be cast from the painter_comms_vtable_t* type
painter_driver_comms_send_command_func send_command;
painter_driver_comms_bulk_command_sequence bulk_command_sequence;
ld7032_driver_comms_send_command_and_data_func send_command_data;
ld7032_driver_comms_send_command_and_databuf_func send_command_databuf;
} ld7032_comms_with_command_vtable_t;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// LD7032 Internal API
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ld7032_comms_i2c_send_command_and_data(painter_device_t device, uint8_t cmd, uint8_t data) {
uint8_t buf[2] = {cmd, data};
qp_comms_i2c_send_data(device, buf, 2);
}
void ld7032_comms_i2c_bulk_command_sequence(painter_device_t device, const uint8_t *sequence, size_t sequence_len) {
uint8_t buf[32];
for (size_t i = 0; i < sequence_len;) {
uint8_t command = sequence[i];
uint8_t delay = sequence[i + 1];
uint8_t num_bytes = sequence[i + 2];
buf[0] = command;
memcpy(&buf[1], &sequence[i + 3], num_bytes);
qp_comms_i2c_send_data(device, buf, num_bytes + 1);
if (delay > 0) {
wait_ms(delay);
}
i += (3 + num_bytes);
}
}
uint32_t ld7032_comms_i2c_send_command_and_databuf(painter_device_t device, uint8_t cmd, const void *data, uint32_t byte_count) {
uint8_t buf[byte_count + 1];
memset(buf, 0, sizeof(buf));
buf[0] = cmd;
memcpy(&buf[1], data, byte_count);
return qp_comms_send(device, buf, byte_count + 1);
}
// Power control
bool qp_ld7032_power(painter_device_t device, bool power_on) {
painter_driver_t * driver = (painter_driver_t *)device;
ld7032_comms_with_command_vtable_t *comms_vtable = (ld7032_comms_with_command_vtable_t *)driver->comms_vtable;
comms_vtable->send_command_data(device, LD7032_DISP_ON_OFF, power_on ? 0x01 : 0x00);
return true;
}
// Screen clear
bool qp_ld7032_clear(painter_device_t device) {
qp_rect(device, 0, 0, 127, 127, 0, 0, 0, true); // clear memory
painter_driver_t *driver = (painter_driver_t *)device;
driver->driver_vtable->init(device, driver->rotation); // Re-init the display
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Flush helpers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ld7032_flush_0(painter_device_t device, surface_dirty_data_t *dirty, const uint8_t *framebuffer, bool inverted) {
painter_driver_t * driver = (painter_driver_t *)device;
ld7032_comms_with_command_vtable_t *comms_vtable = (ld7032_comms_with_command_vtable_t *)driver->comms_vtable;
int x_start = dirty->l >> 3;
int x_end = dirty->r >> 3;
int y_start = dirty->t;
int y_end = dirty->b;
int x_length = (x_end - x_start) + 1;
uint8_t x_view_offset = driver->offset_x >> 3;
uint8_t y_view_offset = driver->offset_y;
for (int y_pos = y_start; y_pos <= y_end; y_pos++) {
int y_new_pos = y_pos;
if (inverted) {
y_new_pos = y_end - y_pos;
}
uint8_t packet[x_length];
memcpy(packet, &framebuffer[(y_pos * (driver->panel_width >> 3)) + x_start], x_length);
uint8_t x_write_start = MIN(x_start + x_view_offset, (128 >> 3));
uint8_t x_write_end = MIN(x_end + x_view_offset, (128 >> 3));
uint8_t y_write_start = MIN(y_new_pos + y_view_offset, 39);
uint8_t y_write_end = MIN(y_new_pos + y_view_offset, 39);
comms_vtable->send_command_data(device, LD7032_X_BOX_ADR_START, x_write_start);
comms_vtable->send_command_data(device, LD7032_X_BOX_ADR_END, x_write_end);
comms_vtable->send_command_data(device, LD7032_Y_BOX_ADR_START, y_write_start);
comms_vtable->send_command_data(device, LD7032_Y_BOX_ADR_END, y_write_end);
comms_vtable->send_command_databuf(device, LD7032_DATA_RW, packet, x_length);
}
}
void ld7032_flush_90(painter_device_t device, surface_dirty_data_t *dirty, const uint8_t *framebuffer, bool inverted) {
painter_driver_t * driver = (painter_driver_t *)device;
ld7032_comms_with_command_vtable_t *comms_vtable = (ld7032_comms_with_command_vtable_t *)driver->comms_vtable;
int x_start = dirty->t >> 3;
int x_end = dirty->b >> 3;
int y_start = dirty->l;
int y_end = dirty->r;
int x_length = (x_end - x_start) + 1;
uint8_t x_view_offset = driver->offset_x >> 3;
uint8_t y_view_offset = driver->offset_y;
for (int y_pos = y_start; y_pos <= y_end; y_pos++) {
int y_new_pos = y_pos;
if (inverted) {
y_new_pos = y_end - y_pos;
}
uint8_t packet[x_length];
memset(packet, 0, sizeof(packet));
int count = 0;
for (int x_pos = x_start; x_pos <= x_end; x_pos++) {
for (int x = 0; x < 8; ++x) {
uint32_t pixel_num = (((x_pos << 3) + x) * driver->panel_height) + y_pos;
uint32_t byte_offset = pixel_num / 8;
uint8_t bit_offset = pixel_num % 8;
packet[count] |= ((framebuffer[byte_offset] & (1 << bit_offset)) >> bit_offset) << x;
}
count++;
}
uint8_t x_width = (driver->panel_width >> 3) - 1;
uint8_t x_write_start = MAX((int)x_width - x_end - x_view_offset, 0);
uint8_t x_write_end = MAX((int)x_width - x_start - x_view_offset, 0);
uint8_t y_write_start = MIN(y_new_pos + y_view_offset, 39);
uint8_t y_write_end = MIN(y_new_pos + y_view_offset, 39);
comms_vtable->send_command_data(device, LD7032_X_BOX_ADR_START, x_write_start);
comms_vtable->send_command_data(device, LD7032_X_BOX_ADR_END, x_write_end);
comms_vtable->send_command_data(device, LD7032_Y_BOX_ADR_START, y_write_start);
comms_vtable->send_command_data(device, LD7032_Y_BOX_ADR_END, y_write_end);
comms_vtable->send_command_databuf(device, LD7032_DATA_RW, packet, x_length);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Driver storage
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct ld7032_device_t {
oled_panel_painter_device_t oled;
uint8_t framebuffer[SURFACE_REQUIRED_BUFFER_BYTE_SIZE(128, 40, 1)];
} ld7032_device_t;
static ld7032_device_t ld7032_drivers[LD7032_NUM_DEVICES] = {0};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Quantum Painter API implementations
// Initialisation
__attribute__((weak)) bool qp_ld7032_init(painter_device_t device, painter_rotation_t rotation) {
ld7032_device_t *driver = (ld7032_device_t *)device;
// Change the surface geometry based on the panel rotation
if (rotation == QP_ROTATION_90 || rotation == QP_ROTATION_270) {
driver->oled.surface.base.panel_width = driver->oled.base.panel_height;
driver->oled.surface.base.panel_height = driver->oled.base.panel_width;
} else {
driver->oled.surface.base.panel_width = driver->oled.base.panel_width;
driver->oled.surface.base.panel_height = driver->oled.base.panel_height;
}
// Init the internal surface
if (!qp_init(&driver->oled.surface.base, QP_ROTATION_0)) {
qp_dprintf("Failed to init internal surface in qp_ld7032_init\n");
return false;
}
// clang-format off
const uint8_t ld7032_init_sequence[] = {
// Command, Delay, N, Data[N]
LD7032_DISP_STBY_ON_OFF, 0, 1, 0x00,
LD7032_DISP_ON_OFF, 0, 1, 0x00,
LD7032_DFRAME, 0, 1, 0x05,
//LD7032_WRITE_DIRECTION, 0, 1, 0b00001000, // 0 Right, 1 Up, 2 Vertical, 3 Bit Order, 4-7 Unused
LD7032_DISP_DIRECTION, 0, 1, 0x00,
LD7032_PEAK_WIDTH, 0, 1, 0x1F,
LD7032_PEAK_DELAY, 0, 1, 0x05,
LD7032_SCAN_MODE, 0, 1, 0x01,
LD7032_DOT_CURRENT, 0, 1, 0x1f,
LD7032_VDD_SEL, 0, 1, 0x01,
};
// clang-format on
qp_comms_bulk_command_sequence(device, ld7032_init_sequence, sizeof(ld7032_init_sequence));
uint8_t display_y_start = 40 - driver->oled.base.panel_height;
uint8_t display_x_start = (128 - driver->oled.base.panel_width) / 2;
// clang-format off
uint8_t ld7032_memory_setup[] = {
// Command, Delay, N, Data[N]
LD7032_DISP_SIZE_X, 0, 2, 0x00, 0x7F,
LD7032_DISP_SIZE_Y, 0, 2, 0x00, 0x27,
LD7032_X_DISP_START, 0, 1, 0x0,
LD7032_Y_DISP_START, 0, 1, 0x0,
};
// clang-format on
ld7032_memory_setup[3] = display_x_start;
ld7032_memory_setup[4] = display_x_start + driver->oled.base.panel_width - 1;
ld7032_memory_setup[8] = display_y_start;
ld7032_memory_setup[9] = display_y_start + driver->oled.base.panel_height - 1;
ld7032_memory_setup[13] = ld7032_memory_setup[4] + 1;
ld7032_memory_setup[17] = driver->oled.base.panel_height;
qp_comms_bulk_command_sequence(device, ld7032_memory_setup, sizeof(ld7032_memory_setup));
uint8_t write_direction = 0;
switch (rotation) {
default:
case QP_ROTATION_0:
write_direction = 0b00001000;
break;
case QP_ROTATION_90:
write_direction = 0b00000001;
break;
case QP_ROTATION_180:
write_direction = 0b00000001;
break;
case QP_ROTATION_270:
write_direction = 0b00001000;
break;
}
painter_driver_t * pdriver = (painter_driver_t *)device;
ld7032_comms_with_command_vtable_t *comms_vtable = (ld7032_comms_with_command_vtable_t *)pdriver->comms_vtable;
comms_vtable->send_command_data(device, LD7032_WRITE_DIRECTION, write_direction);
qp_ld7032_power(device, true);
return true;
}
// Screen flush
bool qp_ld7032_flush(painter_device_t device) {
ld7032_device_t *driver = (ld7032_device_t *)device;
if (!driver->oled.surface.dirty.is_dirty) {
return true;
}
switch (driver->oled.base.rotation) {
default:
case QP_ROTATION_0:
ld7032_flush_0(device, &driver->oled.surface.dirty, driver->framebuffer, false);
break;
case QP_ROTATION_180:
ld7032_flush_0(device, &driver->oled.surface.dirty, driver->framebuffer, true);
break;
case QP_ROTATION_90:
ld7032_flush_90(device, &driver->oled.surface.dirty, driver->framebuffer, false);
break;
case QP_ROTATION_270:
ld7032_flush_90(device, &driver->oled.surface.dirty, driver->framebuffer, true);
break;
}
// Clear the dirty area
qp_flush(&driver->oled.surface);
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Driver vtable
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const painter_driver_vtable_t ld7032_driver_vtable = {
.init = qp_ld7032_init,
.power = qp_ld7032_power,
.clear = qp_ld7032_clear,
.flush = qp_ld7032_flush,
.pixdata = qp_oled_panel_passthru_pixdata,
.viewport = qp_oled_panel_passthru_viewport,
.palette_convert = qp_oled_panel_passthru_palette_convert,
.append_pixels = qp_oled_panel_passthru_append_pixels,
.append_pixdata = qp_oled_panel_passthru_append_pixdata,
};
#ifdef QUANTUM_PAINTER_LD7032_SPI_ENABLE
const ld7032_comms_with_command_vtable_t ld7032_spi_comms_vtable = {
.base =
{
.comms_init = qp_comms_spi_dc_reset_init,
.comms_start = qp_comms_spi_start,
.comms_send = qp_comms_spi_dc_reset_send_data,
.comms_stop = qp_comms_spi_stop,
},
.send_command = qp_comms_spi_dc_reset_send_command,
.send_command_data = qp_comms_command_databyte,
.send_command_databuf = qp_comms_command_databuf,
.bulk_command_sequence = qp_comms_spi_dc_reset_bulk_command_sequence,
};
// Factory function for creating a handle to the LD7032 device
painter_device_t qp_ld7032_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode) {
for (uint32_t i = 0; i < LD7032_NUM_DEVICES; ++i) {
ld7032_device_t *driver = &ld7032_drivers[i];
if (!driver->oled.base.driver_vtable) {
painter_device_t surface = qp_make_mono1bpp_surface_advanced(&driver->oled.surface, 1, panel_width, panel_height, driver->framebuffer);
if (!surface) {
return NULL;
}
// Setup the OLED device
driver->oled.base.driver_vtable = (const painter_driver_vtable_t *)&ld7032_driver_vtable;
driver->oled.base.comms_vtable = (const painter_comms_vtable_t *)&ld7032_spi_comms_vtable;
driver->oled.base.native_bits_per_pixel = 1; // 1bpp mono
driver->oled.base.panel_width = panel_width;
driver->oled.base.panel_height = panel_height;
driver->oled.base.rotation = QP_ROTATION_0;
driver->oled.base.offset_x = 0;
driver->oled.base.offset_y = 0;
// SPI and other pin configuration
driver->oled.base.comms_config = &driver->oled.spi_dc_reset_config;
driver->oled.spi_dc_reset_config.spi_config.chip_select_pin = chip_select_pin;
driver->oled.spi_dc_reset_config.spi_config.divisor = spi_divisor;
driver->oled.spi_dc_reset_config.spi_config.lsb_first = false;
driver->oled.spi_dc_reset_config.spi_config.mode = spi_mode;
driver->oled.spi_dc_reset_config.dc_pin = dc_pin;
driver->oled.spi_dc_reset_config.reset_pin = reset_pin;
driver->oled.spi_dc_reset_config.command_params_uses_command_pin = true;
if (!qp_internal_register_device((painter_device_t)driver)) {
memset(driver, 0, sizeof(ld7032_device_t));
return NULL;
}
return (painter_device_t)driver;
}
}
return NULL;
}
#endif // QUANTUM_PAINTER_LD7032_SPI_ENABLE
#ifdef QUANTUM_PAINTER_LD7032_I2C_ENABLE
const ld7032_comms_with_command_vtable_t ld7032_i2c_comms_vtable = {
.base =
{
.comms_init = qp_comms_i2c_init,
.comms_start = qp_comms_i2c_start,
.comms_send = qp_comms_i2c_send_data,
.comms_stop = qp_comms_i2c_stop,
},
.send_command = NULL,
.send_command_data = ld7032_comms_i2c_send_command_and_data,
.send_command_databuf = ld7032_comms_i2c_send_command_and_databuf,
.bulk_command_sequence = ld7032_comms_i2c_bulk_command_sequence,
};
// Factory function for creating a handle to the LD7032 device
painter_device_t qp_ld7032_make_i2c_device(uint16_t panel_width, uint16_t panel_height, uint8_t i2c_address) {
for (uint32_t i = 0; i < LD7032_NUM_DEVICES; ++i) {
ld7032_device_t *driver = &ld7032_drivers[i];
if (!driver->oled.base.driver_vtable) {
painter_device_t surface = qp_make_mono1bpp_surface_advanced(&driver->oled.surface, 1, panel_width, panel_height, driver->framebuffer);
if (!surface) {
return NULL;
}
// Setup the OLED device
driver->oled.base.driver_vtable = (const painter_driver_vtable_t *)&ld7032_driver_vtable;
driver->oled.base.comms_vtable = (const painter_comms_vtable_t *)&ld7032_i2c_comms_vtable;
driver->oled.base.native_bits_per_pixel = 1; // 1bpp mono
driver->oled.base.panel_width = panel_width;
driver->oled.base.panel_height = panel_height;
driver->oled.base.rotation = QP_ROTATION_0;
driver->oled.base.offset_x = 0;
driver->oled.base.offset_y = 0;
// I2C configuration
driver->oled.base.comms_config = &driver->oled.i2c_config;
driver->oled.i2c_config.chip_address = i2c_address;
if (!qp_internal_register_device((painter_device_t)driver)) {
memset(driver, 0, sizeof(ld7032_device_t));
return NULL;
}
return (painter_device_t)driver;
}
}
return NULL;
}
#endif // QUANTUM_PAINTER_LD7032_SPI_ENABLE

View File

@ -0,0 +1,66 @@
// Copyright 2023 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "gpio.h"
#include "qp_internal.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Quantum Painter LD7032 configurables (add to your keyboard's config.h)
#if defined(QUANTUM_PAINTER_LD7032_SPI_ENABLE) && !defined(LD7032_NUM_SPI_DEVICES)
/**
* @def This controls the maximum number of SPI LD7032 devices that Quantum Painter can communicate with at any one time.
* Increasing this number allows for multiple displays to be used.
*/
# define LD7032_NUM_SPI_DEVICES 1
#else
# define LD7032_NUM_SPI_DEVICES 0
#endif
#if defined(QUANTUM_PAINTER_LD7032_I2C_ENABLE) && !defined(LD7032_NUM_I2C_DEVICES)
/**
* @def This controls the maximum number of I2C LD7032 devices that Quantum Painter can communicate with at any one time.
* Increasing this number allows for multiple displays to be used.
*/
# define LD7032_NUM_I2C_DEVICES 1
#else
# define LD7032_NUM_I2C_DEVICES 0
#endif
#define LD7032_NUM_DEVICES ((LD7032_NUM_SPI_DEVICES) + (LD7032_NUM_I2C_DEVICES))
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Quantum Painter LD7032 device factories
#ifdef QUANTUM_PAINTER_LD7032_SPI_ENABLE
/**
* Factory method for an LD7032 SPI LCD device.
*
* @param panel_width[in] the width of the display in pixels (usually 128)
* @param panel_height[in] the height of the display in pixels (usually 64)
* @param chip_select_pin[in] the GPIO pin used for SPI chip select
* @param dc_pin[in] the GPIO pin used for D/C control
* @param reset_pin[in] the GPIO pin used for RST
* @param spi_divisor[in] the SPI divisor to use when communicating with the display
* @param spi_mode[in] the SPI mode to use when communicating with the display
* @return the device handle used with all drawing routines in Quantum Painter
*/
painter_device_t qp_ld7032_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
#endif // QUANTUM_PAINTER_LD7032_SPI_ENABLE
#ifdef QUANTUM_PAINTER_LD7032_I2C_ENABLE
/**
* Factory method for an LD7032 I2C LCD device.
*
* @param panel_width[in] the width of the display in pixels (usually 128)
* @param panel_height[in] the height of the display in pixels (usually 64)
* @param i2c_address[in] the I2C address to use
* @return the device handle used with all drawing routines in Quantum Painter
*/
painter_device_t qp_ld7032_make_i2c_device(uint16_t panel_width, uint16_t panel_height, uint8_t i2c_address);
#endif // QUANTUM_PAINTER_LD7032_I2C_ENABLE

View File

@ -0,0 +1,45 @@
// Copyright 2023 Dasky (@daskygit)
// SPDX-License-Identifier: GPL-2.0-or-later
typedef enum {
LD7032_SOFTRES = 0x01,
LD7032_DISP_ON_OFF = 0x02,
LD7032_DATA_RW = 0x08,
LD7032_DISP_DIRECTION = 0x09,
LD7032_IFMODE = 0x0D,
LD7032_PEAK_WIDTH = 0x10,
LD7032_DOT_CURRENT = 0x12,
LD7032_SCAN_MODE = 0x13,
LD7032_DISP_STBY_ON_OFF = 0x14,
LD7032_PEAK_DELAY = 0x16,
LD7032_ROW_SCAN = 0x17,
LD7032_PRE_C_WIDTH = 0x18,
LD7032_DFRAME = 0x1A,
LD7032_DATA_REVERSE = 0x1C,
LD7032_WRITE_DIRECTION = 0x1D,
LD7032_READREG = 0x20,
LD7032_DISP_SIZE_X = 0x30,
LD7032_DISP_SIZE_Y = 0x32,
LD7032_X_BOX_ADR_START = 0x34,
LD7032_X_BOX_ADR_END = 0x35,
LD7032_Y_BOX_ADR_START = 0x36,
LD7032_Y_BOX_ADR_END = 0x37,
LD7032_X_DISP_START = 0x38,
LD7032_Y_DISP_START = 0x39,
LD7032_XTALK_EN = 0x3A,
LD7032_XTALK_REF = 0x3B,
LD7032_AGING_EN = 0x3C,
LD7032_VDD_SEL = 0x3D,
LD7032_TESTCNT0 = 0x3E,
LD7032_VCC_R_SEL = 0x3F,
LD7032_PRE_C_SELECT = 0x44,
LD7032_ROW_OVERLAP = 0x48,
LD7032_S_SLEEP_TIMER = 0xC0,
LD7032_S_SLEEP_START = 0xC2,
LD7032_S_STEP_TIMER = 0xC3,
LD7032_S_STEP_UNIT = 0xC4,
LD7032_S_CONDITION = 0xCC,
LD7032_S_START_STOP = 0xCD,
LD7032_S_SELECT = 0xCE,
LD7032_TESTCNT1 = 0xF0, //-0xFF
} ld7032_opcodes;

View File

@ -67,14 +67,15 @@
#define REG_SROM_Load_Burst 0x62 #define REG_SROM_Load_Burst 0x62
#define REG_Pixel_Burst 0x64 #define REG_Pixel_Burst 0x64
#define MIN_CPI 200 #define MIN_CPI 200
#define MAX_CPI 8200 #define MAX_CPI 8200
#define CPI_STEP 200 #define CPI_STEP 200
#define CLAMP_CPI(value) value<MIN_CPI ? MIN_CPI : value> MAX_CPI ? MAX_CPI : value #define CLAMP_CPI(value) value<MIN_CPI ? MIN_CPI : value> MAX_CPI ? MAX_CPI : value
#define US_BETWEEN_WRITES 120 #define US_BETWEEN_WRITES 120
#define US_BETWEEN_READS 20 #define US_BETWEEN_READS 20
#define US_BEFORE_MOTION 100 #define US_DELAY_AFTER_ADDR 100
#define MSB1 0x80 #define US_BEFORE_MOTION 100
#define MSB1 0x80
// clang-format on // clang-format on
void adns9800_spi_start(void) { void adns9800_spi_start(void) {
@ -92,6 +93,7 @@ void adns9800_write(uint8_t reg_addr, uint8_t data) {
uint8_t adns9800_read(uint8_t reg_addr) { uint8_t adns9800_read(uint8_t reg_addr) {
adns9800_spi_start(); adns9800_spi_start();
spi_write(reg_addr & 0x7f); spi_write(reg_addr & 0x7f);
wait_us(US_DELAY_AFTER_ADDR);
uint8_t data = spi_read(); uint8_t data = spi_read();
spi_stop(); spi_stop();
wait_us(US_BETWEEN_READS); wait_us(US_BETWEEN_READS);

View File

@ -8,6 +8,8 @@ A TKL PCB attempting a87 compatibility with different switch and layout-options.
Make example for this keyboard (after setting up your build environment): Make example for this keyboard (after setting up your build environment):
make 4pplet/waffling80/rev_a:default make 4pplet/waffling80/rev_a:default
make 4pplet/waffling80/rev_b:default
make 4pplet/waffling80/rev_b_ansi:default
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs). See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).

View File

@ -0,0 +1,19 @@
/*
Copyright 2022 Stefan Sundin "4pplet" <mail@4pplet.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#define WS2812_EXTERNAL_PULLUP

View File

@ -0,0 +1,29 @@
{
"keyboard_name": "waffling80 Rev B ANSI HS",
"usb": {
"pid": "0x0017",
"device_version": "0.0.1"
},
"rgblight": {
"saturation_steps": 8,
"brightness_steps": 8,
"led_count": 2
},
"features": {
"bootmagic": true,
"extrakey": true,
"mousekey": true,
"nkro": true,
"rgblight": true
},
"ws2812": {
"pin": "A8"
},
"matrix_pins": {
"cols": ["B2", "B1", "B0", "A7", "A6", "A3", "B9", "B8"],
"rows": ["B13", "B12", "A5", "A4", "A2", "A1", "F0", "C15", "C13", "C14", "F1", "A0"]
},
"diode_direction": "COL2ROW",
"processor": "STM32F072",
"bootloader": "stm32-dfu"
}

View File

@ -0,0 +1,18 @@
# waffling80
A TKL PCB attempting a87 and a88 compatibility with different switch and layout-options.
* Keyboard Maintainer: [4pplet](https://github.com/4pplet)
* Hardware Supported: [waffling80](https://github.com/4pplet/waffling80)
Make example for this keyboard (after setting up your build environment):
make 4pplet/waffling80/rev_b_ansi:default
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
How to enter bootloader (DFU):
* Hold the reset-header for a few seconds on the back of the PCB for keyboard to enter DFU. When in DFU, it's ready to flash the firmware.
Alternative option if the firmware is already pre-flashed:
* Unplug your keyboard, hold down the Esc key, plug in your keyboard and wait a second before releasing the keys. The keyboard will enter DFU and is ready to flash the firmware.

View File

@ -0,0 +1,47 @@
/*
Copyright 2024 Stefan Sundin "4pplet" <mail@4pplet.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rev_b_ansi.h"
bool led_update_kb(led_t led_state) {
bool res = led_update_user(led_state);
if (SCROLL_LOCK_ENABLE && res) {
if(led_state.scroll_lock) {
#ifdef SCROLL_LOCK_COLOR
rgblight_sethsv_at(SCROLL_LOCK_COLOR, 0);
#else
rgblight_sethsv_at(rgblight_get_hue(),rgblight_get_sat(),rgblight_get_val(), 0);
#endif
}
else {
rgblight_sethsv_at(HSV_OFF, 0);
}
}
if (CAPS_LOCK_ENABLE && res) {
if(led_state.caps_lock) {
#ifdef CAPS_LOCK_COLOR
rgblight_sethsv_at(CAPS_LOCK_COLOR, 1);
#else
rgblight_sethsv_at(rgblight_get_hue(),rgblight_get_sat(),rgblight_get_val(), 1);
#endif
}
else{
rgblight_sethsv_at(HSV_OFF, 1);
}
}
return res;
}

View File

@ -0,0 +1,26 @@
/*
Copyright 2022 Stefan Sundin "4pplet" <mail@4pplet.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#define CAPS_LOCK_ENABLE 1
#define SCROLL_LOCK_ENABLE 1
// If colors are defined, they will be static. If not defined, color for incicators can be set in VIA.
//#define CAPS_LOCK_COLOR HSV_GREEN
//#define SCROLL_LOCK_COLOR HSV_GREEN
#include "quantum.h"

View File

@ -0,0 +1,2 @@
# Wildcard to allow APM32 MCU
DFU_SUFFIX_ARGS = -p FFFF -v FFFF

View File

@ -40,7 +40,7 @@
"static_gradient": true, "static_gradient": true,
"twinkle": true "twinkle": true
}, },
"led_count": 22 "led_count": 19
}, },
"usb": { "usb": {
"device_version": "0.0.1", "device_version": "0.0.1",

View File

@ -136,7 +136,7 @@
{"matrix": [0, 10], "x": 10, "y": 0}, {"matrix": [0, 10], "x": 10, "y": 0},
{"matrix": [0, 11], "x": 11, "y": 0}, {"matrix": [0, 11], "x": 11, "y": 0},
{"matrix": [0, 12], "x": 12, "y": 0}, {"matrix": [0, 12], "x": 12, "y": 0},
{"matrix": [0, 14], "x": 13, "y": 0, "w": 2}, {"matrix": [0, 13], "x": 13, "y": 0, "w": 2},
{"matrix": [0, 15], "x": 15, "y": 0}, {"matrix": [0, 15], "x": 15, "y": 0},
{"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5}, {"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"matrix": [1, 1], "x": 1.5, "y": 1}, {"matrix": [1, 1], "x": 1.5, "y": 1},
@ -279,7 +279,7 @@
{"matrix": [0, 10], "x": 10, "y": 0}, {"matrix": [0, 10], "x": 10, "y": 0},
{"matrix": [0, 11], "x": 11, "y": 0}, {"matrix": [0, 11], "x": 11, "y": 0},
{"matrix": [0, 12], "x": 12, "y": 0}, {"matrix": [0, 12], "x": 12, "y": 0},
{"matrix": [0, 14], "x": 13, "y": 0, "w": 2}, {"matrix": [0, 13], "x": 13, "y": 0, "w": 2},
{"matrix": [0, 15], "x": 15, "y": 0}, {"matrix": [0, 15], "x": 15, "y": 0},
{"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5}, {"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"matrix": [1, 1], "x": 1.5, "y": 1}, {"matrix": [1, 1], "x": 1.5, "y": 1},
@ -420,7 +420,7 @@
{"matrix": [0, 10], "x": 10, "y": 0}, {"matrix": [0, 10], "x": 10, "y": 0},
{"matrix": [0, 11], "x": 11, "y": 0}, {"matrix": [0, 11], "x": 11, "y": 0},
{"matrix": [0, 12], "x": 12, "y": 0}, {"matrix": [0, 12], "x": 12, "y": 0},
{"matrix": [0, 14], "x": 13, "y": 0, "w": 2}, {"matrix": [0, 13], "x": 13, "y": 0, "w": 2},
{"matrix": [0, 15], "x": 15, "y": 0}, {"matrix": [0, 15], "x": 15, "y": 0},
{"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5}, {"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"matrix": [1, 1], "x": 1.5, "y": 1}, {"matrix": [1, 1], "x": 1.5, "y": 1},
@ -565,7 +565,7 @@
{"matrix": [0, 10], "x": 10, "y": 0}, {"matrix": [0, 10], "x": 10, "y": 0},
{"matrix": [0, 11], "x": 11, "y": 0}, {"matrix": [0, 11], "x": 11, "y": 0},
{"matrix": [0, 12], "x": 12, "y": 0}, {"matrix": [0, 12], "x": 12, "y": 0},
{"matrix": [0, 14], "x": 13, "y": 0, "w": 2}, {"matrix": [0, 13], "x": 13, "y": 0, "w": 2},
{"matrix": [0, 15], "x": 15, "y": 0}, {"matrix": [0, 15], "x": 15, "y": 0},
{"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5}, {"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"matrix": [1, 1], "x": 1.5, "y": 1}, {"matrix": [1, 1], "x": 1.5, "y": 1},

View File

@ -0,0 +1,17 @@
// Copyright 2024 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#ifdef POINTING_DEVICE_ENABLE
# define POINTING_DEVICE_SCLK_PIN D0
# define POINTING_DEVICE_SDIO_PIN D1
#endif
#ifdef AUDIO_ENABLE
# define AUDIO_PIN B5
#endif
#ifdef OLED_ENABLE
# define OLED_DISPLAY_128X64
# define OLED_FONT_H "keyboards/geigeigeist/klor/glcdfont.c"
#endif

View File

@ -0,0 +1,16 @@
// Copyright 2024 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include "progmem.h"
static const unsigned char PROGMEM font[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x00, 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x00, 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00, 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00, 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x00, 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, 0x00, 0x18, 0x3C, 0x18, 0x00, 0x00, 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, 0x00, 0x18, 0x24, 0x18, 0x00, 0x00, 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x00, 0x30, 0x48, 0x3A, 0x06, 0x0E, 0x00, 0x26, 0x29, 0x79, 0x29, 0x26, 0x00, 0x40, 0x7F, 0x05, 0x05, 0x07, 0x00, 0x40, 0x7F, 0x05, 0x25, 0x3F, 0x00, 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x00, 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x00, 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x00, 0x14, 0x22, 0x7F, 0x22, 0x14, 0x00, 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, 0x00, 0x66, 0x89, 0x95, 0x6A, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x94, 0xB6, 0xFF, 0xB6, 0x94, 0x00, 0x08, 0x0C, 0x7E, 0x0C, 0x08, 0x00,
0x10, 0x30, 0x7E, 0x30, 0x10, 0x00, 0x08, 0x08, 0x3E, 0x1C, 0x08, 0x00, 0x08, 0x1C, 0x3E, 0x08, 0x08, 0x00, 0x1E, 0x10, 0x10, 0x10, 0x10, 0x00, 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x00, 0x30, 0x38, 0x3E, 0x38, 0x30, 0x00, 0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x14, 0x3E, 0x14, 0x3E, 0x14, 0x00, 0x2E, 0x2A, 0x7F, 0x2A, 0x3A, 0x00, 0x20, 0x12, 0x08, 0x24, 0x02, 0x00, 0x37, 0x49, 0x49, 0x37, 0x50, 0x00, 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x80, 0x70, 0x30, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x7F, 0x51, 0x49, 0x45, 0x7F, 0x00, 0x08, 0x04, 0x02, 0x7F, 0x00, 0x00,
0x71, 0x49, 0x49, 0x49, 0x4F, 0x00, 0x41, 0x41, 0x49, 0x49, 0x77, 0x00, 0x0F, 0x10, 0x10, 0x10, 0x7F, 0x00, 0x4F, 0x49, 0x49, 0x49, 0x71, 0x00, 0x7E, 0x49, 0x49, 0x49, 0x70, 0x00, 0x01, 0x01, 0x71, 0x09, 0x07, 0x00, 0x77, 0x49, 0x49, 0x49, 0x77, 0x00, 0x07, 0x49, 0x49, 0x49, 0x3F, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, 0x41, 0x22, 0x14, 0x08, 0x00, 0x01, 0x01, 0x59, 0x09, 0x0F, 0x00, 0x7F, 0x41, 0x5D, 0x59, 0x4F, 0x00, 0x7F, 0x09, 0x09, 0x09, 0x7F, 0x00, 0x7F, 0x49, 0x49, 0x49, 0x76, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x41, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7E, 0x00, 0x7F, 0x49, 0x49, 0x49, 0x49, 0x00, 0x7F, 0x09, 0x09, 0x09, 0x09, 0x00, 0x7F, 0x41, 0x41, 0x49, 0x7B, 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x70, 0x40, 0x40, 0x40, 0x7F, 0x00,
0x7F, 0x08, 0x08, 0x08, 0x77, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, 0x7F, 0x01, 0x1F, 0x01, 0x7F, 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x7F, 0x09, 0x09, 0x09, 0x0F, 0x00, 0x7F, 0x41, 0x71, 0x41, 0x7F, 0x00, 0x7F, 0x09, 0x09, 0x19, 0x6F, 0x00, 0x47, 0x49, 0x49, 0x49, 0x79, 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, 0x7F, 0x40, 0x7F, 0x40, 0x7F, 0x00, 0x77, 0x08, 0x08, 0x08, 0x77, 0x00, 0x4F, 0x48, 0x48, 0x48, 0x7F, 0x00, 0x61, 0x51, 0x49, 0x45, 0x43, 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x60, 0x54, 0x54, 0x54, 0x7C, 0x00, 0x7F, 0x44, 0x44, 0x44, 0x78, 0x00, 0x7C, 0x44, 0x44, 0x44, 0x44, 0x00,
0x78, 0x44, 0x44, 0x44, 0x7F, 0x00, 0x7C, 0x54, 0x54, 0x54, 0x5C, 0x00, 0x08, 0x7F, 0x09, 0x09, 0x09, 0x00, 0x38, 0xA4, 0xA4, 0xA4, 0xFC, 0x00, 0x7F, 0x04, 0x04, 0x04, 0x78, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x70, 0x40, 0x40, 0x7D, 0x00, 0x00, 0x7F, 0x08, 0x08, 0x08, 0x76, 0x00, 0x00, 0x00, 0x7F, 0x40, 0x00, 0x00, 0x7C, 0x04, 0x7C, 0x04, 0x7C, 0x00, 0x7C, 0x04, 0x04, 0x04, 0x78, 0x00, 0x7C, 0x44, 0x44, 0x44, 0x7C, 0x00, 0xFC, 0x24, 0x24, 0x24, 0x38, 0x00, 0x38, 0x24, 0x24, 0x24, 0xFC, 0x00, 0x7C, 0x04, 0x04, 0x04, 0x04, 0x00, 0x5C, 0x54, 0x54, 0x54, 0x74, 0x00, 0x04, 0x04, 0x7F, 0x04, 0x04, 0x00, 0x7C, 0x40, 0x40, 0x40, 0x7C, 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, 0x7C, 0x40, 0x7C, 0x40, 0x7C, 0x00, 0x6C, 0x10, 0x10, 0x10, 0x6C, 0x00, 0xBC, 0xA0, 0xA0, 0xA0, 0xFC, 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00,
0x00, 0x41, 0x36, 0x08, 0x00, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x00, 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00, 0x00, 0x00, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFE, 0xFF, 0x9F, 0x0F, 0x0F, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0x0F, 0x0F, 0x9F, 0xFF, 0xFE, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x10, 0x08, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x04, 0x08, 0x10, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, 0x7F, 0x51, 0x55, 0x55, 0x45, 0x7F, 0x41, 0x5F, 0x5F, 0x5F, 0x7F, 0x00, 0x7F, 0x41, 0x7B, 0x77, 0x41, 0x7F, 0x41, 0x5F, 0x5F, 0x5F, 0x7F, 0x00, 0x7F, 0x41, 0x5D, 0x5D, 0x5D, 0x7F, 0x41, 0x5F, 0x5F, 0x5F, 0x7F, 0x00, 0xC0, 0xE0, 0xF0, 0xF0, 0xF0, 0xE0,
0xE6, 0xF7, 0xF3, 0xF0, 0x60, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0xF8, 0x1C, 0xDE, 0x1F, 0xFF, 0xFF, 0xFF, 0x1F, 0xDE, 0x1C, 0xF8, 0x00, 0xC0, 0xE2, 0xB4, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xB4, 0xE2, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0x87, 0xE1, 0xF9, 0xF9, 0xE1, 0x87, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xC0, 0x30, 0x0C, 0x33, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0x00, 0xFF, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0xC8, 0x08, 0x08, 0x0F,
0x7E, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x78, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x24, 0x24, 0x12, 0x12, 0x24, 0x24, 0x48, 0x48, 0x24, 0x24, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x3F, 0x7F, 0x7F, 0x3F, 0x3F, 0x7F, 0x7F, 0x38, 0x10, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x0F, 0x14, 0x21, 0x40, 0x45, 0x41, 0x45, 0x40, 0x21, 0x14, 0x0F, 0x00, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x02, 0x04, 0x08, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x30, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x1C, 0x3E, 0x3E, 0x3E, 0x1C, 0x00, 0x3E, 0x1C, 0x1C, 0x08, 0x08, 0x00, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

View File

@ -0,0 +1,167 @@
{
"manufacturer": "Geigeigeist",
"keyboard_name": "Klor",
"maintainer": "waffle87",
"build": {
"lto": true
},
"development_board": "elite_c",
"diode_direction": "COL2ROW",
"encoder": {
"rotary": [
{"pin_a": "F5", "pin_b": "F4"}
]
},
"features": {
"bootmagic": true,
"encoder": true,
"extrakey": true,
"haptic": true,
"mousekey": true,
"oled": true,
"pointing_device": false,
"rgb_matrix": true,
"audio": false
},
"haptic": {
"driver": "drv2605l"
},
"matrix_pins": {
"cols": ["F6", "F7", "B1", "B3", "B2", "B6"],
"rows": ["C6", "D7", "E6", "B4"]
},
"rgb_matrix": {
"driver": "ws2812",
"animations": {
"alphas_mods": true,
"band_sat": true,
"band_val": true,
"breathing": true,
"gradient_left_right": true,
"gradient_up_down": true
},
"layout": [
{"matrix": [3, 4], "x": 102, "y": 63, "flags": 1},
{"matrix": [3, 3], "x": 89, "y": 54, "flags": 1},
{"matrix": [3, 2], "x": 74, "y": 49, "flags": 1},
{"matrix": [2, 5], "x": 75, "y": 34, "flags": 4},
{"matrix": [1, 5], "x": 75, "y": 21, "flags": 4},
{"matrix": [0, 5], "x": 75, "y": 8, "flags": 4},
{"matrix": [0, 4], "x": 60, "y": 6, "flags": 4},
{"matrix": [1, 4], "x": 60, "y": 19, "flags": 4},
{"matrix": [2, 4], "x": 60, "y": 32, "flags": 4},
{"matrix": [3, 1], "x": 58, "y": 48, "flags": 1},
{"matrix": [2, 3], "x": 46, "y": 25, "flags": 4},
{"matrix": [1, 3], "x": 46, "y": 12, "flags": 4},
{"matrix": [0, 3], "x": 46, "y": 0, "flags": 4},
{"matrix": [0, 2], "x": 29, "y": 7, "flags": 4},
{"matrix": [1, 2], "x": 30, "y": 20, "flags": 4},
{"matrix": [2, 2], "x": 31, "y": 33, "flags": 4},
{"matrix": [2, 1], "x": 17, "y": 42, "flags": 4},
{"matrix": [1, 1], "x": 15, "y": 30, "flags": 4},
{"matrix": [0, 1], "x": 13, "y": 17, "flags": 4},
{"matrix": [1, 0], "x": 0, "y": 28, "flags": 1},
{"matrix": [2, 0], "x": 3, "y": 41, "flags": 1},
{"matrix": [7, 4], "x": 122, "y": 63, "flags": 1},
{"matrix": [7, 3], "x": 135, "y": 54, "flags": 1},
{"matrix": [7, 2], "x": 150, "y": 49, "flags": 1},
{"matrix": [6, 5], "x": 149, "y": 34, "flags": 4},
{"matrix": [5, 5], "x": 149, "y": 21, "flags": 4},
{"matrix": [4, 5], "x": 149, "y": 8, "flags": 4},
{"matrix": [4, 4], "x": 163, "y": 6, "flags": 4},
{"matrix": [5, 4], "x": 163, "y": 19, "flags": 4},
{"matrix": [6, 4], "x": 163, "y": 32, "flags": 4},
{"matrix": [7, 1], "x": 166, "y": 48, "flags": 1},
{"matrix": [6, 3], "x": 178, "y": 25, "flags": 4},
{"matrix": [5, 3], "x": 178, "y": 12, "flags": 4},
{"matrix": [4, 3], "x": 178, "y": 0, "flags": 4},
{"matrix": [4, 2], "x": 195, "y": 7, "flags": 4},
{"matrix": [5, 2], "x": 194, "y": 20, "flags": 4},
{"matrix": [6, 2], "x": 193, "y": 33, "flags": 4},
{"matrix": [4, 1], "x": 206, "y": 42, "flags": 4},
{"matrix": [5, 1], "x": 209, "y": 30, "flags": 4},
{"matrix": [6, 1], "x": 211, "y": 17, "flags": 4},
{"matrix": [5, 0], "x": 224, "y": 28, "flags": 1},
{"matrix": [6, 0], "x": 221, "y": 41, "flags": 1}
],
"split_count": [21, 21]
},
"split": {
"enabled": true,
"encoder": {
"right": {
"rotary": [
{"pin_a": "F4", "pin_b": "F5"}
]
}
},
"serial": {
"pin": "D2"
},
"transport": {
"sync": {
"oled": true,
"matrix_state": true
}
}
},
"url": "https://github.com/geigeigeist/klor",
"usb": {
"device_version": "1.0.0",
"pid": "0x0001",
"vid": "0x3A3C"
},
"ws2812": {
"pin": "D3"
},
"layouts": {
"LAYOUT": {
"layout": [
{"label": "L01", "matrix": [0, 1], "x": 1, "y": 0},
{"label": "L02", "matrix": [0, 2], "x": 2, "y": 0},
{"label": "L03", "matrix": [0, 3], "x": 3, "y": 0},
{"label": "L04", "matrix": [0, 4], "x": 4, "y": 0},
{"label": "L05", "matrix": [0, 5], "x": 5, "y": 0},
{"label": "R00", "matrix": [4, 5], "x": 9, "y": 0},
{"label": "R01", "matrix": [4, 4], "x": 10, "y": 0},
{"label": "R02", "matrix": [4, 3], "x": 11, "y": 0},
{"label": "R03", "matrix": [4, 2], "x": 12, "y": 0},
{"label": "R04", "matrix": [4, 1], "x": 13, "y": 0},
{"label": "L10", "matrix": [1, 0], "x": 0, "y": 1},
{"label": "L11", "matrix": [1, 1], "x": 1, "y": 1},
{"label": "L12", "matrix": [1, 2], "x": 2, "y": 1},
{"label": "L13", "matrix": [1, 3], "x": 3, "y": 1},
{"label": "L14", "matrix": [1, 4], "x": 4, "y": 1},
{"label": "L15", "matrix": [1, 5], "x": 5, "y": 1},
{"label": "R10", "matrix": [5, 5], "x": 9, "y": 1},
{"label": "R11", "matrix": [5, 4], "x": 10, "y": 1},
{"label": "R12", "matrix": [5, 3], "x": 11, "y": 1},
{"label": "R13", "matrix": [5, 2], "x": 12, "y": 1},
{"label": "R14", "matrix": [5, 1], "x": 13, "y": 1},
{"label": "R15", "matrix": [5, 0], "x": 14, "y": 1},
{"label": "L20", "matrix": [2, 0], "x": 0, "y": 2},
{"label": "L21", "matrix": [2, 1], "x": 1, "y": 2},
{"label": "L22", "matrix": [2, 2], "x": 2, "y": 2},
{"label": "L23", "matrix": [2, 3], "x": 3, "y": 2},
{"label": "L24", "matrix": [2, 4], "x": 4, "y": 2},
{"label": "L25", "matrix": [2, 5], "x": 5, "y": 2},
{"label": "L35", "matrix": [3, 5], "x": 6, "y": 2},
{"label": "R30", "matrix": [7, 5], "x": 8, "y": 2},
{"label": "R20", "matrix": [6, 5], "x": 9, "y": 2},
{"label": "R21", "matrix": [6, 4], "x": 10, "y": 2},
{"label": "R22", "matrix": [6, 3], "x": 11, "y": 2},
{"label": "R23", "matrix": [6, 2], "x": 12, "y": 2},
{"label": "R24", "matrix": [6, 1], "x": 13, "y": 2},
{"label": "R25", "matrix": [6, 0], "x": 14, "y": 2},
{"label": "L31", "matrix": [3, 1], "x": 2, "y": 3},
{"label": "L32", "matrix": [3, 2], "x": 3, "y": 3},
{"label": "L33", "matrix": [3, 3], "x": 4, "y": 3},
{"label": "L34", "matrix": [3, 4], "x": 5, "y": 3},
{"label": "R31", "matrix": [7, 4], "x": 9, "y": 3},
{"label": "R32", "matrix": [7, 3], "x": 10, "y": 3},
{"label": "R33", "matrix": [7, 2], "x": 11, "y": 3},
{"label": "R34", "matrix": [7, 1], "x": 12, "y": 3}
]
}
}
}

View File

@ -0,0 +1,13 @@
{
"keyboard": "geigeigeist/klor",
"keymap": "default",
"layout": "LAYOUT",
"layers": [
[
"KC_Q", "KC_W", "KC_E", "KC_R", "KC_T", "KC_Y", "KC_U", "KC_I", "KC_O", "KC_P",
"KC_TAB", "KC_A", "KC_S", "KC_D", "KC_F", "KC_G", "KC_H", "KC_J", "KC_K", "KC_L", "KC_SCLN", "KC_QUOT",
"KC_DEL", "KC_Z", "KC_X", "KC_C", "KC_V", "KC_B", "KC_MUTE", "KC_MPLY", "KC_N", "KC_M", "KC_COMM", "KC_DOT", "KC_SLSH", "KC_RSFT",
"KC_LCTL", "KC_TRNS", "KC_SPC", "KC_LALT", "KC_LGUI", "KC_ENT", "KC_TRNS", "KC_BSPC"
]
]
}

View File

@ -0,0 +1,103 @@
// Copyright 2024 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include "quantum.h"
#ifdef OLED_ENABLE
oled_rotation_t oled_init_kb(oled_rotation_t rotation) {
return OLED_ROTATION_180;
}
static const char PROGMEM klor_face[] = {
// clang-format off
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0,
0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
// clang-format on
};
void render_keyboard_status(void) {
static const char PROGMEM sep_v[] = {0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0};
static const char PROGMEM sep_h1[] = {0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0};
static const char PROGMEM sep_h2[] = {0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0};
static const char PROGMEM face_1[] = {0x80, 0x81, 0x82, 0x83, 0x84, 0xE1, 0};
static const char PROGMEM face_2[] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xE1, 0};
static const char PROGMEM os_m_1[] = {0x95, 0x96, 0};
static const char PROGMEM os_m_2[] = {0xB5, 0xB6, 0};
static const char PROGMEM os_w_1[] = {0x97, 0x98, 0};
static const char PROGMEM os_w_2[] = {0xB7, 0xB8, 0};
static const char PROGMEM s_lock[] = {0x8F, 0x90, 0};
static const char PROGMEM n_lock[] = {0x91, 0x92, 0};
static const char PROGMEM c_lock[] = {0x93, 0x94, 0};
static const char PROGMEM b_lock[] = {0xE1, 0xE1, 0};
static const char PROGMEM hap_en[] = {0xB1, 0xB2, 0};
# ifdef AUDIO_ENABLE
static const char PROGMEM aud_en[] = {0xAF, 0xB0, 0};
static const char PROGMEM aud_di[] = {0xCF, 0xD0, 0};
# endif
oled_write_ln_P(sep_v, false);
oled_write_P(keymap_config.swap_lctl_lgui ? os_m_1 : os_w_1, false);
oled_write_P(sep_h1, false);
oled_write_P(face_1, false);
oled_write_P(keymap_config.swap_lctl_lgui ? os_m_2 : os_w_2, false);
oled_write_P(sep_h1, false);
oled_write_P(face_2, false);
oled_write_ln_P(sep_v, false);
led_t led_usb_state = host_keyboard_led_state();
oled_write_P(led_usb_state.num_lock ? n_lock : b_lock, false);
oled_write_P(led_usb_state.caps_lock ? c_lock : b_lock, false);
oled_write_P(led_usb_state.scroll_lock ? s_lock : b_lock, false);
oled_write_P(sep_h2, false);
# ifndef AUDIO_ENABLE
oled_write_P(b_lock, false);
# endif
oled_write_P(b_lock, false);
# ifdef AUDIO_ENABLE
oled_write_P(is_audio_on() ? aud_en : aud_di, false);
# endif
oled_write_P(hap_en, false);
}
bool oled_task_kb(void) {
if (!oled_task_user()) {
return false;
}
if (is_keyboard_master()) {
render_keyboard_status();
} else {
oled_write_raw_P(klor_face, sizeof(klor_face));
}
return false;
}
#endif

View File

@ -0,0 +1,26 @@
# Klor
![keyboard_image](https://i.imgur.com/1cx62B2.jpeg)
* Keyboard Maintainer: [waffle87](https://github.com/waffle87)
* Hardware Supported: Klor PCBs w/ Pro-Micro compatible microcontrollers
* Hardware Availability: [github:geigeigeist/klor](https://github.com/geigeigeist/klor)
**Note**: Audio and Pointing Device features are disabled by default to conserve firmware space on AVR
Make example for this keyboard (after setting up your build environment):
make geigeigeist/klor:default
Flashing example for this keyboard:
make geigeigeist/klor:default:flash
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
## Bootloader
Enter the bootloader in 2 ways:
* **Bootmagic reset**: Hold down the key at (0,0) in the matrix
* **Physical reset button**: Briefly press the button on the PCB

View File

@ -0,0 +1 @@
POINTING_DEVICE_DRIVER = paw3204

View File

@ -0,0 +1,127 @@
{
"keyboard_name": "Styrka Atmel",
"manufacturer": "NoPunIn10Did",
"url": "https://github.com/qmk/qmk_firmware/tree/master/keyboards/nopunin10did/styrkatmel",
"maintainer": "NoPunIn10Did",
"usb": {
"vid": "0x4E50",
"pid": "0x5341",
"device_version": "0.0.1"
},
"features": {
"backlight": false,
"bootmagic": true,
"command": false,
"console": false,
"extrakey": true,
"mousekey": true,
"nkro": true
},
"qmk": {
"locking": {
"enabled": true,
"resync": true
}
},
"matrix_pins": {
"cols": ["F7", "F6", "F5", "F4", "F1", "D7", "B4", "B5", "B6"],
"rows": ["B3", "B0", "B1", "B2", "E6", "B7", "C6", "C7", "D6", "D4"]
},
"diode_direction": "COL2ROW",
"dynamic_keymap": {
"layer_count": 3
},
"indicators": {
"caps_lock": "F0"
},
"processor": "atmega32u4",
"bootloader": "atmel-dfu",
"layouts": {
"LAYOUT": {
"layout": [
{"matrix": [0, 0], "x": 0, "y": 0},
{"matrix": [1, 0], "x": 1, "y": 0},
{"matrix": [0, 1], "x": 2.25, "y": 0},
{"matrix": [1, 1], "x": 3.25, "y": 0},
{"matrix": [0, 2], "x": 4.25, "y": 0},
{"matrix": [1, 2], "x": 5.25, "y": 0},
{"matrix": [0, 3], "x": 6.25, "y": 0},
{"matrix": [1, 3], "x": 7.25, "y": 0},
{"matrix": [0, 4], "x": 8.25, "y": 0},
{"matrix": [1, 4], "x": 9.25, "y": 0},
{"matrix": [0, 5], "x": 10.25, "y": 0},
{"matrix": [1, 5], "x": 11.25, "y": 0},
{"matrix": [0, 6], "x": 12.25, "y": 0},
{"matrix": [1, 6], "x": 13.25, "y": 0},
{"matrix": [0, 7], "x": 14.25, "y": 0},
{"matrix": [0, 8], "x": 15.25, "y": 0, "w": 2},
{"matrix": [1, 8], "x": 17.25, "y": 0},
{"matrix": [2, 0], "x": 0, "y": 1},
{"matrix": [3, 0], "x": 1, "y": 1},
{"matrix": [2, 1], "x": 2.25, "y": 1, "w":1.5},
{"matrix": [3, 1], "x": 3.75, "y": 1},
{"matrix": [2, 2], "x": 4.75, "y": 1},
{"matrix": [3, 2], "x": 5.75, "y": 1},
{"matrix": [2, 3], "x": 6.75, "y": 1},
{"matrix": [3, 3], "x": 7.75, "y": 1},
{"matrix": [2, 4], "x": 8.75, "y": 1},
{"matrix": [3, 4], "x": 9.75, "y": 1},
{"matrix": [2, 5], "x": 10.75, "y": 1},
{"matrix": [3, 5], "x": 11.75, "y": 1},
{"matrix": [2, 6], "x": 12.75, "y": 1},
{"matrix": [3, 6], "x": 13.75, "y": 1},
{"matrix": [2, 7], "x": 14.75, "y": 1},
{"matrix": [3, 8], "x": 17.25, "y": 1},
{"matrix": [4, 0], "x": 0, "y": 2},
{"matrix": [5, 0], "x": 1, "y": 2},
{"matrix": [4, 1], "x": 2.25, "y": 2, "w":1.25},
{"matrix": [5, 1], "x": 4, "y": 2},
{"matrix": [4, 2], "x": 5, "y": 2},
{"matrix": [5, 2], "x": 6, "y": 2},
{"matrix": [4, 3], "x": 7, "y": 2},
{"matrix": [5, 3], "x": 8, "y": 2},
{"matrix": [4, 4], "x": 9, "y": 2},
{"matrix": [5, 4], "x": 10, "y": 2},
{"matrix": [4, 5], "x": 11, "y": 2},
{"matrix": [5, 5], "x": 12, "y": 2},
{"matrix": [4, 6], "x": 13, "y": 2},
{"matrix": [5, 6], "x": 14, "y": 2},
{"matrix": [4, 7], "x": 15, "y": 2},
{"matrix": [4, 8], "x": 16, "y": 1, "w":1.25, "h":2},
{"matrix": [5, 8], "x": 17.25, "y": 2},
{"matrix": [6, 0], "x": 0, "y": 3},
{"matrix": [7, 0], "x": 1, "y": 3},
{"matrix": [6, 1], "x": 2.25, "y": 3, "w":1.25},
{"matrix": [7, 1], "x": 3.5, "y": 3},
{"matrix": [6, 2], "x": 4.5, "y": 3},
{"matrix": [7, 2], "x": 5.5, "y": 3},
{"matrix": [6, 3], "x": 6.5, "y": 3},
{"matrix": [7, 3], "x": 7.5, "y": 3},
{"matrix": [6, 4], "x": 8.5, "y": 3},
{"matrix": [7, 4], "x": 9.5, "y": 3},
{"matrix": [6, 5], "x": 10.5, "y": 3},
{"matrix": [7, 5], "x": 11.5, "y": 3},
{"matrix": [6, 6], "x": 12.5, "y": 3},
{"matrix": [7, 6], "x": 13.5, "y": 3},
{"matrix": [6, 7], "x": 14.5, "y": 3, "w":1.75},
{"matrix": [6, 8], "x": 16.25, "y": 3},
{"matrix": [7, 8], "x": 17.25, "y": 3},
{"matrix": [8, 0], "x": 0, "y": 4},
{"matrix": [9, 0], "x": 1, "y": 4},
{"matrix": [8, 1], "x": 2.25, "y": 4, "w":1.25},
{"matrix": [9, 1], "x": 3.5, "y": 4, "w":1.25},
{"matrix": [8, 2], "x": 4.75, "y": 4, "w":1.25},
{"matrix": [8, 4], "x": 6, "y": 4, "w":7},
{"matrix": [8, 6], "x": 12.25, "y": 4, "w":1.25},
{"matrix": [9, 6], "x": 13.5, "y": 4, "w":1.25},
{"matrix": [8, 7], "x": 15.25, "y": 4},
{"matrix": [8, 8], "x": 16.25, "y": 4},
{"matrix": [9, 8], "x": 17.25, "y": 4}
]
}
}
}

View File

@ -0,0 +1,48 @@
/* Copyright 2024 W. Alex Ronke, a.k.a. NoPunIn10Did (w.alex.ronke@gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* Keymap BASE: (Base Layer) Default Layer
* .-------.,---------------------------------------------------------------.
* | F1| F2||Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| BkSpc |Ins|
* |---|---||---------------------------------------------------------------|
* | F3| F4||Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| |Del|
* |---|---||---------------------------------------------------------------|
* | F5| F6||CAPS | A| S| D| F| G| H| J| K| L| ;| '| \| Ent|PgU|
* |---|---||---------------------------------------------------------------|
* | F7| F8||Shft| <>| Z| X| C| V| B| N| M| ,| .| /| Shift| Up|PgD|
* |---|---||---------------------------------------------------------------|
* | F9|F10||LCtl|LGUI|LAlt| Space | Alt| FN||| Lt| Dn| Rt|
* `-------'`---------------------------------------------------------------'
*/
[0] = LAYOUT(
KC_F1, KC_F2, KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_INS,
KC_F3, KC_F4, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL,
KC_F5, KC_F6, KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_NUHS, KC_ENT, KC_PGUP,
KC_F7, KC_F8, KC_LSFT, KC_NUBS, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_PGDN,
KC_F9, KC_F10, KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(1), KC_LEFT, KC_DOWN, KC_RGHT
),
[1] = LAYOUT(
QK_BOOT, KC_F2, KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSLS, KC_INS,
KC_F3, KC_F4, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL,
KC_F5, KC_F6, KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_NUHS, KC_ENT, KC_PGUP,
KC_F7, KC_F8, KC_LSFT, KC_NUBS, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_PGDN,
KC_F9, KC_F10, KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT
),
};

View File

@ -0,0 +1,25 @@
# Viktus Styrka Atmel Edition
The Viktus Styrka is a 65% + left macro block created in a collaboration of OneCreativeMind and BlindAssassin111 (Viktus owner).
This is a custom Atmel ISO Hotswap PCB for the Viktus Styrka designed and maintained by NoPunIn10Did.
* Firmware Maintainer: [nopunin10did](https://github.com/nopunin10did)
* Hardware Supported: Styrka
* Hardware Availability: <https://www.Viktus.Design>
Make example for this keyboard (after setting up your build environment):
make nopunin10did/styrkatmel:default
Flashing example for this keyboard:
make nopunin10did/styrkatmel:default:flash
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
Enter the bootloader in 3 ways:
* **Bootmagic reset**: Hold down the key at the top left in the macro columns (default: F1) and plug in the keyboard.
* **Physical reset button**: Briefly press the button on the back of the PCB.
* **Keycode in layout**: Press the key mapped to `QK_BOOT`. For the default layout, hold down the rightmost 1.25u key on the bottom row, then tap the top-left key in the macro columns.

View File

@ -0,0 +1,46 @@
{
"manufacturer": "PHDesign",
"keyboard_name": "phac",
"maintainer": "nonameCCC",
"bootloader": "rp2040",
"encoder": {
"rotary": [
{"pin_a": "GP7", "pin_b": "GP8", "resolution": 1},
{"pin_a": "GP10", "pin_b": "GP9", "resolution": 1}
]
},
"features": {
"bootmagic": true,
"command": false,
"console": false,
"encoder": true,
"extrakey": true,
"mousekey": true,
"nkro": true
},
"matrix_pins": {
"direct": [
["GP1", "GP6", "GP5", "GP4", "GP3", "GP2", "GP0"]
]
},
"processor": "RP2040",
"url": "",
"usb": {
"device_version": "2.2.0",
"pid": "0x0001",
"vid": "0x5048"
},
"layouts": {
"LAYOUT": {
"layout": [
{"matrix": [0, 0], "x": 2.5, "y": 0},
{"matrix": [0, 1], "x": 0, "y": 1, "w": 1.5},
{"matrix": [0, 2], "x": 1.5, "y": 1, "w": 1.5},
{"matrix": [0, 3], "x": 3, "y": 1, "w": 1.5},
{"matrix": [0, 4], "x": 4.5, "y": 1, "w": 1.5},
{"matrix": [0, 5], "x": 0.375, "y": 2, "w": 2.25},
{"matrix": [0, 6], "x": 3.375, "y": 2, "w": 2.25}
]
}
}
}

View File

@ -0,0 +1,22 @@
// Copyright 2023 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include QMK_KEYBOARD_H
enum layer_names {
_BL,
};
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_BL] = LAYOUT(
KC_B,
KC_S, KC_D, KC_K, KC_L,
KC_V, KC_N
)
};
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
[_BL] = { ENCODER_CCW_CW(MS_UP, MS_DOWN), ENCODER_CCW_CW(MS_LEFT, MS_RGHT) },
};
#endif

View File

@ -0,0 +1 @@
ENCODER_MAP_ENABLE = yes

View File

@ -0,0 +1,26 @@
# phac
![phac](https://i.imgur.com/bQdYGMf.png)
A rhythm game controller with 7 keys and 2 encoders on it.
* Keyboard Maintainer: [Xufeng Tao](https://github.com/nonameCCC)
* Hardware Supported: RP2040 minimal system
* Hardware Availability: https://m.tb.cn/h.gLFXLaX?tk=7DpL3TuPVxx (currently not available outside of mainland China)
Make example for this keyboard (after setting up your build environment):
make phdesign/phac:default
Flashing example for this keyboard:
make phdesign/phac:default:flash
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
## Bootloader
Enter the bootloader in 2 ways:
* **Bootmagic reset**: Hold down the key at (0,5) in the matrix (the START button) and plug in the controller
* **Physical reset button**: Short pin hole SW1 on the back of the PCB (not recommended as the case is not easy to open)

View File

@ -46,11 +46,11 @@
"pin": "GP29" "pin": "GP29"
}, },
"layout_aliases": { "layout_aliases": {
"LAYOUT_all": "LAYOUT_60_tsangan_hhkb" "LAYOUT_all": "LAYOUT_60_ansi_tsangan_split_bs_rshift"
}, },
"community_layouts": [ "community_layouts": [
"60_ansi_tsangan", "60_ansi_tsangan",
"60_tsangan_hhkb", "60_ansi_tsangan_split_bs_rshift",
"60_ansi_wkl", "60_ansi_wkl",
"60_ansi_wkl_split_bs_rshift", "60_ansi_wkl_split_bs_rshift",
"60_hhkb" "60_hhkb"
@ -124,7 +124,7 @@
{"matrix": [4, 12], "x": 13.5, "y": 4, "w": 1.5} {"matrix": [4, 12], "x": 13.5, "y": 4, "w": 1.5}
] ]
}, },
"LAYOUT_60_tsangan_hhkb": { "LAYOUT_60_ansi_tsangan_split_bs_rshift": {
"layout": [ "layout": [
{"matrix": [0, 0], "x": 0, "y": 0}, {"matrix": [0, 0], "x": 0, "y": 0},
{"matrix": [0, 1], "x": 1, "y": 0}, {"matrix": [0, 1], "x": 1, "y": 0},

View File

@ -1,3 +0,0 @@
# 60_tsangan_hhkb
LAYOUT_60_tsangan_hhkb

View File

@ -1,27 +0,0 @@
// Copyright 2023 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include QMK_KEYBOARD_H
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/*
*
* ` 1 2 3 4 5 6 7 8 9 0 - = BspBsp
*
* Tab Q W E R T Y U I O P [ ] \
*
* Caps A S D F G H J K L ; ' Enter
*
* Shift Z X C V B N M , . / ShiftSft
*
* Ctrl GUI Alt Alt GUI Ctrl
*
*/
[0] = LAYOUT_60_tsangan_hhkb(
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_BSPC,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_RSFT,
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, KC_RGUI, KC_RCTL
)
};

View File

@ -1,77 +0,0 @@
{
"keyboard_name": "60% ANSI Tsangan HHKB layout",
"url": "",
"maintainer": "qmk",
"layouts": {
"LAYOUT_60_tsangan_hhkb": {
"layout": [
{"x":0, "y":0},
{"x":1, "y":0},
{"x":2, "y":0},
{"x":3, "y":0},
{"x":4, "y":0},
{"x":5, "y":0},
{"x":6, "y":0},
{"x":7, "y":0},
{"x":8, "y":0},
{"x":9, "y":0},
{"x":10, "y":0},
{"x":11, "y":0},
{"x":12, "y":0},
{"x":13, "y":0},
{"x":14, "y":0},
{"x":0, "y":1, "w":1.5},
{"x":1.5, "y":1},
{"x":2.5, "y":1},
{"x":3.5, "y":1},
{"x":4.5, "y":1},
{"x":5.5, "y":1},
{"x":6.5, "y":1},
{"x":7.5, "y":1},
{"x":8.5, "y":1},
{"x":9.5, "y":1},
{"x":10.5, "y":1},
{"x":11.5, "y":1},
{"x":12.5, "y":1},
{"x":13.5, "y":1, "w":1.5},
{"x":0, "y":2, "w":1.75},
{"x":1.75, "y":2},
{"x":2.75, "y":2},
{"x":3.75, "y":2},
{"x":4.75, "y":2},
{"x":5.75, "y":2},
{"x":6.75, "y":2},
{"x":7.75, "y":2},
{"x":8.75, "y":2},
{"x":9.75, "y":2},
{"x":10.75, "y":2},
{"x":11.75, "y":2},
{"x":12.75, "y":2, "w":2.25},
{"x":0, "y":3, "w":2.25},
{"x":2.25, "y":3},
{"x":3.25, "y":3},
{"x":4.25, "y":3},
{"x":5.25, "y":3},
{"x":6.25, "y":3},
{"x":7.25, "y":3},
{"x":8.25, "y":3},
{"x":9.25, "y":3},
{"x":10.25, "y":3},
{"x":11.25, "y":3},
{"x":12.25, "y":3, "w":1.75},
{"x":14, "y":3},
{"x":0, "y":4, "w":1.5},
{"x":1.5, "y":4},
{"x":2.5, "y":4, "w":1.5},
{"x":4, "y":4, "w":7},
{"x":11, "y":4, "w":1.5},
{"x":12.5, "y":4},
{"x":13.5, "y":4, "w":1.5}
]
}
}
}

View File

@ -1,5 +0,0 @@
[{a:7},"","","","","","","","","","","","","","",""],
[{w:1.5},"","","","","","","","","","","","","",{w:1.5},""],
[{w:1.75},"","","","","","","","","","","","",{w:2.25},""],
[{w:2.25},"","","","","","","","","","","",{w:1.75},"",""],
[{w:1.5},"","",{w:1.5},"",{w:7},"",{w:1.5},"","",{w:1.5},""]

View File

@ -1,3 +0,0 @@
# 60_tsangan_hhkb
LAYOUT_60_tsangan_hhkb

View File

@ -74,28 +74,30 @@ class Exists(FilterFunction):
func_name = "exists" func_name = "exists"
def apply(self, target_info: KeyboardKeymapDesc) -> bool: def apply(self, target_info: KeyboardKeymapDesc) -> bool:
return self.key in target_info.data return self.key in target_info.dotty
class Absent(FilterFunction): class Absent(FilterFunction):
func_name = "absent" func_name = "absent"
def apply(self, target_info: KeyboardKeymapDesc) -> bool: def apply(self, target_info: KeyboardKeymapDesc) -> bool:
return self.key not in target_info.data return self.key not in target_info.dotty
class Length(FilterFunction): class Length(FilterFunction):
func_name = "length" func_name = "length"
def apply(self, target_info: KeyboardKeymapDesc) -> bool: def apply(self, target_info: KeyboardKeymapDesc) -> bool:
return (self.key in target_info.data and len(target_info.data[self.key]) == int(self.value)) info_dotty = target_info.dotty
return (self.key in info_dotty and len(info_dotty[self.key]) == int(self.value))
class Contains(FilterFunction): class Contains(FilterFunction):
func_name = "contains" func_name = "contains"
def apply(self, target_info: KeyboardKeymapDesc) -> bool: def apply(self, target_info: KeyboardKeymapDesc) -> bool:
return (self.key in target_info.data and self.value in target_info.data[self.key]) info_dotty = target_info.dotty
return (self.key in info_dotty and self.value in info_dotty[self.key])
def _get_filter_class(func_name: str, key: str, value: str) -> Optional[FilterFunction]: def _get_filter_class(func_name: str, key: str, value: str) -> Optional[FilterFunction]:

View File

@ -347,3 +347,68 @@ def test_format_json_keymap_auto():
result = check_subcommand('format-json', '--format', 'auto', 'lib/python/qmk/tests/minimal_keymap.json') result = check_subcommand('format-json', '--format', 'auto', 'lib/python/qmk/tests/minimal_keymap.json')
check_returncode(result) check_returncode(result)
assert result.stdout == '{\n "keyboard": "handwired/pytest/basic",\n "keymap": "test",\n "layers": [\n ["KC_A"]\n ],\n "layout": "LAYOUT_ortho_1x1",\n "version": 1\n}\n' assert result.stdout == '{\n "keyboard": "handwired/pytest/basic",\n "keymap": "test",\n "layers": [\n ["KC_A"]\n ],\n "layout": "LAYOUT_ortho_1x1",\n "version": 1\n}\n'
def test_find_exists():
result = check_subcommand('find', '-f', 'exists(rgb_matrix.split_count)', '-p', 'rgb_matrix.split_count')
check_returncode(result)
values = [s for s in result.stdout.splitlines() if 'rgb_matrix.split_count=' in s]
assert len(values) > 0
for s in values:
assert '=None' not in s
assert '=[' in s
def test_find_absent():
result = check_subcommand('find', '-f', 'absent(rgb_matrix.split_count)', '-p', 'rgb_matrix.split_count')
check_returncode(result)
values = [s for s in result.stdout.splitlines() if 'rgb_matrix.split_count=' in s]
assert len(values) > 0
for s in values:
assert '=None' in s
assert '=[' not in s
def test_find_length():
result = check_subcommand('find', '-f', 'length(matrix_pins.cols, 6)', '-p', 'matrix_pins.cols')
check_returncode(result)
values = [s for s in result.stdout.splitlines() if 'matrix_pins.cols=' in s]
assert len(values) > 0
for s in values:
assert s.count(',') == 5
def test_find_contains():
result = check_subcommand('find', '-f', 'contains(matrix_pins.cols, B1)', '-p', 'matrix_pins.cols')
check_returncode(result)
values = [s for s in result.stdout.splitlines() if 'matrix_pins.cols=' in s]
assert len(values) > 0
for s in values:
assert "'B1'" in s
def test_find_multiple_conditions():
# this is intended to match at least 'crkbd/rev1'
result = check_subcommand(
'find', '-f', 'exists(rgb_matrix.split_count)', '-f', 'contains(matrix_pins.cols, B1)', '-f', 'length(matrix_pins.cols, 6)', '-f', 'absent(eeprom.driver)', '-f', 'ws2812.pin=D3', '-p', 'rgb_matrix.split_count', '-p', 'matrix_pins.cols', '-p',
'eeprom.driver', '-p', 'ws2812.pin'
)
check_returncode(result)
rgb_matrix_split_count_values = [s for s in result.stdout.splitlines() if 'rgb_matrix.split_count=' in s]
assert len(rgb_matrix_split_count_values) > 0
for s in rgb_matrix_split_count_values:
assert '=None' not in s
assert '=[' in s
matrix_pins_cols_values = [s for s in result.stdout.splitlines() if 'matrix_pins.cols=' in s]
assert len(matrix_pins_cols_values) > 0
for s in matrix_pins_cols_values:
assert s.count(',') == 5
assert "'B1'" in s
eeprom_driver_values = [s for s in result.stdout.splitlines() if 'eeprom.driver=' in s]
assert len(eeprom_driver_values) > 0
for s in eeprom_driver_values:
assert '=None' in s
ws2812_pin_values = [s for s in result.stdout.splitlines() if 'ws2812.pin=' in s]
assert len(ws2812_pin_values) > 0
for s in ws2812_pin_values:
assert '=D3' in s

View File

@ -36,9 +36,18 @@
# define SPI_TIMEOUT 100 # define SPI_TIMEOUT 100
#endif #endif
static pin_t currentSlavePin = NO_PIN; static pin_t current_slave_pin = NO_PIN;
static uint8_t currentSlaveConfig = 0; static bool current_cs_active_low = true;
static bool currentSlave2X = false; static uint8_t current_slave_config = 0;
static bool current_slave_2x = false;
static inline void spi_select(void) {
gpio_write_pin(current_slave_pin, current_cs_active_low ? 0 : 1);
}
static inline void spi_unselect(void) {
gpio_write_pin(current_slave_pin, current_cs_active_low ? 1 : 0);
}
void spi_init(void) { void spi_init(void) {
gpio_write_pin_high(SPI_SS_PIN); gpio_write_pin_high(SPI_SS_PIN);
@ -50,63 +59,74 @@ void spi_init(void) {
} }
bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) { bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
if (currentSlavePin != NO_PIN || slavePin == NO_PIN) { spi_start_config_t start_config = {0};
start_config.slave_pin = slavePin;
start_config.lsb_first = lsbFirst;
start_config.mode = mode;
start_config.divisor = divisor;
start_config.cs_active_low = true;
return spi_start_extended(&start_config);
}
bool spi_start_extended(spi_start_config_t *start_config) {
if (current_slave_pin != NO_PIN || start_config->slave_pin == NO_PIN) {
return false; return false;
} }
currentSlaveConfig = 0; current_slave_config = 0;
if (lsbFirst) { if (start_config->lsb_first) {
currentSlaveConfig |= _BV(DORD); current_slave_config |= _BV(DORD);
} }
switch (mode) { switch (start_config->mode) {
case 1: case 1:
currentSlaveConfig |= _BV(CPHA); current_slave_config |= _BV(CPHA);
break; break;
case 2: case 2:
currentSlaveConfig |= _BV(CPOL); current_slave_config |= _BV(CPOL);
break; break;
case 3: case 3:
currentSlaveConfig |= (_BV(CPOL) | _BV(CPHA)); current_slave_config |= (_BV(CPOL) | _BV(CPHA));
break; break;
} }
uint16_t roundedDivisor = 1; uint16_t roundedDivisor = 1;
while (roundedDivisor < divisor) { while (roundedDivisor < start_config->divisor) {
roundedDivisor <<= 1; roundedDivisor <<= 1;
} }
switch (roundedDivisor) { switch (roundedDivisor) {
case 16: case 16:
currentSlaveConfig |= _BV(SPR0); current_slave_config |= _BV(SPR0);
break; break;
case 64: case 64:
currentSlaveConfig |= _BV(SPR1); current_slave_config |= _BV(SPR1);
break; break;
case 128: case 128:
currentSlaveConfig |= (_BV(SPR1) | _BV(SPR0)); current_slave_config |= (_BV(SPR1) | _BV(SPR0));
break; break;
case 2: case 2:
currentSlave2X = true; current_slave_2x = true;
break; break;
case 8: case 8:
currentSlave2X = true; current_slave_2x = true;
currentSlaveConfig |= _BV(SPR0); current_slave_config |= _BV(SPR0);
break; break;
case 32: case 32:
currentSlave2X = true; current_slave_2x = true;
currentSlaveConfig |= _BV(SPR1); current_slave_config |= _BV(SPR1);
break; break;
} }
SPCR |= currentSlaveConfig; SPCR |= current_slave_config;
if (currentSlave2X) { if (current_slave_2x) {
SPSR |= _BV(SPI2X); SPSR |= _BV(SPI2X);
} }
currentSlavePin = slavePin; current_slave_pin = start_config->slave_pin;
gpio_set_pin_output(currentSlavePin); current_cs_active_low = start_config->cs_active_low;
gpio_write_pin_low(currentSlavePin); gpio_set_pin_output(current_slave_pin);
spi_select();
return true; return true;
} }
@ -168,13 +188,13 @@ spi_status_t spi_receive(uint8_t *data, uint16_t length) {
} }
void spi_stop(void) { void spi_stop(void) {
if (currentSlavePin != NO_PIN) { if (current_slave_pin != NO_PIN) {
gpio_set_pin_output(currentSlavePin); gpio_set_pin_output(current_slave_pin);
gpio_write_pin_high(currentSlavePin); spi_unselect();
currentSlavePin = NO_PIN; current_slave_pin = NO_PIN;
SPSR &= ~(_BV(SPI2X)); SPSR &= ~(_BV(SPI2X));
SPCR &= ~(currentSlaveConfig); SPCR &= ~(current_slave_config);
currentSlaveConfig = 0; current_slave_config = 0;
currentSlave2X = false; current_slave_2x = false;
} }
} }

View File

@ -41,9 +41,18 @@ typedef int16_t spi_status_t;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef struct spi_start_config_t {
pin_t slave_pin;
bool lsb_first;
uint8_t mode;
uint16_t divisor;
bool cs_active_low;
} spi_start_config_t;
void spi_init(void); void spi_init(void);
bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor); bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor);
bool spi_start_extended(spi_start_config_t *start_config);
spi_status_t spi_write(uint8_t data); spi_status_t spi_write(uint8_t data);

View File

@ -40,7 +40,7 @@
#define STM32_PLS STM32_PLS_LEV0 #define STM32_PLS STM32_PLS_LEV0
#define STM32_HSI16_ENABLED TRUE #define STM32_HSI16_ENABLED TRUE
#define STM32_HSI48_ENABLED TRUE #define STM32_HSI48_ENABLED TRUE
#define STM32_LSI_ENABLED TRUE #define STM32_LSI_ENABLED FALSE
#define STM32_HSE_ENABLED FALSE #define STM32_HSE_ENABLED FALSE
#define STM32_LSE_ENABLED FALSE #define STM32_LSE_ENABLED FALSE
#define STM32_MSIPLL_ENABLED FALSE #define STM32_MSIPLL_ENABLED FALSE

View File

@ -1,85 +1,10 @@
/* /*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio * Copyright 2006..2018 Giovanni Di Sirio
* Copyright 2022 QMK contributors
Licensed under the Apache License, Version 2.0 (the "License"); * SPDX-License-Identifier: GPL-2.0-or-later
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* STM32F401xC memory setup.
*/ */
MEMORY
{
flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */
flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */
flash2 (rx) : org = 0x08008000, len = 256k - 32k /* Sector 2..6 - Rest of firmware */
flash3 (rx) : org = 0x00000000, len = 0
flash4 (rx) : org = 0x00000000, len = 0
flash5 (rx) : org = 0x00000000, len = 0
flash6 (rx) : org = 0x00000000, len = 0
flash7 (rx) : org = 0x00000000, len = 0
ram0 (wx) : org = 0x20000000, len = 64k
ram1 (wx) : org = 0x00000000, len = 0
ram2 (wx) : org = 0x00000000, len = 0
ram3 (wx) : org = 0x00000000, len = 0
ram4 (wx) : org = 0x00000000, len = 0
ram5 (wx) : org = 0x00000000, len = 0
ram6 (wx) : org = 0x00000000, len = 0
ram7 (wx) : org = 0x00000000, len = 0
}
/* For each data/text section two region are defined, a virtual region f4xx_flash_size = 256k;
and a load region (_LMA suffix).*/ f4xx_ram_size = 64k;
/* Flash region to be used for exception vectors.*/ INCLUDE stm32f4xx_common.ld
REGION_ALIAS("VECTORS_FLASH", flash0);
REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
/* Flash region to be used for constructors and destructors.*/
REGION_ALIAS("XTORS_FLASH", flash2);
REGION_ALIAS("XTORS_FLASH_LMA", flash2);
/* Flash region to be used for code text.*/
REGION_ALIAS("TEXT_FLASH", flash2);
REGION_ALIAS("TEXT_FLASH_LMA", flash2);
/* Flash region to be used for read only data.*/
REGION_ALIAS("RODATA_FLASH", flash2);
REGION_ALIAS("RODATA_FLASH_LMA", flash2);
/* Flash region to be used for various.*/
REGION_ALIAS("VARIOUS_FLASH", flash2);
REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
/* Flash region to be used for RAM(n) initialization data.*/
REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2);
/* RAM region to be used for Main stack. This stack accommodates the processing
of all exceptions and interrupts.*/
REGION_ALIAS("MAIN_STACK_RAM", ram0);
/* RAM region to be used for the process stack. This is the stack used by
the main() function.*/
REGION_ALIAS("PROCESS_STACK_RAM", ram0);
/* RAM region to be used for data segment.*/
REGION_ALIAS("DATA_RAM", ram0);
REGION_ALIAS("DATA_RAM_LMA", flash2);
/* RAM region to be used for BSS segment.*/
REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
/* Generic rules inclusion.*/
INCLUDE rules.ld

View File

@ -1,88 +1,10 @@
/* /*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio * Copyright 2006..2018 Giovanni Di Sirio
* Copyright 2022 QMK contributors
Licensed under the Apache License, Version 2.0 (the "License"); * SPDX-License-Identifier: GPL-2.0-or-later
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* STM32F401xC memory setup.
*/ */
MEMORY
{
flash0 (rx) : org = 0x08000000 + 64k, len = 256k - 64k /* tinyuf2 bootloader requires app to be located at 64k offset for this MCU */
flash1 (rx) : org = 0x00000000, len = 0
flash2 (rx) : org = 0x00000000, len = 0
flash3 (rx) : org = 0x00000000, len = 0
flash4 (rx) : org = 0x00000000, len = 0
flash5 (rx) : org = 0x00000000, len = 0
flash6 (rx) : org = 0x00000000, len = 0
flash7 (rx) : org = 0x00000000, len = 0
ram0 (wx) : org = 0x20000000, len = 64k
ram1 (wx) : org = 0x00000000, len = 0
ram2 (wx) : org = 0x00000000, len = 0
ram3 (wx) : org = 0x00000000, len = 0
ram4 (wx) : org = 0x00000000, len = 0
ram5 (wx) : org = 0x00000000, len = 0
ram6 (wx) : org = 0x00000000, len = 0
ram7 (wx) : org = 0x00000000, len = 0
}
/* For each data/text section two region are defined, a virtual region f4xx_flash_size = 256k;
and a load region (_LMA suffix).*/ f4xx_ram_size = 64k;
/* Flash region to be used for exception vectors.*/ INCLUDE stm32f4xx_tinyuf2_common.ld
REGION_ALIAS("VECTORS_FLASH", flash0);
REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
/* Flash region to be used for constructors and destructors.*/
REGION_ALIAS("XTORS_FLASH", flash0);
REGION_ALIAS("XTORS_FLASH_LMA", flash0);
/* Flash region to be used for code text.*/
REGION_ALIAS("TEXT_FLASH", flash0);
REGION_ALIAS("TEXT_FLASH_LMA", flash0);
/* Flash region to be used for read only data.*/
REGION_ALIAS("RODATA_FLASH", flash0);
REGION_ALIAS("RODATA_FLASH_LMA", flash0);
/* Flash region to be used for various.*/
REGION_ALIAS("VARIOUS_FLASH", flash0);
REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
/* Flash region to be used for RAM(n) initialization data.*/
REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
/* RAM region to be used for Main stack. This stack accommodates the processing
of all exceptions and interrupts.*/
REGION_ALIAS("MAIN_STACK_RAM", ram0);
/* RAM region to be used for the process stack. This is the stack used by
the main() function.*/
REGION_ALIAS("PROCESS_STACK_RAM", ram0);
/* RAM region to be used for data segment.*/
REGION_ALIAS("DATA_RAM", ram0);
REGION_ALIAS("DATA_RAM_LMA", flash0);
/* RAM region to be used for BSS segment.*/
REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
/* Generic rules inclusion.*/
INCLUDE rules.ld
/* TinyUF2 bootloader reset support */
_board_dfu_dbl_tap = ORIGIN(ram0) + 64k - 4; /* this is based off the linker file for tinyuf2 */

View File

@ -1,85 +1,10 @@
/* /*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio * Copyright 2006..2018 Giovanni Di Sirio
* Copyright 2022 QMK contributors
Licensed under the Apache License, Version 2.0 (the "License"); * SPDX-License-Identifier: GPL-2.0-or-later
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* STM32F401xE memory setup.
*/ */
MEMORY
{
flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */
flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */
flash2 (rx) : org = 0x08008000, len = 512k - 32k /* Sector 2..7 - Rest of firmware */
flash3 (rx) : org = 0x00000000, len = 0
flash4 (rx) : org = 0x00000000, len = 0
flash5 (rx) : org = 0x00000000, len = 0
flash6 (rx) : org = 0x00000000, len = 0
flash7 (rx) : org = 0x00000000, len = 0
ram0 (wx) : org = 0x20000000, len = 96k
ram1 (wx) : org = 0x00000000, len = 0
ram2 (wx) : org = 0x00000000, len = 0
ram3 (wx) : org = 0x00000000, len = 0
ram4 (wx) : org = 0x00000000, len = 0
ram5 (wx) : org = 0x00000000, len = 0
ram6 (wx) : org = 0x00000000, len = 0
ram7 (wx) : org = 0x00000000, len = 0
}
/* For each data/text section two region are defined, a virtual region f4xx_flash_size = 512k;
and a load region (_LMA suffix).*/ f4xx_ram_size = 96k;
/* Flash region to be used for exception vectors.*/ INCLUDE stm32f4xx_common.ld
REGION_ALIAS("VECTORS_FLASH", flash0);
REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
/* Flash region to be used for constructors and destructors.*/
REGION_ALIAS("XTORS_FLASH", flash2);
REGION_ALIAS("XTORS_FLASH_LMA", flash2);
/* Flash region to be used for code text.*/
REGION_ALIAS("TEXT_FLASH", flash2);
REGION_ALIAS("TEXT_FLASH_LMA", flash2);
/* Flash region to be used for read only data.*/
REGION_ALIAS("RODATA_FLASH", flash2);
REGION_ALIAS("RODATA_FLASH_LMA", flash2);
/* Flash region to be used for various.*/
REGION_ALIAS("VARIOUS_FLASH", flash2);
REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
/* Flash region to be used for RAM(n) initialization data.*/
REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2);
/* RAM region to be used for Main stack. This stack accommodates the processing
of all exceptions and interrupts.*/
REGION_ALIAS("MAIN_STACK_RAM", ram0);
/* RAM region to be used for the process stack. This is the stack used by
the main() function.*/
REGION_ALIAS("PROCESS_STACK_RAM", ram0);
/* RAM region to be used for data segment.*/
REGION_ALIAS("DATA_RAM", ram0);
REGION_ALIAS("DATA_RAM_LMA", flash2);
/* RAM region to be used for BSS segment.*/
REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
/* Generic rules inclusion.*/
INCLUDE rules.ld

View File

@ -1,88 +1,10 @@
/* /*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio * Copyright 2006..2018 Giovanni Di Sirio
* Copyright 2022 QMK contributors
Licensed under the Apache License, Version 2.0 (the "License"); * SPDX-License-Identifier: GPL-2.0-or-later
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* STM32F401xE memory setup.
*/ */
MEMORY
{
flash0 (rx) : org = 0x08000000 + 64k, len = 512k - 64k /* tinyuf2 bootloader requires app to be located at 64k offset for this MCU */
flash1 (rx) : org = 0x00000000, len = 0
flash2 (rx) : org = 0x00000000, len = 0
flash3 (rx) : org = 0x00000000, len = 0
flash4 (rx) : org = 0x00000000, len = 0
flash5 (rx) : org = 0x00000000, len = 0
flash6 (rx) : org = 0x00000000, len = 0
flash7 (rx) : org = 0x00000000, len = 0
ram0 (wx) : org = 0x20000000, len = 96k
ram1 (wx) : org = 0x00000000, len = 0
ram2 (wx) : org = 0x00000000, len = 0
ram3 (wx) : org = 0x00000000, len = 0
ram4 (wx) : org = 0x00000000, len = 0
ram5 (wx) : org = 0x00000000, len = 0
ram6 (wx) : org = 0x00000000, len = 0
ram7 (wx) : org = 0x00000000, len = 0
}
/* For each data/text section two region are defined, a virtual region f4xx_flash_size = 512k;
and a load region (_LMA suffix).*/ f4xx_ram_size = 96k;
/* Flash region to be used for exception vectors.*/ INCLUDE stm32f4xx_tinyuf2_common.ld
REGION_ALIAS("VECTORS_FLASH", flash0);
REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
/* Flash region to be used for constructors and destructors.*/
REGION_ALIAS("XTORS_FLASH", flash0);
REGION_ALIAS("XTORS_FLASH_LMA", flash0);
/* Flash region to be used for code text.*/
REGION_ALIAS("TEXT_FLASH", flash0);
REGION_ALIAS("TEXT_FLASH_LMA", flash0);
/* Flash region to be used for read only data.*/
REGION_ALIAS("RODATA_FLASH", flash0);
REGION_ALIAS("RODATA_FLASH_LMA", flash0);
/* Flash region to be used for various.*/
REGION_ALIAS("VARIOUS_FLASH", flash0);
REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
/* Flash region to be used for RAM(n) initialization data.*/
REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
/* RAM region to be used for Main stack. This stack accommodates the processing
of all exceptions and interrupts.*/
REGION_ALIAS("MAIN_STACK_RAM", ram0);
/* RAM region to be used for the process stack. This is the stack used by
the main() function.*/
REGION_ALIAS("PROCESS_STACK_RAM", ram0);
/* RAM region to be used for data segment.*/
REGION_ALIAS("DATA_RAM", ram0);
REGION_ALIAS("DATA_RAM_LMA", flash0);
/* RAM region to be used for BSS segment.*/
REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
/* Generic rules inclusion.*/
INCLUDE rules.ld
/* TinyUF2 bootloader reset support */
_board_dfu_dbl_tap = ORIGIN(ram0) + 64k - 4; /* this is based off the linker file for tinyuf2 */

View File

@ -0,0 +1,10 @@
/*
* Copyright 2006..2018 Giovanni Di Sirio
* Copyright 2022 QMK contributors
* SPDX-License-Identifier: GPL-2.0-or-later
*/
f4xx_flash_size = 256k;
f4xx_ram_size = 128k;
INCLUDE stm32f4xx_common.ld

View File

@ -1,89 +1,10 @@
/* /*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio * Copyright 2006..2018 Giovanni Di Sirio
* Copyright 2022 QMK contributors
Licensed under the Apache License, Version 2.0 (the "License"); * SPDX-License-Identifier: GPL-2.0-or-later
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* STM32F411xC memory setup.
*/ */
MEMORY
{
flash0 (rx) : org = 0x08000000 + 64k, len = 256k - 64k /* tinyuf2 bootloader requires app to be located at 64k offset for this MCU */
flash1 (rx) : org = 0x00000000, len = 0
flash2 (rx) : org = 0x00000000, len = 0
flash3 (rx) : org = 0x00000000, len = 0
flash4 (rx) : org = 0x00000000, len = 0
flash5 (rx) : org = 0x00000000, len = 0
flash6 (rx) : org = 0x00000000, len = 0
flash7 (rx) : org = 0x00000000, len = 0
ram0 (wx) : org = 0x20000000, len = 128k
ram1 (wx) : org = 0x00000000, len = 0
ram2 (wx) : org = 0x00000000, len = 0
ram3 (wx) : org = 0x00000000, len = 0
ram4 (wx) : org = 0x00000000, len = 0
ram5 (wx) : org = 0x00000000, len = 0
ram6 (wx) : org = 0x00000000, len = 0
ram7 (wx) : org = 0x00000000, len = 0
}
/* For each data/text section two region are defined, a virtual region f4xx_flash_size = 256k;
and a load region (_LMA suffix).*/ f4xx_ram_size = 128k;
/* Flash region to be used for exception vectors.*/
REGION_ALIAS("VECTORS_FLASH", flash0);
REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
/* Flash region to be used for constructors and destructors.*/
REGION_ALIAS("XTORS_FLASH", flash0);
REGION_ALIAS("XTORS_FLASH_LMA", flash0);
/* Flash region to be used for code text.*/
REGION_ALIAS("TEXT_FLASH", flash0);
REGION_ALIAS("TEXT_FLASH_LMA", flash0);
/* Flash region to be used for read only data.*/
REGION_ALIAS("RODATA_FLASH", flash0);
REGION_ALIAS("RODATA_FLASH_LMA", flash0);
/* Flash region to be used for various.*/
REGION_ALIAS("VARIOUS_FLASH", flash0);
REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
/* Flash region to be used for RAM(n) initialization data.*/
REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
/* RAM region to be used for Main stack. This stack accommodates the processing
of all exceptions and interrupts.*/
REGION_ALIAS("MAIN_STACK_RAM", ram0);
/* RAM region to be used for the process stack. This is the stack used by
the main() function.*/
REGION_ALIAS("PROCESS_STACK_RAM", ram0);
/* RAM region to be used for data segment.*/
REGION_ALIAS("DATA_RAM", ram0);
REGION_ALIAS("DATA_RAM_LMA", flash0);
/* RAM region to be used for BSS segment.*/
REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
/* Generic rules inclusion.*/
INCLUDE rules.ld
/* TinyUF2 bootloader reset support */
_board_dfu_dbl_tap = ORIGIN(ram0) + 64k - 4; /* this is based off the linker file for tinyuf2 */
INCLUDE stm32f4xx_tinyuf2_common.ld

View File

@ -1,85 +1,10 @@
/* /*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio * Copyright 2006..2018 Giovanni Di Sirio
* Copyright 2022 QMK contributors
Licensed under the Apache License, Version 2.0 (the "License"); * SPDX-License-Identifier: GPL-2.0-or-later
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* STM32F411xE memory setup.
*/ */
MEMORY
{
flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */
flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */
flash2 (rx) : org = 0x08008000, len = 512k - 32k /* Sector 2..7 - Rest of firmware */
flash3 (rx) : org = 0x00000000, len = 0
flash4 (rx) : org = 0x00000000, len = 0
flash5 (rx) : org = 0x00000000, len = 0
flash6 (rx) : org = 0x00000000, len = 0
flash7 (rx) : org = 0x00000000, len = 0
ram0 (wx) : org = 0x20000000, len = 128k
ram1 (wx) : org = 0x00000000, len = 0
ram2 (wx) : org = 0x00000000, len = 0
ram3 (wx) : org = 0x00000000, len = 0
ram4 (wx) : org = 0x00000000, len = 0
ram5 (wx) : org = 0x00000000, len = 0
ram6 (wx) : org = 0x00000000, len = 0
ram7 (wx) : org = 0x00000000, len = 0
}
/* For each data/text section two region are defined, a virtual region f4xx_flash_size = 512k;
and a load region (_LMA suffix).*/ f4xx_ram_size = 128k;
/* Flash region to be used for exception vectors.*/ INCLUDE stm32f4xx_common.ld
REGION_ALIAS("VECTORS_FLASH", flash0);
REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
/* Flash region to be used for constructors and destructors.*/
REGION_ALIAS("XTORS_FLASH", flash2);
REGION_ALIAS("XTORS_FLASH_LMA", flash2);
/* Flash region to be used for code text.*/
REGION_ALIAS("TEXT_FLASH", flash2);
REGION_ALIAS("TEXT_FLASH_LMA", flash2);
/* Flash region to be used for read only data.*/
REGION_ALIAS("RODATA_FLASH", flash2);
REGION_ALIAS("RODATA_FLASH_LMA", flash2);
/* Flash region to be used for various.*/
REGION_ALIAS("VARIOUS_FLASH", flash2);
REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
/* Flash region to be used for RAM(n) initialization data.*/
REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2);
/* RAM region to be used for Main stack. This stack accommodates the processing
of all exceptions and interrupts.*/
REGION_ALIAS("MAIN_STACK_RAM", ram0);
/* RAM region to be used for the process stack. This is the stack used by
the main() function.*/
REGION_ALIAS("PROCESS_STACK_RAM", ram0);
/* RAM region to be used for data segment.*/
REGION_ALIAS("DATA_RAM", ram0);
REGION_ALIAS("DATA_RAM_LMA", flash2);
/* RAM region to be used for BSS segment.*/
REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
/* Generic rules inclusion.*/
INCLUDE rules.ld

View File

@ -1,89 +1,10 @@
/* /*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio * Copyright 2006..2018 Giovanni Di Sirio
* Copyright 2022 QMK contributors
Licensed under the Apache License, Version 2.0 (the "License"); * SPDX-License-Identifier: GPL-2.0-or-later
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* STM32F411xE memory setup.
*/ */
MEMORY
{
flash0 (rx) : org = 0x08000000 + 64k, len = 512k - 64k /* tinyuf2 bootloader requires app to be located at 64k offset for this MCU */
flash1 (rx) : org = 0x00000000, len = 0
flash2 (rx) : org = 0x00000000, len = 0
flash3 (rx) : org = 0x00000000, len = 0
flash4 (rx) : org = 0x00000000, len = 0
flash5 (rx) : org = 0x00000000, len = 0
flash6 (rx) : org = 0x00000000, len = 0
flash7 (rx) : org = 0x00000000, len = 0
ram0 (wx) : org = 0x20000000, len = 128k
ram1 (wx) : org = 0x00000000, len = 0
ram2 (wx) : org = 0x00000000, len = 0
ram3 (wx) : org = 0x00000000, len = 0
ram4 (wx) : org = 0x00000000, len = 0
ram5 (wx) : org = 0x00000000, len = 0
ram6 (wx) : org = 0x00000000, len = 0
ram7 (wx) : org = 0x00000000, len = 0
}
/* For each data/text section two region are defined, a virtual region f4xx_flash_size = 512k;
and a load region (_LMA suffix).*/ f4xx_ram_size = 128k;
/* Flash region to be used for exception vectors.*/
REGION_ALIAS("VECTORS_FLASH", flash0);
REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
/* Flash region to be used for constructors and destructors.*/
REGION_ALIAS("XTORS_FLASH", flash0);
REGION_ALIAS("XTORS_FLASH_LMA", flash0);
/* Flash region to be used for code text.*/
REGION_ALIAS("TEXT_FLASH", flash0);
REGION_ALIAS("TEXT_FLASH_LMA", flash0);
/* Flash region to be used for read only data.*/
REGION_ALIAS("RODATA_FLASH", flash0);
REGION_ALIAS("RODATA_FLASH_LMA", flash0);
/* Flash region to be used for various.*/
REGION_ALIAS("VARIOUS_FLASH", flash0);
REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
/* Flash region to be used for RAM(n) initialization data.*/
REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
/* RAM region to be used for Main stack. This stack accommodates the processing
of all exceptions and interrupts.*/
REGION_ALIAS("MAIN_STACK_RAM", ram0);
/* RAM region to be used for the process stack. This is the stack used by
the main() function.*/
REGION_ALIAS("PROCESS_STACK_RAM", ram0);
/* RAM region to be used for data segment.*/
REGION_ALIAS("DATA_RAM", ram0);
REGION_ALIAS("DATA_RAM_LMA", flash0);
/* RAM region to be used for BSS segment.*/
REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
/* Generic rules inclusion.*/
INCLUDE rules.ld
/* TinyUF2 bootloader reset support */
_board_dfu_dbl_tap = ORIGIN(ram0) + 64k - 4; /* this is based off the linker file for tinyuf2 */
INCLUDE stm32f4xx_tinyuf2_common.ld

View File

@ -0,0 +1,83 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
MEMORY
{
flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */
flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */
flash2 (rx) : org = 0x08008000, len = f4xx_flash_size - 32k /* Sector 2..6 - Rest of firmware */
flash3 (rx) : org = 0x00000000, len = 0
flash4 (rx) : org = 0x00000000, len = 0
flash5 (rx) : org = 0x00000000, len = 0
flash6 (rx) : org = 0x00000000, len = 0
flash7 (rx) : org = 0x00000000, len = 0
ram0 (wx) : org = 0x20000000, len = f4xx_ram_size
ram1 (wx) : org = 0x00000000, len = 0
ram2 (wx) : org = 0x00000000, len = 0
ram3 (wx) : org = 0x00000000, len = 0
ram4 (wx) : org = 0x00000000, len = 0
ram5 (wx) : org = 0x00000000, len = 0
ram6 (wx) : org = 0x00000000, len = 0
ram7 (wx) : org = 0x00000000, len = 0
}
/* For each data/text section two region are defined, a virtual region
and a load region (_LMA suffix).*/
/* Flash region to be used for exception vectors.*/
REGION_ALIAS("VECTORS_FLASH", flash0);
REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
/* Flash region to be used for constructors and destructors.*/
REGION_ALIAS("XTORS_FLASH", flash2);
REGION_ALIAS("XTORS_FLASH_LMA", flash2);
/* Flash region to be used for code text.*/
REGION_ALIAS("TEXT_FLASH", flash2);
REGION_ALIAS("TEXT_FLASH_LMA", flash2);
/* Flash region to be used for read only data.*/
REGION_ALIAS("RODATA_FLASH", flash2);
REGION_ALIAS("RODATA_FLASH_LMA", flash2);
/* Flash region to be used for various.*/
REGION_ALIAS("VARIOUS_FLASH", flash2);
REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
/* Flash region to be used for RAM(n) initialization data.*/
REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2);
/* RAM region to be used for Main stack. This stack accommodates the processing
of all exceptions and interrupts.*/
REGION_ALIAS("MAIN_STACK_RAM", ram0);
/* RAM region to be used for the process stack. This is the stack used by
the main() function.*/
REGION_ALIAS("PROCESS_STACK_RAM", ram0);
/* RAM region to be used for data segment.*/
REGION_ALIAS("DATA_RAM", ram0);
REGION_ALIAS("DATA_RAM_LMA", flash2);
/* RAM region to be used for BSS segment.*/
REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
/* Generic rules inclusion.*/
INCLUDE rules.ld

View File

@ -0,0 +1,90 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* STM32F411xE memory setup.
*/
MEMORY
{
flash0 (rx) : org = 0x08000000 + 64k, len = f4xx_flash_size - 64k /* tinyuf2 bootloader requires app to be located at 64k offset for this MCU */
flash1 (rx) : org = 0x00000000, len = 0
flash2 (rx) : org = 0x00000000, len = 0
flash3 (rx) : org = 0x00000000, len = 0
flash4 (rx) : org = 0x00000000, len = 0
flash5 (rx) : org = 0x00000000, len = 0
flash6 (rx) : org = 0x00000000, len = 0
flash7 (rx) : org = 0x00000000, len = 0
ram0 (wx) : org = 0x20000000, len = f4xx_ram_size
ram1 (wx) : org = 0x00000000, len = 0
ram2 (wx) : org = 0x00000000, len = 0
ram3 (wx) : org = 0x00000000, len = 0
ram4 (wx) : org = 0x00000000, len = 0
ram5 (wx) : org = 0x00000000, len = 0
ram6 (wx) : org = 0x00000000, len = 0
ram7 (wx) : org = 0x00000000, len = 0
}
/* For each data/text section two region are defined, a virtual region
and a load region (_LMA suffix).*/
/* Flash region to be used for exception vectors.*/
REGION_ALIAS("VECTORS_FLASH", flash0);
REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
/* Flash region to be used for constructors and destructors.*/
REGION_ALIAS("XTORS_FLASH", flash0);
REGION_ALIAS("XTORS_FLASH_LMA", flash0);
/* Flash region to be used for code text.*/
REGION_ALIAS("TEXT_FLASH", flash0);
REGION_ALIAS("TEXT_FLASH_LMA", flash0);
/* Flash region to be used for read only data.*/
REGION_ALIAS("RODATA_FLASH", flash0);
REGION_ALIAS("RODATA_FLASH_LMA", flash0);
/* Flash region to be used for various.*/
REGION_ALIAS("VARIOUS_FLASH", flash0);
REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
/* Flash region to be used for RAM(n) initialization data.*/
REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
/* RAM region to be used for Main stack. This stack accommodates the processing
of all exceptions and interrupts.*/
REGION_ALIAS("MAIN_STACK_RAM", ram0);
/* RAM region to be used for the process stack. This is the stack used by
the main() function.*/
REGION_ALIAS("PROCESS_STACK_RAM", ram0);
/* RAM region to be used for data segment.*/
REGION_ALIAS("DATA_RAM", ram0);
REGION_ALIAS("DATA_RAM_LMA", flash0);
/* RAM region to be used for BSS segment.*/
REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
/* Generic rules inclusion.*/
INCLUDE rules.ld
/* TinyUF2 bootloader reset support */
_board_dfu_dbl_tap = ORIGIN(ram0) + 64k - 4; /* this is based off the linker file for tinyuf2 */

View File

@ -19,13 +19,33 @@
#include "timer.h" #include "timer.h"
static bool spiStarted = false; static bool spiStarted = false;
#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE #if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
static pin_t currentSlavePin; static pin_t current_slave_pin = NO_PIN;
static bool current_cs_active_low = true;
#endif #endif
static SPIConfig spiConfig; static SPIConfig spiConfig;
static inline void spi_select(void) {
spiSelect(&SPI_DRIVER);
#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
if (current_slave_pin != NO_PIN) {
gpio_write_pin(current_slave_pin, current_cs_active_low ? 0 : 1);
}
#endif
}
static inline void spi_unselect(void) {
#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
if (current_slave_pin != NO_PIN) {
gpio_write_pin(current_slave_pin, current_cs_active_low ? 1 : 0);
}
#endif
spiUnselect(&SPI_DRIVER);
}
__attribute__((weak)) void spi_init(void) { __attribute__((weak)) void spi_init(void) {
static bool is_initialised = false; static bool is_initialised = false;
if (!is_initialised) { if (!is_initialised) {
@ -63,7 +83,7 @@ __attribute__((weak)) void spi_init(void) {
} }
} }
bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) { bool spi_start_extended(spi_start_config_t *start_config) {
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE) #if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
spiAcquireBus(&SPI_DRIVER); spiAcquireBus(&SPI_DRIVER);
#endif // (SPI_USE_MUTUAL_EXCLUSION == TRUE) #endif // (SPI_USE_MUTUAL_EXCLUSION == TRUE)
@ -71,16 +91,15 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
if (spiStarted) { if (spiStarted) {
return false; return false;
} }
#if SPI_SELECT_MODE != SPI_SELECT_MODE_NONE #if SPI_SELECT_MODE != SPI_SELECT_MODE_NONE
if (slavePin == NO_PIN) { if (start_config->slave_pin == NO_PIN) {
return false; return false;
} }
#endif #endif
#if !(defined(WB32F3G71xx) || defined(WB32FQ95xx)) #if !(defined(WB32F3G71xx) || defined(WB32FQ95xx))
uint16_t roundedDivisor = 2; uint16_t roundedDivisor = 2;
while (roundedDivisor < divisor) { while (roundedDivisor < start_config->divisor) {
roundedDivisor <<= 1; roundedDivisor <<= 1;
} }
@ -92,11 +111,11 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
#if defined(K20x) || defined(KL2x) #if defined(K20x) || defined(KL2x)
spiConfig.tar0 = SPIx_CTARn_FMSZ(7) | SPIx_CTARn_ASC(1); spiConfig.tar0 = SPIx_CTARn_FMSZ(7) | SPIx_CTARn_ASC(1);
if (lsbFirst) { if (start_config->lsb_first) {
spiConfig.tar0 |= SPIx_CTARn_LSBFE; spiConfig.tar0 |= SPIx_CTARn_LSBFE;
} }
switch (mode) { switch (start_config->mode) {
case 0: case 0:
break; break;
case 1: case 1:
@ -141,11 +160,11 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
spiConfig.cr0 = SPI_CR0_SELOEN; spiConfig.cr0 = SPI_CR0_SELOEN;
spiConfig.cr1 = SPI_CR1_MODE | 8; // 8 bits and in master mode spiConfig.cr1 = SPI_CR1_MODE | 8; // 8 bits and in master mode
if (lsbFirst) { if (start_config->lsb_first) {
spiConfig.cr1 |= SPI_CR1_FIRSTBIT; spiConfig.cr1 |= SPI_CR1_FIRSTBIT;
} }
switch (mode) { switch (start_config->mode) {
case 0: case 0:
spiConfig.cr1 |= SPI_CR1_FORMAT_MODE0; spiConfig.cr1 |= SPI_CR1_FORMAT_MODE0;
break; break;
@ -163,17 +182,17 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
spiConfig.cpr = (roundedDivisor - 1) >> 1; spiConfig.cpr = (roundedDivisor - 1) >> 1;
#elif defined(WB32F3G71xx) || defined(WB32FQ95xx) #elif defined(WB32F3G71xx) || defined(WB32FQ95xx)
if (!lsbFirst) { if (!start_config->lsb_first) {
osalDbgAssert(lsbFirst != FALSE, "unsupported lsbFirst"); osalDbgAssert(start_config->lsb_first != FALSE, "unsupported lsb_first");
} }
if (divisor < 1) { if (start_config->divisor < 1) {
return false; return false;
} }
spiConfig.SPI_BaudRatePrescaler = (divisor << 2); spiConfig.SPI_BaudRatePrescaler = (start_config->divisor << 2);
switch (mode) { switch (start_config->mode) {
case 0: case 0:
spiConfig.SPI_CPHA = SPI_CPHA_1Edge; spiConfig.SPI_CPHA = SPI_CPHA_1Edge;
spiConfig.SPI_CPOL = SPI_CPOL_Low; spiConfig.SPI_CPOL = SPI_CPOL_Low;
@ -192,8 +211,8 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
break; break;
} }
#elif defined(MCU_RP) #elif defined(MCU_RP)
if (lsbFirst) { if (start_config->lsb_first) {
osalDbgAssert(lsbFirst == false, "RP2040s PrimeCell SPI implementation does not support sending LSB first."); osalDbgAssert(start_config->lsb_first == false, "RP2040s PrimeCell SPI implementation does not support sending LSB first.");
} }
// Motorola frame format and 8bit transfer data size. // Motorola frame format and 8bit transfer data size.
@ -203,7 +222,7 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
// passed divisor to be the only value to divide the input clock by. // passed divisor to be the only value to divide the input clock by.
spiConfig.SSPCPSR = roundedDivisor; // Even number from 2 to 254 spiConfig.SSPCPSR = roundedDivisor; // Even number from 2 to 254
switch (mode) { switch (start_config->mode) {
case 0: case 0:
spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low
spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge
@ -224,11 +243,11 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
#else #else
spiConfig.cr1 = 0; spiConfig.cr1 = 0;
if (lsbFirst) { if (start_config->lsb_first) {
spiConfig.cr1 |= SPI_CR1_LSBFIRST; spiConfig.cr1 |= SPI_CR1_LSBFIRST;
} }
switch (mode) { switch (start_config->mode) {
case 0: case 0:
break; break;
case 1: case 1:
@ -271,31 +290,37 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
spiStarted = true; spiStarted = true;
#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE #if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
currentSlavePin = slavePin; current_slave_pin = start_config->slave_pin;
current_cs_active_low = start_config->cs_active_low;
#endif #endif
#if SPI_SELECT_MODE == SPI_SELECT_MODE_PAD #if SPI_SELECT_MODE == SPI_SELECT_MODE_PAD
spiConfig.ssport = PAL_PORT(slavePin); spiConfig.ssport = PAL_PORT(start_config->slave_pin);
spiConfig.sspad = PAL_PAD(slavePin); spiConfig.sspad = PAL_PAD(start_config->slave_pin);
gpio_set_pin_output(slavePin); gpio_set_pin_output(start_config->slave_pin);
#elif SPI_SELECT_MODE == SPI_SELECT_MODE_NONE #elif SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
if (slavePin != NO_PIN) { if (start_config->slave_pin != NO_PIN) {
gpio_set_pin_output(slavePin); gpio_set_pin_output(start_config->slave_pin);
} }
#else #else
# error "Unsupported SPI_SELECT_MODE" # error "Unsupported SPI_SELECT_MODE"
#endif #endif
spiStart(&SPI_DRIVER, &spiConfig); spiStart(&SPI_DRIVER, &spiConfig);
spiSelect(&SPI_DRIVER); spi_select();
#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
if (slavePin != NO_PIN) {
gpio_write_pin_low(slavePin);
}
#endif
return true; return true;
} }
bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
spi_start_config_t start_config = {0};
start_config.slave_pin = slavePin;
start_config.lsb_first = lsbFirst;
start_config.mode = mode;
start_config.divisor = divisor;
start_config.cs_active_low = true;
return spi_start_extended(&start_config);
}
spi_status_t spi_write(uint8_t data) { spi_status_t spi_write(uint8_t data) {
uint8_t rxData; uint8_t rxData;
spiExchange(&SPI_DRIVER, 1, &data, &rxData); spiExchange(&SPI_DRIVER, 1, &data, &rxData);
@ -322,12 +347,7 @@ spi_status_t spi_receive(uint8_t *data, uint16_t length) {
void spi_stop(void) { void spi_stop(void) {
if (spiStarted) { if (spiStarted) {
#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE spi_unselect();
if (currentSlavePin != NO_PIN) {
gpio_write_pin_high(currentSlavePin);
}
#endif
spiUnselect(&SPI_DRIVER);
spiStop(&SPI_DRIVER); spiStop(&SPI_DRIVER);
spiStarted = false; spiStarted = false;
} }

View File

@ -75,9 +75,18 @@ typedef int16_t spi_status_t;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef struct spi_start_config_t {
pin_t slave_pin;
bool lsb_first;
uint8_t mode;
uint16_t divisor;
bool cs_active_low;
} spi_start_config_t;
void spi_init(void); void spi_init(void);
bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor); bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor);
bool spi_start_extended(spi_start_config_t *start_config);
spi_status_t spi_write(uint8_t data); spi_status_t spi_write(uint8_t data);

View File

@ -133,7 +133,7 @@ static void set_led_color_rgb(rgb_led_t color, int pos) {
#endif #endif
#ifdef WS2812_RGBW #ifdef WS2812_RGBW
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 4 + j] = get_protocol_eq(color.w, j); tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 3 + j] = get_protocol_eq(color.w, j);
#endif #endif
} }

View File

@ -387,7 +387,6 @@ struct led_matrix_limits_t led_matrix_get_limits(uint8_t iter) {
limits.led_min_index = LED_MATRIX_LED_PROCESS_LIMIT * (iter); limits.led_min_index = LED_MATRIX_LED_PROCESS_LIMIT * (iter);
limits.led_max_index = limits.led_min_index + LED_MATRIX_LED_PROCESS_LIMIT; limits.led_max_index = limits.led_min_index + LED_MATRIX_LED_PROCESS_LIMIT;
if (limits.led_max_index > LED_MATRIX_LED_COUNT) limits.led_max_index = LED_MATRIX_LED_COUNT; if (limits.led_max_index > LED_MATRIX_LED_COUNT) limits.led_max_index = LED_MATRIX_LED_COUNT;
uint8_t k_led_matrix_split[2] = LED_MATRIX_SPLIT;
if (is_keyboard_left() && (limits.led_max_index > k_led_matrix_split[0])) limits.led_max_index = k_led_matrix_split[0]; if (is_keyboard_left() && (limits.led_max_index > k_led_matrix_split[0])) limits.led_max_index = k_led_matrix_split[0];
if (!(is_keyboard_left()) && (limits.led_min_index < k_led_matrix_split[0])) limits.led_min_index = k_led_matrix_split[0]; if (!(is_keyboard_left()) && (limits.led_min_index < k_led_matrix_split[0])) limits.led_min_index = k_led_matrix_split[0];
# else # else
@ -397,9 +396,8 @@ struct led_matrix_limits_t led_matrix_get_limits(uint8_t iter) {
# endif # endif
#else #else
# if defined(LED_MATRIX_SPLIT) # if defined(LED_MATRIX_SPLIT)
limits.led_min_index = 0; limits.led_min_index = 0;
limits.led_max_index = LED_MATRIX_LED_COUNT; limits.led_max_index = LED_MATRIX_LED_COUNT;
const uint8_t k_led_matrix_split[2] = LED_MATRIX_SPLIT;
if (is_keyboard_left() && (limits.led_max_index > k_led_matrix_split[0])) limits.led_max_index = k_led_matrix_split[0]; if (is_keyboard_left() && (limits.led_max_index > k_led_matrix_split[0])) limits.led_max_index = k_led_matrix_split[0];
if (!(is_keyboard_left()) && (limits.led_min_index < k_led_matrix_split[0])) limits.led_min_index = k_led_matrix_split[0]; if (!(is_keyboard_left()) && (limits.led_min_index < k_led_matrix_split[0])) limits.led_min_index = k_led_matrix_split[0];
# else # else

View File

@ -557,6 +557,12 @@ int16_t qp_drawtext_recolor(painter_device_t device, uint16_t x, uint16_t y, pai
# define SH1106_NUM_DEVICES 0 # define SH1106_NUM_DEVICES 0
#endif // QUANTUM_PAINTER_SH1106_ENABLE #endif // QUANTUM_PAINTER_SH1106_ENABLE
#ifdef QUANTUM_PAINTER_LD7032_ENABLE
# include "qp_ld7032.h"
#else // QUANTUM_PAINTER_LD7032_ENABLE
# define LD7032_NUM_DEVICES 0
#endif // QUANTUM_PAINTER_LD7032_ENABLE
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Quantum Painter Extras // Quantum Painter Extras

View File

@ -19,6 +19,7 @@ enum {
+ (GC9107_NUM_DEVICES) // GC9107 + (GC9107_NUM_DEVICES) // GC9107
+ (SSD1351_NUM_DEVICES) // SSD1351 + (SSD1351_NUM_DEVICES) // SSD1351
+ (SH1106_NUM_DEVICES) // SH1106 + (SH1106_NUM_DEVICES) // SH1106
+ (LD7032_NUM_DEVICES) // LD7032
}; };
static painter_device_t qp_devices[QP_NUM_DEVICES] = {NULL}; static painter_device_t qp_devices[QP_NUM_DEVICES] = {NULL};

View File

@ -17,7 +17,9 @@ VALID_QUANTUM_PAINTER_DRIVERS := \
gc9107_spi \ gc9107_spi \
ssd1351_spi \ ssd1351_spi \
sh1106_i2c \ sh1106_i2c \
sh1106_spi sh1106_spi \
ld7032_i2c \
ld7032_spi
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@ -182,6 +184,29 @@ define handle_quantum_painter_driver
$(DRIVER_PATH)/painter/oled_panel/qp_oled_panel.c \ $(DRIVER_PATH)/painter/oled_panel/qp_oled_panel.c \
$(DRIVER_PATH)/painter/sh1106/qp_sh1106.c $(DRIVER_PATH)/painter/sh1106/qp_sh1106.c
else ifeq ($$(strip $$(CURRENT_PAINTER_DRIVER)),ld7032_spi)
QUANTUM_PAINTER_NEEDS_SURFACE := yes
QUANTUM_PAINTER_NEEDS_COMMS_SPI := yes
QUANTUM_PAINTER_NEEDS_COMMS_SPI_DC_RESET := yes
OPT_DEFS += -DQUANTUM_PAINTER_LD7032_ENABLE -DQUANTUM_PAINTER_LD7032_SPI_ENABLE
COMMON_VPATH += \
$(DRIVER_PATH)/painter/oled_panel \
$(DRIVER_PATH)/painter/ld7032
SRC += \
$(DRIVER_PATH)/painter/oled_panel/qp_oled_panel.c \
$(DRIVER_PATH)/painter/ld7032/qp_ld7032.c
else ifeq ($$(strip $$(CURRENT_PAINTER_DRIVER)),ld7032_i2c)
QUANTUM_PAINTER_NEEDS_SURFACE := yes
QUANTUM_PAINTER_NEEDS_COMMS_I2C := yes
OPT_DEFS += -DQUANTUM_PAINTER_LD7032_ENABLE -DQUANTUM_PAINTER_LD7032_I2C_ENABLE
COMMON_VPATH += \
$(DRIVER_PATH)/painter/oled_panel \
$(DRIVER_PATH)/painter/ld7032
SRC += \
$(DRIVER_PATH)/painter/oled_panel/qp_oled_panel.c \
$(DRIVER_PATH)/painter/ld7032/qp_ld7032.c
endif endif
endef endef

View File

@ -65,12 +65,20 @@ __attribute__((weak)) bool process_combo_key_release(uint16_t combo_index, combo
} }
#endif #endif
#ifdef COMBO_PROCESS_KEY_REPRESS
__attribute__((weak)) bool process_combo_key_repress(uint16_t combo_index, combo_t *combo, uint8_t key_index, uint16_t keycode) {
return false;
}
#endif
#ifdef COMBO_SHOULD_TRIGGER #ifdef COMBO_SHOULD_TRIGGER
__attribute__((weak)) bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode, keyrecord_t *record) { __attribute__((weak)) bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode, keyrecord_t *record) {
return true; return true;
} }
#endif #endif
typedef enum { COMBO_KEY_NOT_PRESSED, COMBO_KEY_PRESSED, COMBO_KEY_REPRESSED } combo_key_action_t;
#ifndef COMBO_NO_TIMER #ifndef COMBO_NO_TIMER
static uint16_t timer = 0; static uint16_t timer = 0;
#endif #endif
@ -414,14 +422,14 @@ static bool keys_pressed_in_order(uint16_t combo_index, combo_t *combo, uint16_t
} }
#endif #endif
static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record, uint16_t combo_index) { static combo_key_action_t process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record, uint16_t combo_index) {
uint8_t key_count = 0; uint8_t key_count = 0;
uint16_t key_index = -1; uint16_t key_index = -1;
_find_key_index_and_count(combo->keys, keycode, &key_index, &key_count); _find_key_index_and_count(combo->keys, keycode, &key_index, &key_count);
/* Continue processing if key isn't part of current combo. */ /* Continue processing if key isn't part of current combo. */
if (-1 == (int16_t)key_index) { if (-1 == (int16_t)key_index) {
return false; return COMBO_KEY_NOT_PRESSED;
} }
bool key_is_part_of_combo = (!COMBO_DISABLED(combo) && is_combo_enabled() bool key_is_part_of_combo = (!COMBO_DISABLED(combo) && is_combo_enabled()
@ -449,7 +457,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
/* Don't buffer this combo if its combo term has passed. */ /* Don't buffer this combo if its combo term has passed. */
if (timer && timer_elapsed(timer) > time) { if (timer && timer_elapsed(timer) > time) {
DISABLE_COMBO(combo); DISABLE_COMBO(combo);
return true; return COMBO_KEY_PRESSED;
} else } else
#endif #endif
{ {
@ -485,6 +493,15 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
} }
} // if timer elapsed end } // if timer elapsed end
} }
#ifdef COMBO_PROCESS_KEY_REPRESS
} else if (record->event.pressed) {
if (COMBO_ACTIVE(combo)) {
if (process_combo_key_repress(combo_index, combo, key_index, keycode)) {
KEY_STATE_DOWN(combo->state, key_index);
return COMBO_KEY_REPRESSED;
}
}
#endif
} else { } else {
// chord releases // chord releases
if (!COMBO_ACTIVE(combo) && ALL_COMBO_KEYS_ARE_DOWN(COMBO_STATE(combo), key_count)) { if (!COMBO_ACTIVE(combo) && ALL_COMBO_KEYS_ARE_DOWN(COMBO_STATE(combo), key_count)) {
@ -531,12 +548,12 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
KEY_STATE_UP(combo->state, key_index); KEY_STATE_UP(combo->state, key_index);
} }
return key_is_part_of_combo; return key_is_part_of_combo ? COMBO_KEY_PRESSED : COMBO_KEY_NOT_PRESSED;
} }
bool process_combo(uint16_t keycode, keyrecord_t *record) { bool process_combo(uint16_t keycode, keyrecord_t *record) {
bool is_combo_key = false; uint8_t is_combo_key = COMBO_KEY_NOT_PRESSED;
bool no_combo_keys_pressed = true; bool no_combo_keys_pressed = true;
if (keycode == QK_COMBO_ON && record->event.pressed) { if (keycode == QK_COMBO_ON && record->event.pressed) {
combo_enable(); combo_enable();
@ -582,12 +599,17 @@ bool process_combo(uint16_t keycode, keyrecord_t *record) {
# endif # endif
#endif #endif
if (key_buffer_size < COMBO_KEY_BUFFER_LENGTH) { #ifdef COMBO_PROCESS_KEY_REPRESS
key_buffer[key_buffer_size++] = (queued_record_t){ if (is_combo_key == COMBO_KEY_PRESSED)
.record = *record, #endif
.keycode = keycode, {
.combo_index = -1, // this will be set when applying combos if (key_buffer_size < COMBO_KEY_BUFFER_LENGTH) {
}; key_buffer[key_buffer_size++] = (queued_record_t){
.record = *record,
.keycode = keycode,
.combo_index = -1, // this will be set when applying combos
};
}
} }
} else { } else {
if (combo_buffer_read != combo_buffer_write) { if (combo_buffer_read != combo_buffer_write) {

View File

@ -83,6 +83,11 @@ static uint32_t rgb_timer_buffer;
static last_hit_t last_hit_buffer; static last_hit_t last_hit_buffer;
#endif // RGB_MATRIX_KEYREACTIVE_ENABLED #endif // RGB_MATRIX_KEYREACTIVE_ENABLED
// split rgb matrix
#if defined(RGB_MATRIX_SPLIT)
const uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT;
#endif
EECONFIG_DEBOUNCE_HELPER(rgb_matrix, rgb_matrix_config); EECONFIG_DEBOUNCE_HELPER(rgb_matrix, rgb_matrix_config);
void eeconfig_force_flush_rgb_matrix(void) { void eeconfig_force_flush_rgb_matrix(void) {
@ -399,7 +404,6 @@ struct rgb_matrix_limits_t rgb_matrix_get_limits(uint8_t iter) {
limits.led_min_index = RGB_MATRIX_LED_PROCESS_LIMIT * (iter); limits.led_min_index = RGB_MATRIX_LED_PROCESS_LIMIT * (iter);
limits.led_max_index = limits.led_min_index + RGB_MATRIX_LED_PROCESS_LIMIT; limits.led_max_index = limits.led_min_index + RGB_MATRIX_LED_PROCESS_LIMIT;
if (limits.led_max_index > RGB_MATRIX_LED_COUNT) limits.led_max_index = RGB_MATRIX_LED_COUNT; if (limits.led_max_index > RGB_MATRIX_LED_COUNT) limits.led_max_index = RGB_MATRIX_LED_COUNT;
uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT;
if (is_keyboard_left() && (limits.led_max_index > k_rgb_matrix_split[0])) limits.led_max_index = k_rgb_matrix_split[0]; if (is_keyboard_left() && (limits.led_max_index > k_rgb_matrix_split[0])) limits.led_max_index = k_rgb_matrix_split[0];
if (!(is_keyboard_left()) && (limits.led_min_index < k_rgb_matrix_split[0])) limits.led_min_index = k_rgb_matrix_split[0]; if (!(is_keyboard_left()) && (limits.led_min_index < k_rgb_matrix_split[0])) limits.led_min_index = k_rgb_matrix_split[0];
# else # else
@ -409,9 +413,8 @@ struct rgb_matrix_limits_t rgb_matrix_get_limits(uint8_t iter) {
# endif # endif
#else #else
# if defined(RGB_MATRIX_SPLIT) # if defined(RGB_MATRIX_SPLIT)
limits.led_min_index = 0; limits.led_min_index = 0;
limits.led_max_index = RGB_MATRIX_LED_COUNT; limits.led_max_index = RGB_MATRIX_LED_COUNT;
const uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT;
if (is_keyboard_left() && (limits.led_max_index > k_rgb_matrix_split[0])) limits.led_max_index = k_rgb_matrix_split[0]; if (is_keyboard_left() && (limits.led_max_index > k_rgb_matrix_split[0])) limits.led_max_index = k_rgb_matrix_split[0];
if (!(is_keyboard_left()) && (limits.led_min_index < k_rgb_matrix_split[0])) limits.led_min_index = k_rgb_matrix_split[0]; if (!(is_keyboard_left()) && (limits.led_min_index < k_rgb_matrix_split[0])) limits.led_min_index = k_rgb_matrix_split[0];
# else # else

View File

@ -0,0 +1,10 @@
// Copyright 2024 @Filios92
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "test_common.h"
#define TAPPING_TERM 200
#define COMBO_PROCESS_KEY_REPRESS

View File

@ -0,0 +1,6 @@
# Copyright 2024 @Filios92
# SPDX-License-Identifier: GPL-2.0-or-later
COMBO_ENABLE = yes
INTROSPECTION_KEYMAP_C = test_combos_repress.c

View File

@ -0,0 +1,158 @@
// Copyright 2024 @Filios92
// SPDX-License-Identifier: GPL-2.0-or-later
#include "keyboard_report_util.hpp"
#include "quantum.h"
#include "keycode.h"
#include "test_common.h"
#include "test_driver.hpp"
#include "test_fixture.hpp"
#include "test_keymap_key.hpp"
using testing::_;
using testing::InSequence;
class ComboRepress : public TestFixture {};
TEST_F(ComboRepress, combo_repress_tapped) {
TestDriver driver;
KeymapKey key_f(0, 0, 0, KC_F);
KeymapKey key_g(0, 0, 1, KC_G);
set_keymap({key_f, key_g});
EXPECT_REPORT(driver, (KC_LEFT_ALT)).Times(2);
EXPECT_REPORT(driver, (KC_TAB, KC_LEFT_ALT));
EXPECT_EMPTY_REPORT(driver);
tap_combo({key_f, key_g}, 20);
VERIFY_AND_CLEAR(driver);
}
TEST_F(ComboRepress, combo_repress_held_released_one_key_and_repressed) {
TestDriver driver;
KeymapKey key_f(0, 0, 0, KC_F);
KeymapKey key_g(0, 0, 1, KC_G);
KeymapKey key_h(0, 0, 2, KC_H);
KeymapKey key_j(0, 0, 3, KC_J);
set_keymap({key_f, key_g, key_h, key_j});
/* Press combo F+G */
EXPECT_REPORT(driver, (KC_LEFT_ALT)).Times(2);
EXPECT_REPORT(driver, (KC_TAB, KC_LEFT_ALT));
key_f.press();
run_one_scan_loop();
key_g.press();
run_one_scan_loop();
idle_for(COMBO_TERM + 1);
VERIFY_AND_CLEAR(driver);
/* Release G */
EXPECT_NO_REPORT(driver);
key_g.release();
idle_for(80);
VERIFY_AND_CLEAR(driver);
/* Tap G */
EXPECT_REPORT(driver, (KC_TAB, KC_LEFT_ALT));
EXPECT_REPORT(driver, (KC_LEFT_ALT));
tap_key(key_g, TAPPING_TERM + 1);
VERIFY_AND_CLEAR(driver);
/* Tap G, but hold for longer */
EXPECT_REPORT(driver, (KC_TAB, KC_LEFT_ALT));
EXPECT_REPORT(driver, (KC_LEFT_ALT));
tap_key(key_g, TAPPING_TERM * 2);
VERIFY_AND_CLEAR(driver);
idle_for(500);
/* Tap other combo while holding F */
EXPECT_REPORT(driver, (KC_ESCAPE, KC_LEFT_ALT));
EXPECT_REPORT(driver, (KC_LEFT_ALT));
tap_combo({key_h, key_j}, TAPPING_TERM + 1);
VERIFY_AND_CLEAR(driver);
/* G press and hold */
EXPECT_REPORT(driver, (KC_TAB, KC_LEFT_ALT));
EXPECT_REPORT(driver, (KC_LEFT_ALT));
key_g.press();
run_one_scan_loop();
VERIFY_AND_CLEAR(driver);
/* F release and tap */
EXPECT_REPORT(driver, (KC_LEFT_ALT, KC_LEFT_SHIFT)).Times(2);
EXPECT_REPORT(driver, (KC_TAB, KC_LEFT_ALT, KC_LEFT_SHIFT));
EXPECT_REPORT(driver, (KC_LEFT_ALT));
key_f.release();
run_one_scan_loop();
tap_key(key_f);
VERIFY_AND_CLEAR(driver);
/* Release G */
EXPECT_EMPTY_REPORT(driver);
key_g.release();
run_one_scan_loop();
VERIFY_AND_CLEAR(driver);
}
TEST_F(ComboRepress, combo_repress_normal_combo) {
TestDriver driver;
KeymapKey key_f(0, 0, 0, KC_F);
KeymapKey key_g(0, 0, 1, KC_G);
KeymapKey key_h(0, 0, 2, KC_H);
KeymapKey key_j(0, 0, 3, KC_J);
set_keymap({key_f, key_g, key_h, key_j});
/* Press combo H+J */
EXPECT_REPORT(driver, (KC_ESCAPE));
key_h.press();
run_one_scan_loop();
key_j.press();
run_one_scan_loop();
idle_for(COMBO_TERM + 10);
VERIFY_AND_CLEAR(driver);
/* Release H */
EXPECT_NO_REPORT(driver);
key_h.release();
idle_for(80);
VERIFY_AND_CLEAR(driver);
/* Tap H */
EXPECT_REPORT(driver, (KC_H, KC_ESCAPE));
EXPECT_REPORT(driver, (KC_ESCAPE));
tap_key(key_h);
VERIFY_AND_CLEAR(driver);
/* Tap H, but hold for longer */
EXPECT_REPORT(driver, (KC_H, KC_ESCAPE));
EXPECT_REPORT(driver, (KC_ESCAPE));
tap_key(key_h, TAPPING_TERM + 1);
VERIFY_AND_CLEAR(driver);
idle_for(500);
/* Tap other combo while holding K */
EXPECT_REPORT(driver, (KC_ESCAPE, KC_LEFT_ALT)).Times(2);
EXPECT_REPORT(driver, (KC_ESCAPE, KC_TAB, KC_LEFT_ALT));
EXPECT_REPORT(driver, (KC_ESCAPE));
tap_combo({key_f, key_g}, TAPPING_TERM + 1);
VERIFY_AND_CLEAR(driver);
/* H press and hold */
EXPECT_REPORT(driver, (KC_H, KC_ESCAPE));
key_h.press();
run_one_scan_loop();
VERIFY_AND_CLEAR(driver);
/* J release and tap */
EXPECT_REPORT(driver, (KC_H));
key_j.release();
run_one_scan_loop();
VERIFY_AND_CLEAR(driver);
/* Release G */
EXPECT_EMPTY_REPORT(driver);
key_h.release();
run_one_scan_loop();
VERIFY_AND_CLEAR(driver);
}

View File

@ -0,0 +1,43 @@
// Copyright 2024 @Filios92
// SPDX-License-Identifier: GPL-2.0-or-later
#include "quantum.h"
enum combos { alttab, esc };
uint16_t const alttab_combo[] = {KC_F, KC_G, COMBO_END};
uint16_t const esc_combo[] = {KC_H, KC_J, COMBO_END};
// clang-format off
combo_t key_combos[] = {
[alttab] = COMBO(alttab_combo, KC_NO),
[esc] = COMBO(esc_combo, KC_ESC)
};
// clang-format on
void process_combo_event(uint16_t combo_index, bool pressed) {
switch (combo_index) {
case alttab:
if (pressed) {
register_mods(MOD_LALT);
tap_code(KC_TAB);
} else {
unregister_mods(MOD_LALT);
}
break;
}
}
bool process_combo_key_repress(uint16_t combo_index, combo_t *combo, uint8_t key_index, uint16_t keycode) {
switch (combo_index) {
case alttab:
switch (keycode) {
case KC_F:
tap_code16(S(KC_TAB));
return true;
case KC_G:
tap_code(KC_TAB);
return true;
}
}
return false;
}