From e38360bcf8e0ded599b1f17d540c2276aedcec62 Mon Sep 17 00:00:00 2001
From: Lyderic Maillet <lmaillet@dataone.fr>
Date: Fri, 18 Apr 2025 18:08:05 +0200
Subject: [PATCH] Retrodactyl support

---
 keyboards/handwired/retrodactyl/config.h      |  56 +++++++
 keyboards/handwired/retrodactyl/halconf.h     |  12 ++
 keyboards/handwired/retrodactyl/keyboard.json | 112 +++++++++++++
 .../retrodactyl/keymaps/default/keymap.c      | 158 ++++++++++++++++++
 keyboards/handwired/retrodactyl/mcuconf.h     |   9 +
 keyboards/handwired/retrodactyl/rules.mk      |  14 ++
 6 files changed, 361 insertions(+)
 create mode 100644 keyboards/handwired/retrodactyl/config.h
 create mode 100644 keyboards/handwired/retrodactyl/halconf.h
 create mode 100644 keyboards/handwired/retrodactyl/keyboard.json
 create mode 100644 keyboards/handwired/retrodactyl/keymaps/default/keymap.c
 create mode 100644 keyboards/handwired/retrodactyl/mcuconf.h
 create mode 100644 keyboards/handwired/retrodactyl/rules.mk

