diff --git a/keyboards/lotus/config.h b/keyboards/lotus/config.h index 77348759ab..265afe866a 100644 --- a/keyboards/lotus/config.h +++ b/keyboards/lotus/config.h @@ -25,7 +25,9 @@ #define WS2812_PIO_USE_PIO1 #define DRIVER_COUNT 1 -#define RGB_MATRIX_LED_COUNT 78 +#define RGB_MATRIX_LED_COUNT 97 +// For the numpad +// #define RGB_MATRIX_LED_COUNT 22 // PWM single one backlight configuration // TODO: Double-check these diff --git a/keyboards/lotus/keymaps/78_ansi/keymap.c b/keyboards/lotus/keymaps/78_ansi/keymap.c index 262d82227f..e4b82c3a14 100644 --- a/keyboards/lotus/keymaps/78_ansi/keymap.c +++ b/keyboards/lotus/keymaps/78_ansi/keymap.c @@ -60,3 +60,134 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, BL_TOGG, KC_TRNS, KC_TRNS, KC_HOME, KC_PGUP, KC_PGDN, KC_END ) }; + +//// TODO: Need to define the LED matrix. +//const is31_led __flash g_is31_leds[RGB_MATRIX_LED_COUNT] = { +///* Refer to IS31 manual for these locations +// * driver +// * | R location +// * | | G location +// * | | | B location +// * | | | | */ +// {0, CS1_SW1, CS2_SW1, CS3_SW1}, +//} + +led_config_t g_led_config = {{ + // Key Matrix to LED Index + {32, 73, 6, 85, 0, 30, 34, 78, 76, 81, 79, 0, 89, 80, 53, 0, }, + {0, 0, 0, 48, 95, 28, 36, 77, 82, 33, 0, 0, 35, 91, 54, 68, }, + {0, 0, 94, 0, 3, 20, 40, 41, 56, 0, 27, 0, 0, 64, 0, 92, }, + {0, 47, 2, 0, 21, 22, 8, 9, 60, 0, 25, 75, 0, 0, 0, 71, }, + {0, 0, 17, 0, 45, 42, 10, 15, 69, 0, 23, 0, 0, 62, 63, 0, }, + {0, 0, 16, 0, 13, 14, 12, 11, 70, 0, 18, 0, 0, 61, 65, 0, }, + {0, 0, 0, 0, 19, 4, 5, 7, 67, 0, 59, 90, 0, 58, 55, 0, }, + {0, 0, 37, 0, 0, 26, 44, 50, 52, 0, 51, 0, 0, 49, 38, 0, }, +}, { + // Key Matrix to LED Index + { 11, 23 }, + { 0, 23 }, + { 57, 22 }, + { 41, 22 }, + { 73, 22 }, + { 25, 22 }, + { 121, 22 }, + { 89, 22 }, + { 105, 22 }, + { 82, 10 }, + { 114, 10 }, + { 66, 10 }, + { 50, 10 }, + { 34, 10 }, + { 98, 10 }, + { 18, 10 }, + { 2, 10 }, + { 130, 10 }, + { 56, 0 }, + { 40, 0 }, + { 72, 0 }, + { 24, 0 }, + { 88, 0 }, + { 10, 0 }, + { 104, 0 }, + { 0, 0 }, + { 120, 0 }, + { 38, 47 }, + { 22, 47 }, + { 54, 47 }, + { 5, 48 }, + { 70, 47 }, + { 1, 48 }, + { 86, 47 }, + { 0, 60 }, + { 102, 47 }, + { 30, 34 }, + { 62, 34 }, + { 7, 35 }, + { 94, 34 }, + { 110, 34 }, + { 46, 34 }, + { 13, 36 }, + { 78, 34 }, + { 1, 36 }, + { 8, 60 }, + { 38, 59 }, + { 54, 59 }, + { 174, 34 }, + { 126, 34 }, + { 142, 34 }, + { 158, 34 }, + { 190, 34 }, + { 205, 34 }, + { 202, 22 }, + { 219, 22 }, + { 223, 36 }, + { 185, 22 }, + { 137, 22 }, + { 153, 22 }, + { 169, 22 }, + { 162, 10 }, + { 194, 10 }, + { 178, 10 }, + { 209, 11 }, + { 222, 11 }, + { 181, 0 }, + { 136, 0 }, + { 168, 0 }, + { 146, 10 }, + { 199, 0 }, + { 186, 0 }, + { 213, 0 }, + { 224, 0 }, + { 152, 0 }, + { 166, 47 }, + { 118, 47 }, + { 134, 47 }, + { 150, 47 }, + { 182, 47 }, + { 197, 48 }, + { 202, 58 }, + { 203, 48 }, + { 217, 48 }, + { 150, 59 }, + { 108, 60 }, + { 121, 60 }, + { 134, 60 }, + { 166, 59 }, + { 183, 64 }, + { 202, 62 }, + { 220, 64 }, + { 222, 48 }, + { 22, 59 }, + { 70, 60 }, + { 83, 60 }, + { 95, 60 } +}, { + // LED Index to Flag + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4 +} diff --git a/keyboards/lotus/led.py b/keyboards/lotus/led.py new file mode 100644 index 0000000000..582e9bd6ba --- /dev/null +++ b/keyboards/lotus/led.py @@ -0,0 +1,274 @@ +""" +Generate C code for the common configuration of the RBG matrix feature of QMK + +Reference: https://docs.qmk.fm/#/feature_rgb_matrix?id=common-configuration + +To use adjust `ansi` variable, run it and use the printed output. + +All LEDs are set as type LED_FLAG_KEYLIGHT. That's good enough for us. +All our LEDs are behind keys. However, LED_FLAG_MODIFIER might be useful for +some keys. Not sure what that means, though. +""" + +from collections import OrderedDict + +# Rows and columns in the electrical keyboard matrix. +# Equivalent to QMK's macros: MATRIX_ROWS and MATRIX_COLS +MATRIX_ROWS = 8 +MATRIX_COLS = 16 + +LED_FLAG_NONE = 0x00 +LED_FLAG_MODIFIER = 0x01 +LED_FLAG_UNDERGLOW = 0x02 +LED_FLAG_KEYLIGHT = 0x04 +LED_FLAG_INDICATOR = 0x08 + +# This structure is (manually) taken from a picture of the LED positions. +# The coordinates don't need to be translated or scaled. This script takes care of that. +# I loaded the PDF into GIMP and just took the coordinates. +# id: LED id, of where it's connected to the LED controller +# x: x coordinate of the LED +# y: y coordinate of the LED +# matrix: The keyboard matrix coordinate of the key this LED belongs to. +# Only one LED per key needs this. Other's can keep it unset. +ansi = [ + { "id": "26", "x":86, "y": 160, "matrix": (5,7) }, # ESC + { "id": "24", "x":134, "y": 160 }, # ESC + { "id": "22", "x":200, "y": 154, "matrix": (5,3) }, + + { "id": "20", "x":275, "y": 154, "matrix": (5,2) }, # Each 75 apart in x + { "id": "19", "x":350, "y": 154, "matrix": (4,6) }, + { "id": "21", "x":425, "y": 154, "matrix": (4,3) }, + { "id": "23", "x":500, "y": 154, "matrix": (10,4) }, + { "id": "25", "x":575, "y": 154, "matrix": (10,3) }, + { "id": "27", "x":650, "y": 154, "matrix": (10,2) }, + { "id": "68", "x":725, "y": 154, "matrix": (15,1) }, + { "id": "75", "x":800, "y": 154, "matrix": (11,3) }, + { "id": "69", "x":875, "y": 154, "matrix": (8,4) }, + + { "id": "67", "x":935, "y": 158, "matrix": (8,6) }, # PrtScr + { "id": "72", "x":960, "y": 158 }, # PrtScr + { "id": "71", "x":1022, "y": 154, "matrix": (15,3) }, + { "id": "73", "x":1088, "y": 160, "matrix": (1,0) }, # Del + { "id": "74", "x":1135, "y": 160 }, # Del + + # Second row + { "id": "17", "x":97, "y": 216, "matrix": (2,4) }, # Each 75 apart in x + { "id": "16", "x":172, "y": 216, "matrix": (2,5) }, + { "id": "14", "x":247, "y": 216, "matrix": (5,5) }, + { "id": "13", "x":322, "y": 216, "matrix": (4,5) }, + { "id": "12", "x":397, "y": 216, "matrix": (6,5) }, + { "id": "10", "x":472, "y": 216, "matrix": (6,4) }, + { "id": "15", "x":547, "y": 216, "matrix": (7,4) }, + { "id": "11", "x":622, "y": 216, "matrix": (7,5) }, + { "id": "18", "x":697, "y": 216, "matrix": (10,5) }, + { "id": "70", "x":772, "y": 216, "matrix": (8,5) }, + { "id": "62", "x":847, "y": 216, "matrix": (13,4) }, + { "id": "64", "x":922, "y": 216, "matrix": (13,2) }, + { "id": "63", "x":997, "y": 216, "matrix": (14,4) }, + + { "id": "65", "x":1067, "y": 224, "matrix": (14,5) }, # Backspace + { "id": "66", "x":1128, "y": 224 }, # Backspace + + # Third row + { "id": "2", "x":90, "y": 298, "matrix": (2,3) }, # Tab + { "id": "1", "x":140, "y": 298 }, # Tab + + { "id": "6", "x":207, "y": 290, "matrix": (2,0) }, # Each 75 apart in x + { "id": "4", "x":282, "y": 290, "matrix": (5,6) }, + { "id": "3", "x":357, "y": 290, "matrix": (4,2) }, + { "id": "5", "x":432, "y": 290, "matrix": (6,6) }, + { "id": "8", "x":507, "y": 290, "matrix": (6,3) }, + { "id": "9", "x":582, "y": 290, "matrix": (7,3) }, + { "id": "7", "x":657, "y": 290, "matrix": (7,6) }, + { "id": "59", "x":732, "y": 290, "matrix": (10,6) }, + { "id": "60", "x":807, "y": 290, "matrix": (8,3) }, + { "id": "61", "x":882, "y": 290, "matrix": (13,5) }, + { "id": "58", "x":957, "y": 290, "matrix": (13,6) }, + { "id": "55", "x":1032, "y": 290, "matrix": (14,6) }, + + { "id": "56", "x":1115, "y": 292, "matrix": (8,2) }, + + # Forth row + { "id": "45", "x":94, "y": 374, "matrix": (4,4) }, # Caps + { "id": "39", "x":123, "y": 367 }, # Caps + { "id": "43", "x":150, "y": 374 }, # Caps + + { "id": "37", "x":227, "y": 365, "matrix": (2,7) }, # Each 75 apart in x + { "id": "42", "x":302, "y": 365, "matrix": (5,4) }, + { "id": "38", "x":377, "y": 365, "matrix": (14,7) }, + { "id": "44", "x":452, "y": 365, "matrix": (6,7) }, + { "id": "40", "x":527, "y": 365, "matrix": (6,2) }, + { "id": "41", "x":602, "y": 365, "matrix": (7,2) }, + { "id": "50", "x":677, "y": 365, "matrix": (7,7) }, + { "id": "51", "x":752, "y": 365, "matrix": (10,7) }, + { "id": "52", "x":827, "y": 365, "matrix": (8,7) }, + { "id": "49", "x":902, "y": 365, "matrix": (13,7) }, + { "id": "53", "x":977, "y": 365, "matrix": (14,0) }, + + { "id": "54", "x":1050, "y": 365, "matrix": (14,1) }, # Enter + { "id": "57", "x":1131, "y": 373 }, # Enter + + # Fifth row + { "id": "33", "x":91, "y": 448, "matrix": (9,1) }, # Shift + { "id": "31", "x":113, "y": 448 }, # Shift + { "id": "29", "x":191, "y": 440 }, # Shift + + { "id": "28", "x":266, "y": 440, "matrix": (5,1) }, # Each 75 apart in x + { "id": "30", "x":341, "y": 440, "matrix": (5,0) }, + { "id": "32", "x":416, "y": 440, "matrix": (0,0) }, + { "id": "34", "x":491, "y": 440, "matrix": (6,0) }, + { "id": "36", "x":566, "y": 440, "matrix": (6,1) }, + { "id": "77", "x":641, "y": 440, "matrix": (7,1) }, + { "id": "78", "x":716, "y": 440, "matrix": (7,0) }, + { "id": "79", "x":791, "y": 440, "matrix": (10,0) }, + { "id": "76", "x":866, "y": 440, "matrix": (8,0) }, + { "id": "80", "x":941, "y": 440, "matrix": (13,0) }, + + { "id": "81", "x":1013, "y": 445, "matrix": (9,0) }, # Shift + { "id": "83", "x":1041, "y": 445 }, # Shift + { "id": "84", "x":1106, "y": 445 }, # Shift + { "id": "93", "x":1127, "y": 445 }, # Shift + + # Sixth row + { "id": "35", "x":89, "y": 522, "matrix": (12,1) }, # CTRL + { "id": "46", "x":124, "y": 522 }, # CTRL + { "id": "94", "x":191, "y": 515, "matrix": (2,2) }, + { "id": "47", "x":266, "y": 515, "matrix": (1,3) }, + { "id": "48", "x":341, "y": 515, "matrix": (3,1) }, + { "id": "95", "x":415, "y": 522, "matrix": (4,1) }, # Space + { "id": "96", "x":475, "y": 522 }, # Space + { "id": "97", "x":535, "y": 522 }, # Space + { "id": "86", "x":595, "y": 522 }, # Space + { "id": "87", "x":655, "y": 522 }, # Space + { "id": "88", "x":715, "y": 522 }, # Space + { "id": "85", "x":791, "y": 515, "matrix": (3,0) }, + { "id": "89", "x":865, "y": 515, "matrix": (12,0) }, + { "id": "90", "x":945, "y": 542, "matrix": (11,6) }, + { "id": "91", "x":1033, "y": 534, "matrix": (13,1) }, + { "id": "82", "x":1033, "y": 510, "matrix": (8,1) }, + { "id": "92", "x":1120, "y": 542, "matrix": (15,2) }, +] + +numpad = [ + { "id": "11", "x":1332, "y": 158, "matrix": (1,2) }, + { "id": "12", "x":1395, "y": 158, "matrix": (2,2) }, + { "id": "46", "x":1460, "y": 158, "matrix": (4,3) }, + { "id": "77", "x":1523, "y": 158, "matrix": (4,2) }, + + { "id": "10", "x":1332, "y": 219, "matrix": (0,0) }, + { "id": "1", "x":1395, "y": 219, "matrix": (4,0) }, + { "id": "46", "x":1460, "y": 219, "matrix": (1,1) }, + { "id": "87", "x":1523, "y": 219, "matrix": (6,1) }, + + { "id": "14", "x":1332, "y": 294, "matrix": (1,0) }, + { "id": "2", "x":1395, "y": 294, "matrix": (5,0) }, + { "id": "96", "x":1460, "y": 294, "matrix": (2,1) }, # Plus + { "id": "78", "x":1523, "y": 294 }, # Plus + + { "id": "12", "x":1332, "y": 368, "matrix": (2,0) }, + { "id": "47", "x":1395, "y": 368, "matrix": (6,0) }, + { "id": "95", "x":1460, "y": 368, "matrix": (3,1) }, + { "id": "42", "x":1523, "y": 368, "matrix": (7,1) }, + + { "id": "20", "x":1332, "y": 443, "matrix": (3,0) }, + { "id": "22", "x":1395, "y": 443, "matrix": (7,0) }, + { "id": "29", "x":1460, "y": 443, "matrix": (4,1) }, # Enter + { "id": "79", "x":1523, "y": 443 }, # Enter + + { "id": "19", "x":1332, "y": 519, "matrix": (0,1) }, # 0 + { "id": "21", "x":1395, "y": 519 }, # 0 + { "id": "28", "x":1460, "y": 519, "matrix": (5,1) }, + { "id": "34", "x":1523, "y": 519, "matrix": (0,2) }, +] + +# Recommended by QMK to be the (x,y) range of position values +LED_MAX = (224.0, 64.0) + +# Map LEDs to keyboard matrix and normalize LED coordinates +def normalize(layout): + led_to_el = [[0 for _ in range(MATRIX_COLS)] for _ in range(MATRIX_ROWS)] + # Find smallest (offset) and largest (max) values + offset_x = layout[0]['x'] + offset_y = layout[0]['y'] + max_x = layout[-1]['x'] + max_y = layout[-1]['y'] + for v in layout: + if v['x'] < offset_x: + offset_x = v['x'] + if v['y'] < offset_y: + offset_y = v['y'] + if v['x'] > max_x: + max_x = v['x'] + if v['y'] > max_y: + max_y = v['y'] + # Ratio of coordinates in the input data vs QMK's reference rectangle + x_ratio = LED_MAX[0] / (max_x - offset_x) + y_ratio = LED_MAX[1] / (max_y - offset_y) + + # Normalize LED coordinates by scaling and translating + normalized = OrderedDict() + for v in sorted(layout, key=lambda item: int(item['id'])): + x = x_ratio * (v['x'] - offset_x) + y = y_ratio * (v['y'] - offset_y) + + normalized[int(v['id'])] = (x, y) + + if 'matrix' in v: + if not v['matrix'] or v['matrix'] == (): + continue + (matrix_x,matrix_y) = v['matrix'] + # Map LED IDs to keyboard matrix + led_to_el[matrix_y][matrix_x] = int(v['id']) + return led_to_el, normalized + +# Turn the data to C code that can be used in QMK's keymap.c +def print_matrix(layout, led_to_el, normalized): + print("led_config_t g_led_config = {{") + print(" // Key Matrix to LED Index") + for row in led_to_el: + print(" {", end='') + for col in row: + print(f"{col}, ", end='') + print("},") + + print("}, {") + print(" // Key Matrix to LED Index") + for i, (x, y) in normalized.items(): + print(f" {{ {int(x)}, {int(y)} }}", end='') + if i < len(normalized): + print(',') + else: + print() + + print("}, {") + print(" // LED Index to Flag") + print(" ", end='') + for i in range(len(layout)): + # TODO: Support other LED flags + print(LED_FLAG_KEYLIGHT, end='') + if i + 1 == len(layout): + print() + break + else: + print(", ", end='') + if (i + 1) % 16 == 0: + print("\n ", end='') + print("}") + +def main(data): + # Normalize data and convert to C code + led_to_el, normalized = normalize(data) + print_matrix(data, led_to_el, normalized) + + # Draw led positions to visually check them with the reference design + import matplotlib.pyplot as plt + a = [[x, y] for _i, (x, y) in normalized.items()] + scatter = plt.scatter(*zip(*a)) + ax = scatter.axes + ax.invert_yaxis() + plt.show() + +if __name__ == "__main__": + # Can choose which dataset to process + main(ansi)