-
-
Notifications
You must be signed in to change notification settings - Fork 39.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial PoC for Dynamic lighting support
- Loading branch information
Showing
13 changed files
with
904 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,7 @@ GENERIC_FEATURES = \ | |
HAPTIC \ | ||
KEY_LOCK \ | ||
KEY_OVERRIDE \ | ||
LAMPARRAY \ | ||
LEADER \ | ||
MAGIC \ | ||
MOUSEKEY \ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
// Copyright 2024 QMK | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
#include <string.h> // for memcpy | ||
#include "lamparray.h" | ||
#include "lamparray_surface.h" | ||
#include "keycodes.h" | ||
#include "keymap_introspection.h" | ||
#include "action_layer.h" | ||
|
||
// Defaults are generated from info.json layout content | ||
#ifndef LAMPARRAY_WIDTH | ||
# define LAMPARRAY_WIDTH ESTIMATED_KEYBOARD_WIDTH | ||
#endif | ||
#ifndef LAMPARRAY_HEIGHT | ||
# define LAMPARRAY_HEIGHT ESTIMATED_KEYBOARD_HEIGHT | ||
#endif | ||
#ifndef LAMPARRAY_DEPTH | ||
# define LAMPARRAY_DEPTH 30000 | ||
#endif | ||
#ifndef LAMPARRAY_KIND | ||
# define LAMPARRAY_KIND LAMPARRAY_KIND_KEYBOARD | ||
#endif | ||
|
||
#ifdef RGB_MATRIX_ENABLE | ||
# include "rgb_matrix.h" | ||
# define LAMPARRAY_RED_LEVELS 255 | ||
# define LAMPARRAY_GREEN_LEVELS 255 | ||
# define LAMPARRAY_BLUE_LEVELS 255 | ||
# define LAMPARRAY_INTENSITY_LEVELS 1 | ||
# define LAMPARRAY_LAMP_COUNT RGB_MATRIX_LED_COUNT | ||
# define LAMPARRAY_UPDATE_INTERVAL (RGB_MATRIX_LED_FLUSH_LIMIT * 1000) | ||
#endif | ||
|
||
//**************************************************************************** | ||
// utils | ||
|
||
/** | ||
* \brief Query a HID usage for a given location | ||
* | ||
* This can be requested while the user is changing layers. This is mitigated somewhat by assuming the default layer changes infrequently. | ||
* This is currently accepted as a limitation as there is no method to invalidate the hosts view of the data. | ||
*/ | ||
uint8_t lamparray_binding_at_keymap_location(uint8_t row, uint8_t col) { | ||
uint16_t keycode = keycode_at_keymap_location(get_highest_layer(default_layer_state), row, col); | ||
(void)keycode; | ||
#if LAMPARRAY_KIND == LAMPARRAY_KIND_KEYBOARD | ||
// Basic QMK keycodes currently map directly to Keyboard UsagePage so safe to return without added indirection | ||
// Mousekeys are ignored due to values overlap Keyboard UsagePage | ||
if (IS_BASIC_KEYCODE(keycode) || IS_MODIFIER_KEYCODE(keycode)) { | ||
return keycode; | ||
} | ||
#elif LAMPARRAY_KIND == LAMPARRAY_KIND_MOUSE | ||
// Usages from the Button UsagePage (0x09) in the range of Button1 (0x01) to Button5 (0x05) inclusive | ||
if ((code) >= KC_MS_BTN1 && (code) <= KC_MS_BTN5) { | ||
return keycode - KC_MS_BTN1 + 1; | ||
} | ||
#endif | ||
return 0; | ||
} | ||
|
||
//**************************************************************************** | ||
// cache | ||
|
||
static uint8_t input_binding_cache[LAMPARRAY_LAMP_COUNT]; | ||
|
||
void lamparray_update_cache(void) { | ||
for (uint8_t lamp_id = 0; lamp_id < LAMPARRAY_LAMP_COUNT; lamp_id++) { | ||
input_binding_cache[lamp_id] = lamparray_get_lamp_binding_impl(lamp_id); | ||
} | ||
} | ||
|
||
uint8_t lamparray_get_lamp_binding(uint16_t lamp_id) { | ||
return input_binding_cache[lamp_id]; | ||
} | ||
|
||
//**************************************************************************** | ||
// queue | ||
|
||
#ifndef LAMPARRAY_REQUEST_QUEUE_SIZE | ||
# define LAMPARRAY_REQUEST_QUEUE_SIZE 5 | ||
#endif | ||
|
||
universal_lamparray_response_t request_queue[LAMPARRAY_REQUEST_QUEUE_SIZE] = {0}; | ||
uint8_t queue_size = 0; | ||
|
||
void lamparray_queue_request(universal_lamparray_response_t* report) { | ||
// get next slot | ||
universal_lamparray_response_t* target = &request_queue[queue_size++]; | ||
|
||
// copy data | ||
memcpy(target, report, sizeof(universal_lamparray_response_t)); | ||
} | ||
|
||
void lamparray_handle_queue(void) { | ||
for (uint8_t id = 0; id < queue_size; id++) { | ||
universal_lamparray_response_t* report = &request_queue[id]; | ||
switch (report->report_id) { | ||
case LAMPARRAY_REPORT_ID_RANGE_UPDATE: | ||
lamparray_set_range(&report->range_update); | ||
break; | ||
case LAMPARRAY_REPORT_ID_MULTI_UPDATE: | ||
lamparray_set_items(&report->multi_update); | ||
break; | ||
case LAMPARRAY_REPORT_ID_CONTROL: | ||
lamparray_set_control_response(report->autonomous); | ||
break; | ||
} | ||
} | ||
queue_size = 0; | ||
} | ||
|
||
//**************************************************************************** | ||
// impl | ||
|
||
static uint16_t cur_lamp_id = 0; | ||
static bool is_autonomous = true; | ||
|
||
void lamparray_get_attributes(lamparray_attributes_t* data) { | ||
data->lamp_count = LAMPARRAY_LAMP_COUNT; | ||
data->update_interval = LAMPARRAY_UPDATE_INTERVAL; | ||
data->kind = LAMPARRAY_KIND; | ||
data->bounds.width = LAMPARRAY_WIDTH; | ||
data->bounds.height = LAMPARRAY_HEIGHT; | ||
data->bounds.depth = LAMPARRAY_DEPTH; | ||
} | ||
|
||
void lamparray_get_attributes_response(lamparray_attributes_response_t* data) { | ||
data->lamp_id = cur_lamp_id; | ||
data->update_latency = 1000; | ||
data->is_programmable = 1; | ||
data->input_binding = lamparray_get_lamp_binding(cur_lamp_id); | ||
|
||
data->levels.red = LAMPARRAY_RED_LEVELS; | ||
data->levels.green = LAMPARRAY_GREEN_LEVELS; | ||
data->levels.blue = LAMPARRAY_BLUE_LEVELS; | ||
data->levels.intensity = LAMPARRAY_INTENSITY_LEVELS; | ||
|
||
lamparray_get_lamp_impl(cur_lamp_id, data); | ||
|
||
// Automatic address pointer incrementing - 26.8.1 LampAttributesRequestReport | ||
cur_lamp_id++; | ||
if (cur_lamp_id >= LAMPARRAY_LAMP_COUNT) cur_lamp_id = 0; | ||
} | ||
|
||
void lamparray_set_attributes_response(uint16_t lamp_id) { | ||
cur_lamp_id = lamp_id; | ||
} | ||
|
||
void lamparray_set_control_response(uint8_t autonomous) { | ||
is_autonomous = !!autonomous; | ||
|
||
lamparray_surface_enable(!autonomous); | ||
} | ||
|
||
void lamparray_set_range(lamparray_range_update_t* data) { | ||
// Any Lamp*UpdateReports can be ignored - 26.10.1 AutonomousMode | ||
if (is_autonomous) { | ||
return; | ||
} | ||
|
||
// Ensure IDs are within bounds | ||
if ((data->start >= LAMPARRAY_LAMP_COUNT) || (data->end >= LAMPARRAY_LAMP_COUNT)) { | ||
return; | ||
} | ||
|
||
for (uint16_t index = data->start; index <= data->end; index++) { | ||
lamparray_surface_set_item(index, data->color); | ||
} | ||
|
||
// Batch update complete - 26.11 Updating Lamp State | ||
if (data->flags & LAMP_UPDATE_FLAG_COMPLETE) { | ||
lamparray_surface_update_finished(); | ||
} | ||
} | ||
|
||
void lamparray_set_items(lamparray_multi_update_t* data) { | ||
// Any Lamp*UpdateReports can be ignored - 26.10.1 AutonomousMode | ||
if (is_autonomous) { | ||
return; | ||
} | ||
|
||
// Ensure data is within bounds | ||
if (data->count > LAMP_MULTI_UPDATE_LAMP_COUNT) { | ||
return; | ||
} | ||
|
||
for (uint8_t i = 0; i < data->count; i++) { | ||
// Ensure IDs are within bounds | ||
if (data->ids[i] >= LAMPARRAY_LAMP_COUNT) { | ||
continue; | ||
} | ||
lamparray_surface_set_item(data->ids[i], data->colors[i]); | ||
} | ||
|
||
// Batch update complete - 26.11 Updating Lamp State | ||
if (data->flags & LAMP_UPDATE_FLAG_COMPLETE) { | ||
lamparray_surface_update_finished(); | ||
} | ||
} | ||
|
||
//**************************************************************************** | ||
// feature hooks | ||
|
||
void lamparray_init(void) { | ||
lamparray_update_cache(); | ||
} | ||
|
||
void lamparray_task(void) { | ||
lamparray_handle_queue(); | ||
|
||
// TODO: regen cache if dynamic keymap updated? | ||
uint16_t temp = 0; | ||
if (!++temp) lamparray_update_cache(); | ||
} | ||
|
||
// TODO: SRC += ... | ||
#ifdef RGB_MATRIX_ENABLE | ||
# include "lamparray_rgb_matrix.c" | ||
#endif |
Oops, something went wrong.