diff --git a/keyboards/handwired/retrodactyl/config.h b/keyboards/handwired/retrodactyl/config.h
new file mode 100644
index 0000000000..8289b00e93
--- /dev/null
+++ b/keyboards/handwired/retrodactyl/config.h
@@ -0,0 +1,56 @@
+// Copyright 2025 Lyderic Maillet (@lydux)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#define EE_HANDS
+
+#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET
+#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 1000U
+
+#define SERIAL_USART_FULL_DUPLEX
+#define SERIAL_USART_TX_PIN GP0
+#define SERIAL_USART_RX_PIN GP1
+
+/* key matrix size */
+#define MATRIX_ROWS 12
+#define MATRIX_COLS 6
+//#define MATRIX_MUX_COLS 3
+
+// Left side
+#define MATRIX_ROW_PINS { GP10, GP11, GP12, GP13, GP14, GP15 }
+#define MATRIX_COL_PINS { GP16, GP17, GP18, GP19, GP20, GP21 }
+#define ENCODER_A_PINS {}
+#define ENCODER_B_PINS {}
+
+//Right side
+#define MATRIX_ROW_PINS_RIGHT { GP23, GP29, GP28, GP27, GP26, GP22 }
+#define MATRIX_COL_PINS_RIGHT { GP21, GP20, GP19, GP18, GP17, GP16 }
+#define ENCODER_A_PINS_RIGHT { GP10 }
+#define ENCODER_B_PINS_RIGHT { GP11 }
+
+#define OLED_DISPLAY_128x32
+#define OLED_IC OLED_IC_SH1106
+
+/* OLED SPI Pins */
+#define OLED_DC_PIN GP6
+#define OLED_CS_PIN GP5
+#define OLED_RST_PIN GP7
+
+/* Divisor for OLED */
+#define OLED_SPI_DIVISOR 4
+
+/* ChibiOS SPI definitions */
+#define SPI_DRIVER SPID0
+#define SPI_SCK_PIN GP2
+#define SPI_MOSI_PIN GP3
+#define SPI_MISO_PIN GP4
+
+
+#define PMW33XX_CS_PIN GP8
+#define PMW33XX_CS_DIVISOR 64
+
+//#define PMW33XX_LIFTOFF_DISTANCE 0x02
+#define PMW33XX_CPI 800
+#define ROTATIONAL_TRANSFORM_ANGLE 0x30
+#define POINTING_DEVICE_INVERT_Y
diff --git a/keyboards/handwired/retrodactyl/halconf.h b/keyboards/handwired/retrodactyl/halconf.h
new file mode 100644
index 0000000000..f04a44a8f4
--- /dev/null
+++ b/keyboards/handwired/retrodactyl/halconf.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include_next <halconf.h>
+
+#undef HAL_USE_SPI
+#define HAL_USE_SPI TRUE
+
+#undef SPI_USE_WAIT
+#define SPI_USE_WAIT TRUE
+
+#undef SPI_SELECT_MODE
+#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
diff --git a/keyboards/handwired/retrodactyl/keyboard.json b/keyboards/handwired/retrodactyl/keyboard.json
new file mode 100644
index 0000000000..fb0e3d0a00
--- /dev/null
+++ b/keyboards/handwired/retrodactyl/keyboard.json
@@ -0,0 +1,112 @@
+{
+    "manufacturer": "Lydux",
+    "keyboard_name": "retrodactyl",
+    "maintainer": "Lydux",
+    "bootloader": "rp2040",
+    "processor": "RP2040",
+    "url": "",
+    "usb": {
+        "device_version": "1.0.0",
+        "pid": "0x0000",
+        "vid": "0xFEED"
+    },
+    "features": {
+        "command": false,
+        "console": false,
+        "extrakey": true,
+        "mousekey": true,
+        "pointing_device": true
+    },
+    "split": {
+        "enabled": true,
+        "serial": {
+            "driver": "vendor"
+        }
+    },
+    "diode_direction": "COL2ROW",
+    "layouts": {
+        "LAYOUT": {
+            "layout": [
+                {"matrix": [0, 0], "x": 0, "y": 0},
+                {"matrix": [0, 1], "x": 1, "y": 0},
+                {"matrix": [0, 2], "x": 2, "y": 0},
+                {"matrix": [0, 3], "x": 3, "y": 0},
+                {"matrix": [0, 4], "x": 4, "y": 0},
+                {"matrix": [0, 5], "x": 5, "y": 0},
+
+                {"matrix": [6, 0], "x": 11, "y": 0},
+                {"matrix": [6, 1], "x": 12, "y": 0},
+                {"matrix": [6, 2], "x": 13, "y": 0},
+                {"matrix": [6, 3], "x": 14, "y": 0},
+                {"matrix": [6, 4], "x": 15, "y": 0},
+                {"matrix": [6, 5], "x": 16, "y": 0},
+
+                {"matrix": [1, 0], "x": 0, "y": 1},
+                {"matrix": [1, 1], "x": 1, "y": 1},
+                {"matrix": [1, 2], "x": 2, "y": 1},
+                {"matrix": [1, 3], "x": 3, "y": 1},
+                {"matrix": [1, 4], "x": 4, "y": 1},
+                {"matrix": [1, 5], "x": 5, "y": 1},
+
+                {"matrix": [7, 0], "x": 11, "y": 1},
+                {"matrix": [7, 1], "x": 12, "y": 1},
+                {"matrix": [7, 2], "x": 13, "y": 1},
+                {"matrix": [7, 3], "x": 14, "y": 1},
+                {"matrix": [7, 4], "x": 15, "y": 1},
+                {"matrix": [7, 5], "x": 16, "y": 1},
+
+                {"matrix": [2, 0], "x": 0, "y": 2},
+                {"matrix": [2, 1], "x": 1, "y": 2},
+                {"matrix": [2, 2], "x": 2, "y": 2},
+                {"matrix": [2, 3], "x": 3, "y": 2},
+                {"matrix": [2, 4], "x": 4, "y": 2},
+                {"matrix": [2, 5], "x": 5, "y": 2},
+
+                {"matrix": [8, 0], "x": 11, "y": 2},
+                {"matrix": [8, 1], "x": 12, "y": 2},
+                {"matrix": [8, 2], "x": 13, "y": 2},
+                {"matrix": [8, 3], "x": 14, "y": 2},
+                {"matrix": [8, 4], "x": 15, "y": 2},
+                {"matrix": [8, 5], "x": 16, "y": 2},
+
+                {"matrix": [3, 0], "x": 0, "y": 3},
+                {"matrix": [3, 1], "x": 1, "y": 3},
+                {"matrix": [3, 2], "x": 2, "y": 3},
+                {"matrix": [3, 3], "x": 3, "y": 3},
+                {"matrix": [3, 4], "x": 4, "y": 3},
+                {"matrix": [3, 5], "x": 5, "y": 3},
+
+                {"matrix": [9, 0], "x": 11, "y": 3},
+                {"matrix": [9, 1], "x": 12, "y": 3},
+                {"matrix": [9, 2], "x": 13, "y": 3},
+                {"matrix": [9, 3], "x": 14, "y": 3},
+                {"matrix": [9, 4], "x": 15, "y": 3},
+                {"matrix": [9, 5], "x": 16, "y": 3},
+
+                {"matrix": [4, 2], "x": 2, "y": 4},
+                {"matrix": [4, 3], "x": 3, "y": 4},
+
+                {"matrix": [10, 2], "x": 13, "y": 4},
+                {"matrix": [10, 3], "x": 14, "y": 4},
+
+                {"matrix": [4, 4], "x": 4, "y": 5},
+                {"matrix": [4, 5], "x": 5, "y": 5},
+
+                {"matrix": [10, 0], "x": 11, "y": 5},
+                {"matrix": [10, 1], "x": 12, "y": 5},
+
+                {"matrix": [5, 4], "x": 6, "y": 6},
+                {"matrix": [5, 5], "x": 7, "y": 6},
+
+                {"matrix": [11, 0], "x": 9, "y": 6},
+                {"matrix": [11, 1], "x": 10, "y": 6},
+
+                {"matrix": [5, 2], "x": 6, "y": 7},
+                {"matrix": [5, 3], "x": 7, "y": 7},
+
+                {"matrix": [11, 2], "x": 9, "y": 7},
+                {"matrix": [11, 3], "x": 10, "y": 7}
+            ]
+        }
+    }
+}
diff --git a/keyboards/handwired/retrodactyl/keymaps/default/keymap.c b/keyboards/handwired/retrodactyl/keymaps/default/keymap.c
new file mode 100644
index 0000000000..8f369bed42
--- /dev/null
+++ b/keyboards/handwired/retrodactyl/keymaps/default/keymap.c
@@ -0,0 +1,158 @@
+// Copyright 2022 Ethan (@rocketstrong)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+/*
+ *    ┌──┐┌──┐┌──┐┌──┐┌──┐                ┌──┐┌──┐┌──┐┌──┐┌──┐
+ *┌──┐│  ││  ││  ││  ││  │                │  ││  ││  ││  ││  │┌──┐
+ *│  │└──┘└──┘└──┘└──┘└──┘                └──┘└──┘└──┘└──┘└──┘│  │
+ *└──┘┌──┐┌──┐┌──┐┌──┐┌──┐                ┌──┐┌──┐┌──┐┌──┐┌──┐└──┘
+ *┌──┐│  ││  ││  ││  ││  │                │  ││  ││  ││  ││  │┌──┐
+ *│  │└──┘└──┘└──┘└──┘└──┘                └──┘└──┘└──┘└──┘└──┘│  │
+ *└──┘┌──┐┌──┐┌──┐┌──┐┌──┐                ┌──┐┌──┐┌──┐┌──┐┌──┐└──┘
+ *┌──┐│  ││  ││  ││  ││  │                │  ││  ││  ││  ││  │┌──┐
+ *│  │└──┘└──┘└──┘└──┘└──┘                └──┘└──┘└──┘└──┘└──┘│  │
+ *└──┘┌──┐┌──┐┌──┐┌──┐┌──┐                ┌──┐┌──┐┌──┐┌──┐┌──┐└──┘
+ *┌──┐│  ││  ││  ││  ││  │                │  ││  ││  ││  ││  │┌──┐
+ *│  │└──┘└──┘└──┘└──┘└──┘                └──┘└──┘└──┘└──┘└──┘│  │
+ *└──┘    ┌──┐┌──┐                                ┌──┐┌──┐    └──┘
+ *        │  ││  │                                │  ││  │
+ *        └──┘└──┘  ┌──┐ ┌──┐          ┌──┐ ┌──┐  └──┘└──┘
+ *                  │  │ │  │          │  │ │  │          
+ *                  └──┘ └──┘          └──┘ └──┘
+ *                    ┌──┐ ┌──┐       ┌──┐ ┌──┐     
+ *                    │  │ │  │       │  │ │  │
+ *                    └──┘ └──┘       └──┘ └──┘
+ *                     ┌──┐┌──┐       ┌──┐┌──┐
+ *                     │  ││  │       │  ││  │
+ *                     └──┘└──┘       └──┘└──┘
+ */
+
+enum custom_keycodes {
+    DRAG_SCROLL = SAFE_RANGE,
+};
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+    [0] = LAYOUT(
+        KC_ESC , KC_1  , KC_2  , KC_3  , KC_4  , KC_5  ,                         KC_6   , KC_7  , KC_8   ,KC_9  ,KC_0   ,KC_GRV ,
+        KC_TAB , KC_Q  , KC_W  , KC_E  , KC_R  , KC_T  ,                         KC_Y   , KC_U  , KC_I   ,KC_O  ,KC_P   ,KC_BSLS,
+        KC_LSFT, KC_A  , KC_S  , KC_D  , KC_F  , KC_G  ,                         KC_H   , KC_J  , KC_K   ,KC_L  ,KC_SCLN,KC_QUOT,
+        KC_LCTL, KC_Z  , KC_X  , KC_C  , KC_V  , KC_B  ,                         KC_N   , KC_M  , KC_COMM,KC_DOT,KC_SLSH,TG(5)  ,
+                        KC_LBRC,KC_RBRC,                                                          KC_MINS,KC_EQL,
+                                        KC_LGUI,KC_SPC ,                         KC_ENT , MO(1) ,
+                                        MO(3)  ,KC_HOME,                         KC_END , KC_DEL,
+                                        KC_BSPC,MO(4)  ,                         MO(2)  , KC_LALT
+    ),
+    [1] = LAYOUT(
+        KC_F12 , KC_F1 , KC_F2 , KC_F3 , KC_F4 , KC_F5 ,                         KC_F6  , KC_F7 , KC_F8 , KC_F9 , KC_F10, KC_F11,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,KC_PGUP,
+        KC_TRNS,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,KC_UP  ,KC_PGDN,
+        KC_TRNS,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,KC_DOWN,KC_RGHT,
+                        _______,_______,                                                         _______,KC_LEFT,
+                                        KC_TRNS,_______,                         _______,KC_TRNS,
+                                        _______,KC_INS ,                         _______,_______,
+                                        _______,_______,                         _______,KC_RALT
+    ),
+    [2] = LAYOUT(
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+                        _______,_______,                                                         _______,_______,
+                                        KC_TRNS,_______,                         _______,_______,
+                                        _______,_______,                         _______,_______,
+                                        _______,_______,                         KC_TRNS,_______
+    ),
+    [3] = LAYOUT(
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+                        _______,_______,                                                         _______,_______,
+                                        _______,_______,                         _______,_______,
+                                        KC_TRNS,_______,                         _______,_______,
+                                        _______,_______,                         _______,_______
+    ),
+    [4] = LAYOUT(
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,QK_BOOT,
+                        _______,_______,                                                         _______,_______,
+                                        _______,_______,                         _______,_______,
+                                        _______,_______,                         _______,_______,
+                                        _______,KC_TRNS,                         _______,_______
+    ),
+    [5] = LAYOUT(
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,_______,
+        _______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,_______,KC_TRNS,
+                        _______,_______,                                                         _______,_______,
+                                        _______,_______,                         _______,_______,
+                                        _______,_______,                         MS_BTN2,_______,
+                                        _______,_______,                         MS_BTN1,DRAG_SCROLL
+    )
+};
+
+#if defined(ENCODER_MAP_ENABLE)
+const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
+    [0] = { ENCODER_CCW_CW(MS_WHLU, MS_WHLD) },
+    [1] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
+    [2] = { ENCODER_CCW_CW(MS_WHLU, MS_WHLD) },
+    [3] = { ENCODER_CCW_CW(MS_WHLU, MS_WHLD) },
+    [4] = { ENCODER_CCW_CW(MS_WHLU, MS_WHLD) },
+    [5] = { ENCODER_CCW_CW(MS_WHLU, MS_WHLD) },
+};
+#endif
+
+static void render_logo(void) {
+    static const char PROGMEM qmk_logo[] = {
+        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94,
+        0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4,
+        0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x00
+    };
+
+    oled_write_P(qmk_logo, false);
+}
+
+bool oled_task_user(void) {
+    render_logo();
+    return false;
+}
+
+
+bool set_scrolling = false;
+float scroll_accumulated_h = 0;
+float scroll_accumulated_v = 0;
+
+#define DRAGSCROLL_DIVISOR_H 16.0
+#define DRAGSCROLL_DIVISOR_V 16.0
+
+report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) {
+    if (set_scrolling) {
+        scroll_accumulated_h += (float)mouse_report.x / DRAGSCROLL_DIVISOR_H;
+        scroll_accumulated_v += (float)mouse_report.y / DRAGSCROLL_DIVISOR_V;
+
+        // Assign integer parts of accumulated scroll values to the mouse report
+        mouse_report.h = (int8_t)scroll_accumulated_h;
+        mouse_report.v = -(int8_t)scroll_accumulated_v;
+
+        // Update accumulated scroll values by subtracting the integer parts
+        scroll_accumulated_h -= (int8_t)scroll_accumulated_h;
+        scroll_accumulated_v -= (int8_t)scroll_accumulated_v;
+
+        // Clear the X and Y values of the mouse report
+        mouse_report.x = 0;
+        mouse_report.y = 0;
+    }
+    return mouse_report;
+}
+
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+    if (keycode == DRAG_SCROLL && record->event.pressed) {
+        set_scrolling = !set_scrolling;
+    }
+    return true;
+}
diff --git a/keyboards/handwired/retrodactyl/mcuconf.h b/keyboards/handwired/retrodactyl/mcuconf.h
new file mode 100644
index 0000000000..d81a1834a5
--- /dev/null
+++ b/keyboards/handwired/retrodactyl/mcuconf.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include_next <mcuconf.h>
+
+#undef RP_SPI_USE_SPI0
+#define RP_SPI_USE_SPI0 TRUE
+
+#undef RP_SPI_USE_SPI1
+#define RP_SPI_USE_SPI1 TRUE
diff --git a/keyboards/handwired/retrodactyl/rules.mk b/keyboards/handwired/retrodactyl/rules.mk
new file mode 100644
index 0000000000..0276734272
--- /dev/null
+++ b/keyboards/handwired/retrodactyl/rules.mk
@@ -0,0 +1,14 @@
+POINTING_DEVICE_DRIVER = pmw3389
+POINTING_DEVICE_ROTATION_180 = yes
+
+MOUSE_SHARED_EP = yes
+
+ENCODER_ENABLE = yes
+ENCODER_MAP_ENABLE = yes
+
+OLED_ENABLE = yes
+OLED_DRIVER = ssd1306
+OLED_TRANSPORT = spi
+
+#QUANTUM_PAINTER_ENABLE = yes
+#QUANTUM_PAINTER_DRIVERS += sh1106_spi