summaryrefslogtreecommitdiff
path: root/keyboards/ferris
diff options
context:
space:
mode:
authorPierre Chevalier <pierrechevalier83@gmail.com>2020-10-17 20:20:34 +0100
committerGitHub <noreply@github.com>2020-10-17 12:20:34 -0700
commit704934c427af1cc2176fa7c82773e86d89cbfa3c (patch)
tree2699b29924e8496c1ee867a645a52a310ac9a532 /keyboards/ferris
parent47ea522e79f2b7bcc2804c309f2b94e029824eb9 (diff)
Ferris reorganization (#10564)
* Add my own keymap * Layer 0: Workman * Layer 1: RSTHD (my own take on it) * Layer 2: Mouse * Layer 3: Navigation * Layer 4: Symbols right * Layer 5: Symbols left * Layer 6: Fn keys * Layer 7: Numbers * Layer 8: Vim and misceallaneaous accessible from any other layer * Move the current code to a 0.1 folder in preparation for upcoming changes Version 0.2 is currently being prototyped and uses an arm chip which will need its own firmware. There is also the Ferris sweep which uses a pro-micro compatible board which will need its own directory. * Move Ferris out of handwired and into the light The keyboard is now well out of the prototype phase as tens of them have been produced and acquired by various people. With 0.2 coming out, adoption is going to increase again as the board will be available for sale at some recognized vendors. Now is probably a good time to recognize its status as more than a prototype :) * Add code for the Ferris Sweep (a.k.a cradio) The Ferris Sweep is a creation of the talented @davidphilipbarr, a.k.a DPB. It has the key layout of a Ferris and uses a pro-micro connected to the switches via direct pins so that diodes are not needed and the soldering is minimal. With their blessing, I took the code for it from DPB's own repo: https://github.com/davidphilipbarr/36keys/tree/master/qmk/cradio and did some adaptations such as removing commented out code, enabling EE_HANDS and mouse keys for consistency with my existing Ferris code. * Fix indentation in rules.mk * Fix indentation in sweep's config * Remove unnecessary lines from sweep's rules.mk * Remove unnecessary lines from sweep's rules.mk * Rename 0.1 to 0_1 This avoids the dot looking like the separation between a filename and its extension. In the same commit, bring matrix.c to the 0_1 folder as this was needed for the code to compile properly (matrix.c is referred to in the readme under `0_1` and is specific to that revision of the firmware). * Update copyright statements for Sweep
Diffstat (limited to 'keyboards/ferris')
-rw-r--r--keyboards/ferris/0_1/0_1.c17
-rw-r--r--keyboards/ferris/0_1/0_1.h43
-rw-r--r--keyboards/ferris/0_1/config.h60
-rw-r--r--keyboards/ferris/0_1/matrix.c282
-rw-r--r--keyboards/ferris/0_1/rules.mk28
-rw-r--r--keyboards/ferris/info.json54
-rw-r--r--keyboards/ferris/keymaps/default/config.h39
-rw-r--r--keyboards/ferris/keymaps/default/keymap.json106
-rw-r--r--keyboards/ferris/keymaps/default/readme.md122
-rwxr-xr-xkeyboards/ferris/keymaps/json2crab.py76
-rw-r--r--keyboards/ferris/keymaps/pierrec83/config.h39
-rw-r--r--keyboards/ferris/keymaps/pierrec83/keymap.json118
-rw-r--r--keyboards/ferris/keymaps/pierrec83/readme.md43
-rw-r--r--keyboards/ferris/readme.md19
-rw-r--r--keyboards/ferris/sweep/config.h74
-rw-r--r--keyboards/ferris/sweep/rules.mk24
-rw-r--r--keyboards/ferris/sweep/sweep.c16
-rw-r--r--keyboards/ferris/sweep/sweep.h47
18 files changed, 1207 insertions, 0 deletions
diff --git a/keyboards/ferris/0_1/0_1.c b/keyboards/ferris/0_1/0_1.c
new file mode 100644
index 0000000000..dbdb0b4bdc
--- /dev/null
+++ b/keyboards/ferris/0_1/0_1.c
@@ -0,0 +1,17 @@
+/*
+Copyright 2020 Pierre Chevalier <pierrechevalier83@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 "0_1.h"
diff --git a/keyboards/ferris/0_1/0_1.h b/keyboards/ferris/0_1/0_1.h
new file mode 100644
index 0000000000..4602637ca6
--- /dev/null
+++ b/keyboards/ferris/0_1/0_1.h
@@ -0,0 +1,43 @@
+/*
+Copyright 2020 Pierre Chevalier <pierrechevalier83@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/>.
+*/
+
+#pragma once
+
+#include "quantum.h"
+
+// clang-format off
+
+/* left hand right hand */
+#define LAYOUT(\
+ K0_0, K0_1, K0_2, K0_3, K0_4, K0_5, K0_6, K0_7, K0_8, K0_9,\
+ K1_0, K1_1, K1_2, K1_3, K1_4, K1_5, K1_6, K1_7, K1_8, K1_9,\
+ K2_0, K2_1, K2_2, K2_3, K2_4, K2_5, K2_6, K2_7, K2_8, K2_9,\
+ K3_3, K3_4, K3_5, K3_6)\
+/* matrix positions */\
+{\
+ {K0_0, K0_1, K0_2, K0_3, K0_4},\
+ {K1_0, K1_1, K1_2, K1_3, K1_4},\
+ {K2_0, K2_1, K2_2, K2_3, K2_4},\
+ {KC_NO, KC_NO, KC_NO, K3_3, K3_4},\
+ \
+ {K0_5, K0_6, K0_7, K0_8, K0_9},\
+ {K1_5, K1_6, K1_7, K1_8, K1_9},\
+ {K2_5, K2_6, K2_7, K2_8, K2_9},\
+ {K3_5, K3_6, KC_NO, KC_NO, KC_NO}\
+}
+
+// clang-format on
diff --git a/keyboards/ferris/0_1/config.h b/keyboards/ferris/0_1/config.h
new file mode 100644
index 0000000000..33494d9273
--- /dev/null
+++ b/keyboards/ferris/0_1/config.h
@@ -0,0 +1,60 @@
+/*
+Copyright 2020 Pierre Chevalier <pierrechevalier83@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/>.
+*/
+
+#pragma once
+
+/* USB Device descriptor parameter */
+#define VENDOR_ID 0xC2AB
+#define PRODUCT_ID 0x0000
+#define DEVICE_VER 0x0001
+#define MANUFACTURER Pierre
+#define PRODUCT Ferris the keeb
+#define DESCRIPTION A minimalistic 34 - keys split keyboard
+
+/* key matrix size */
+#define MATRIX_ROWS 8
+#define MATRIX_COLS 10
+
+#define MATRIX_ROWS_PER_SIDE (MATRIX_ROWS / 2)
+#define MATRIX_COLS_PER_SIDE (MATRIX_COLS / 2)
+
+#define UNUSED_MCU 14
+#define UNUSED_MCP 7
+
+// wiring
+#define MATRIX_ROW_PINS_MCU \
+ { B3, B2, B1, F0 }
+#define MATRIX_COL_PINS_MCU \
+ { D6, D7, B4, B5, B6 }
+#define UNUSED_PINS_MCU \
+ { B0, B7, C6, C7, D2, D3, D4, D5, E6, F1, F4, F5, F6, F7 }
+#define MATRIX_ROW_PINS_MCP \
+ { B0, B1, B2, B3 }
+#define MATRIX_COL_PINS_MCP \
+ { A0, A1, A2, A3, A4 }
+#define UNUSED_PINS_MCP \
+ { B4, B5, B6, B7, A5, A6, A7 }
+
+/* COL2ROW, ROW2COL*/
+#define DIODE_DIRECTION COL2ROW
+
+/* define if matrix has ghost (lacks anti-ghosting diodes) */
+//#define MATRIX_HAS_GHOST
+
+/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
+#define DEBOUNCE 5
+
diff --git a/keyboards/ferris/0_1/matrix.c b/keyboards/ferris/0_1/matrix.c
new file mode 100644
index 0000000000..e13c35d358
--- /dev/null
+++ b/keyboards/ferris/0_1/matrix.c
@@ -0,0 +1,282 @@
+/*
+Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
+ 2020 Pierre Chevalier <pierrechevalier83@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/>.
+*/
+
+/*
+ * This code was heavily inspired by the ergodox_ez keymap, and modernized
+ * to take advantage of the quantum.h microcontroller agnostics gpio control
+ * abstractions and use the macros defined in config.h for the wiring as opposed
+ * to repeating that information all over the place.
+ */
+
+#include QMK_KEYBOARD_H
+#include "i2c_master.h"
+
+extern i2c_status_t mcp23017_status;
+#define I2C_TIMEOUT 1000
+
+// For a better understanding of the i2c protocol, this is a good read:
+// https://www.robot-electronics.co.uk/i2c-tutorial
+
+// I2C address:
+// See the datasheet, section 3.3.1 on addressing I2C devices and figure 3-6 for an
+// illustration
+// http://ww1.microchip.com/downloads/en/devicedoc/20001952c.pdf
+// All address pins of the mcp23017 are connected to the ground on the ferris
+// | 0 | 1 | 0 | 0 | A2 | A1 | A0 |
+// | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
+#define I2C_ADDR 0b0100000
+#define I2C_ADDR_WRITE ((I2C_ADDR << 1) | I2C_WRITE)
+#define I2C_ADDR_READ ((I2C_ADDR << 1) | I2C_READ)
+
+// Register addresses
+// See https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/blob/master/Adafruit_MCP23017.h
+#define IODIRA 0x00 // i/o direction register
+#define IODIRB 0x01
+#define GPPUA 0x0C // GPIO pull-up resistor register
+#define GPPUB 0x0D
+#define GPIOA 0x12 // general purpose i/o port register (write modifies OLAT)
+#define GPIOB 0x13
+#define OLATA 0x14 // output latch register
+#define OLATB 0x15
+
+bool i2c_initialized = 0;
+i2c_status_t mcp23017_status = I2C_ADDR;
+
+uint8_t init_mcp23017(void) {
+ print("starting init");
+ mcp23017_status = I2C_ADDR;
+
+ // I2C subsystem
+ if (i2c_initialized == 0) {
+ i2c_init(); // on pins D(1,0)
+ i2c_initialized = true;
+ wait_ms(I2C_TIMEOUT);
+ }
+
+ // set pin direction
+ // - unused : input : 1
+ // - input : input : 1
+ // - driving : output : 0
+ mcp23017_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+ mcp23017_status = i2c_write(IODIRA, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+ // This means: we will read all the bits on GPIOA
+ mcp23017_status = i2c_write(0b11111111, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+ // This means: we will write to the pins 0-4 on GPIOB (in select_rows)
+ mcp23017_status = i2c_write(0b11110000, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+ i2c_stop();
+
+ // set pull-up
+ // - unused : on : 1
+ // - input : on : 1
+ // - driving : off : 0
+ mcp23017_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+ mcp23017_status = i2c_write(GPPUA, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+ // This means: we will read all the bits on GPIOA
+ mcp23017_status = i2c_write(0b11111111, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+ // This means: we will write to the pins 0-4 on GPIOB (in select_rows)
+ mcp23017_status = i2c_write(0b11110000, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+
+out:
+ i2c_stop();
+ return mcp23017_status;
+}
+
+/* matrix state(1:on, 0:off) */
+static matrix_row_t matrix[MATRIX_ROWS]; // debounced values
+
+static matrix_row_t read_cols(uint8_t row);
+static void init_cols(void);
+static void unselect_rows(void);
+static void select_row(uint8_t row);
+
+static uint8_t mcp23017_reset_loop;
+
+void matrix_init_custom(void) {
+ // initialize row and col
+
+ mcp23017_status = init_mcp23017();
+
+ unselect_rows();
+ init_cols();
+
+ // initialize matrix state: all keys off
+ for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
+ matrix[i] = 0;
+ }
+}
+
+void matrix_power_up(void) {
+ mcp23017_status = init_mcp23017();
+
+ unselect_rows();
+ init_cols();
+
+ // initialize matrix state: all keys off
+ for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
+ matrix[i] = 0;
+ }
+}
+
+// Reads and stores a row, returning
+// whether a change occurred.
+static inline bool store_matrix_row(matrix_row_t current_matrix[], uint8_t index) {
+ matrix_row_t temp = read_cols(index);
+ if (current_matrix[index] != temp) {
+ current_matrix[index] = temp;
+ return true;
+ }
+ return false;
+}
+
+bool matrix_scan_custom(matrix_row_t current_matrix[]) {
+ if (mcp23017_status) { // if there was an error
+ if (++mcp23017_reset_loop == 0) {
+ // if (++mcp23017_reset_loop >= 1300) {
+ // since mcp23017_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
+ // this will be approx bit more frequent than once per second
+ dprint("trying to reset mcp23017\n");
+ mcp23017_status = init_mcp23017();
+ if (mcp23017_status) {
+ dprint("right side not responding\n");
+ } else {
+ dprint("right side attached\n");
+ }
+ }
+ }
+
+ bool changed = false;
+ for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
+ // select rows from left and right hands
+ uint8_t left_index = i;
+ uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
+ select_row(left_index);
+ select_row(right_index);
+
+ // we don't need a 30us delay anymore, because selecting a
+ // left-hand row requires more than 30us for i2c.
+
+ changed |= store_matrix_row(current_matrix, left_index);
+ changed |= store_matrix_row(current_matrix, right_index);
+
+ unselect_rows();
+ }
+
+ return changed;
+}
+
+static void init_cols(void) {
+ // init on mcp23017
+ // not needed, already done as part of init_mcp23017()
+
+ // init on mcu
+ pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_MCU;
+ for (int pin_index = 0; pin_index < MATRIX_COLS_PER_SIDE; pin_index++) {
+ pin_t pin = matrix_col_pins_mcu[pin_index];
+ setPinInput(pin);
+ writePinHigh(pin);
+ }
+}
+
+static matrix_row_t read_cols(uint8_t row) {
+ if (row < MATRIX_ROWS_PER_SIDE) {
+ pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_MCU;
+ matrix_row_t current_row_value = 0;
+ // For each col...
+ for (uint8_t col_index = 0; col_index < MATRIX_COLS_PER_SIDE; col_index++) {
+ // Select the col pin to read (active low)
+ uint8_t pin_state = readPin(matrix_col_pins_mcu[col_index]);
+
+ // Populate the matrix row with the state of the col pin
+ current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index);
+ }
+ return current_row_value;
+ } else {
+ if (mcp23017_status) { // if there was an error
+ return 0;
+ } else {
+ uint8_t data = 0;
+ mcp23017_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+ mcp23017_status = i2c_write(GPIOA, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+ mcp23017_status = i2c_start(I2C_ADDR_READ, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+ mcp23017_status = i2c_read_nack(I2C_TIMEOUT);
+ if (mcp23017_status < 0) goto out;
+ // We read all the pins on GPIOA.
+ // The initial state was all ones and any depressed key at a given column for the currently selected row will have its bit flipped to zero.
+ // The return value is a row as represented in the generic matrix code were the rightmost bits represent the lower columns and zeroes represent non-depressed keys while ones represent depressed keys.
+ // Since the pins connected to eact columns are sequential, and counting from zero up (col 5 -> GPIOA0, col 6 -> GPIOA1 and so on), the only transformation needed is a bitwise not to swap all zeroes and ones.
+ data = ~((uint8_t)mcp23017_status);
+ mcp23017_status = I2C_STATUS_SUCCESS;
+ out:
+ i2c_stop();
+ // return reverse_bits(data, MATRIX_COLS_PER_SIDE);
+ return data;
+ }
+ }
+}
+
+static void unselect_rows(void) {
+ // no need to unselect on mcp23017, because the select step sets all
+ // the other row bits high, and it's not changing to a different
+ // direction
+
+ // unselect rows on microcontroller
+ pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_MCU;
+ for (int pin_index = 0; pin_index < MATRIX_ROWS_PER_SIDE; pin_index++) {
+ pin_t pin = matrix_row_pins_mcu[pin_index];
+ setPinInput(pin);
+ writePinLow(pin);
+ }
+}
+
+static void select_row(uint8_t row) {
+ if (row < MATRIX_ROWS_PER_SIDE) {
+ // select on atmega32u4
+ pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_MCU;
+ pin_t pin = matrix_row_pins_mcu[row];
+ setPinOutput(pin);
+ writePinLow(pin);
+ } else {
+ // select on mcp23017
+ if (mcp23017_status) { // if there was an error
+ // do nothing
+ } else {
+ mcp23017_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+ mcp23017_status = i2c_write(GPIOB, I2C_TIMEOUT);
+ if (mcp23017_status) goto out;
+ // Select the desired row by writing a byte for the entire GPIOB bus where only the bit representing the row we want to select is a zero (write instruction) and every other bit is a one.
+ // Note that the row - MATRIX_ROWS_PER_SIDE reflects the fact that being on the right hand, the columns are numbered from MATRIX_ROWS_PER_SIDE to MATRIX_ROWS, but the pins we want to write to are indexed from zero up on the GPIOB bus.
+ mcp23017_status = i2c_write(0xFF & ~(1 << (row - MATRIX_ROWS_PER_SIDE)), I2C_TIMEOUT);
+
+ if (mcp23017_status) goto out;
+ out:
+ i2c_stop();
+ }
+ }
+}
diff --git a/keyboards/ferris/0_1/rules.mk b/keyboards/ferris/0_1/rules.mk
new file mode 100644
index 0000000000..8645dbba0d
--- /dev/null
+++ b/keyboards/ferris/0_1/rules.mk
@@ -0,0 +1,28 @@
+# MCU name
+MCU = atmega32u4
+
+# Bootloader selection
+BOOTLOADER = atmel-dfu
+
+# change yes to no to disable
+#
+BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration
+MOUSEKEY_ENABLE = yes # Mouse keys
+EXTRAKEY_ENABLE = yes # Audio control and System control
+CONSOLE_ENABLE = no # Console for debug
+COMMAND_ENABLE = no # Commands for debug and configuration
+# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
+SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
+# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
+NKRO_ENABLE = no # USB Nkey Rollover
+BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
+RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
+BLUETOOTH_ENABLE = no # Enable Bluetooth
+AUDIO_ENABLE = no # Audio output
+UNICODE_ENABLE = yes
+CUSTOM_MATRIX = lite
+NO_USB_STARTUP_CHECK = yes
+LTO_ENABLE = yes
+
+SRC += matrix.c
+QUANTUM_LIB_SRC += i2c_master.c
diff --git a/keyboards/ferris/info.json b/keyboards/ferris/info.json
new file mode 100644
index 0000000000..ffffb58ecf
--- /dev/null
+++ b/keyboards/ferris/info.json
@@ -0,0 +1,54 @@
+{
+ "keyboard_name": "Ferris",
+ "url": "https://github.com/pierrechevalier83/ferris/",
+ "maintainer": "@pierrec83",
+ "width": 12,
+ "height": 4.75,
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {"x": 0, "y": 0.93},
+ {"x": 1, "y": 0.31},
+ {"x": 2, "y": 0},
+ {"x": 3, "y": 0.28},
+ {"x": 4, "y": 0.42},
+
+ {"x": 7, "y": 0.42},
+ {"x": 8, "y": 0.28},
+ {"x": 9, "y": 0},
+ {"x": 10, "y": 0.31},
+ {"x": 11, "y": 0.93},
+
+ {"x": 0, "y": 1.93},
+ {"x": 1, "y": 1.31},
+ {"x": 2, "y": 1},
+ {"x": 3, "y": 1.28},
+ {"x": 4, "y": 1.42},
+
+ {"x": 7, "y": 1.42},
+ {"x": 8, "y": 1.28},
+ {"x": 9, "y": 1},
+ {"x": 10, "y": 1.31},
+ {"x": 11, "y": 1.93},
+
+ {"x": 0, "y": 2.93},
+ {"x": 1, "y": 2.31},
+ {"x": 2, "y": 2},
+ {"x": 3, "y": 2.28},
+ {"x": 4, "y": 2.42},
+
+ {"x": 7, "y": 2.42},
+ {"x": 8, "y": 2.28},
+ {"x": 9, "y": 2},
+ {"x": 10, "y": 2.31},
+ {"x": 11, "y": 2.93},
+
+ {"x": 3.5, "y": 3.75},
+ {"x": 4.5, "y": 4},
+
+ {"x": 6.5, "y": 4},
+ {"x": 7.5, "y": 3.75}
+ ]
+ }
+ }
+}
diff --git a/keyboards/ferris/keymaps/default/config.h b/keyboards/ferris/keymaps/default/config.h
new file mode 100644
index 0000000000..cf0fb7478e
--- /dev/null
+++ b/keyboards/ferris/keymaps/default/config.h
@@ -0,0 +1,39 @@
+/*
+Copyright 2020 Pierre Chevalier <pierrechevalier83@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/>.
+*/
+
+#pragma once
+// Set the mouse settings to a comfortable speed/accuracy trade-off,
+// assuming a screen refresh rate of 60 Htz or higher
+// The default is 50. This makes the mouse ~3 times faster and more accurate
+#define MOUSEKEY_INTERVAL 16
+// The default is 20. Since we made the mouse about 3 times faster with the previous setting,
+// give it more time to accelerate to max speed to retain precise control over short distances.
+#define MOUSEKEY_TIME_TO_MAX 40
+// The default is 300. Let's try and make this as low as possible while keeping the cursor responsive
+#define MOUSEKEY_DELAY 100
+// It makes sense to use the same delay for the mouseweel
+#define MOUSEKEY_WHEEL_DELAY 100
+// The default is 100
+#define MOUSEKEY_WHEEL_INTERVAL 50
+// The default is 40
+#define MOUSEKEY_WHEEL_TIME_TO_MAX 100
+
+// Pick good defaults for enabling homerow modifiers
+#define TAPPING_TERM 200
+#define PERMISSIVE_HOLD
+#define IGNORE_MOD_TAP_INTERRUPT
+#define TAPPING_FORCE_HOLD
diff --git a/keyboards/ferris/keymaps/default/keymap.json b/keyboards/ferris/keymaps/default/keymap.json
new file mode 100644
index 0000000000..7f7d614e20
--- /dev/null
+++ b/keyboards/ferris/keymaps/default/keymap.json
@@ -0,0 +1,106 @@
+{ "version": 1,
+ "notes": "My awesome keymap",
+ "documentation": "\"This file is a QMK Configurator export. You can import this at <https://config.qmk.fm>. It can also be used directly with QMK's source code.\n\nTo setup your QMK environment check out the tutorial: <https://docs.qmk.fm/#/newbs>\n\nYou can convert this file to a keymap.c using this command: `qmk json2c {keymap}`\n\nYou can compile this keymap using this command: `qmk compile {keymap}`\"\n",
+ "keyboard": "handwired/ferris",
+ "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",
+
+ "LSFT_T(KC_A)", "LT(5,KC_S)" , "LT(1,KC_D)" , "LT(3,KC_F)" , "KC_G",
+ "KC_H" , "LT(4,KC_J)" , "LT(2,KC_K)" , "LT(6,KC_L)" , "LSFT_T(KC_SCLN)",
+
+ "KC_Z" , "LCTL_T(KC_X)", "LALT_T(KC_C)" , "KC_V" , "KC_B",
+ "KC_N" , "KC_M" , "LALT_T(KC_COMM)", "LCTL_T(KC_DOT)", "KC_SLSH",
+
+ "KC_P0" , "KC_BSPC",
+ "LT(7,KC_SPC)", "KC_P1"
+ ],
+ ["KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_BTN1" , "KC_WH_U" , "KC_BTN2" , "KC_TRNS",
+
+ "KC_TRNS" , "KC_BTN2" , "KC_NO" , "KC_BTN1" , "KC_TRNS",
+ "KC_TRNS" , "KC_MS_L" , "KC_MS_D" , "KC_MS_U" , "KC_MS_R",
+
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_WH_L" , "KC_WH_D" , "KC_WH_R" , "KC_TRNS",
+
+ "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS"
+ ],
+ ["KC_TRNS" , "KC_TRNS" , "KC_PGUP" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_LEFT" , "KC_UP" , "KC_DOWN" , "KC_RGHT" , "KC_TRNS",
+ "KC_TRNS" , "KC_LGUI" , "KC_NO" , "LCTL(KC_LALT)" , "LCA(KC_LSFT)",
+
+ "KC_TRNS" , "KC_HOME" , "KC_PGDN" , "KC_END" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS"
+ ],
+ ["KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_UNDS" , "KC_PIPE" , "KC_QUOT" , "KC_TRNS",
+
+ "KC_CIRC" , "KC_ASTR" , "KC_AMPR" , "KC_NO" , "KC_TRNS",
+ "KC_HASH" , "KC_TILD" , "KC_SLSH" , "KC_DQUO" , "KC_DLR",
+
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_MINS" , "KC_BSLS" , "KC_GRV" , "KC_TRNS",
+
+ "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS"
+ ],
+ ["KC_TRNS" , "KC_COLN" , "KC_LT" , "KC_GT" , "KC_SCLN",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_LCBR" , "KC_RCBR" , "KC_LPRN" , "KC_RPRN" , "KC_AT",
+ "KC_TRNS" , "KC_NO" , "KC_EQL" , "KC_PLUS" , "KC_PERC",
+
+ "KC_TRNS" , "KC_EXLM" , "KC_LBRC" , "KC_RBRC" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_VOLD" , "KC_TRNS",
+ "KC_TRNS" , "KC_VOLU"
+ ],
+ ["KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_F7" , "KC_F8" , "KC_F9" , "KC_F10",
+
+ "KC_TRNS" , "KC_NO" , "LCTL(KC_LALT)" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_F4" , "KC_F5" , "KC_F6" , "KC_F11",
+
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_F1" , "KC_F2" , "KC_F3" , "KC_F12",
+
+ "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS"
+ ],
+ ["KC_PSLS" , "KC_7" , "KC_8" , "KC_9" , "KC_PPLS",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_0" , "KC_1" , "KC_2" , "KC_3" , "KC_PMNS",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_NO" , "KC_TRNS",
+
+ "KC_PAST" , "KC_4" , "KC_5" , "KC_6" , "KC_PEQL",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS"
+ ],
+ ["KC_TRNS" , "KC_TRNS" , "KC_COLN" , "KC_ESC" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_DEL",
+
+ "KC_TRNS" , "KC_PERC" , "KC_SLSH" , "KC_ENT" , "KC_TRNS",
+ "DF(1)" , "KC_LGUI" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_EXLM" , "KC_TRNS",
+ "DF(0)" , "KC_TRNS" , "RALT_T(KC_COMM)", "RCTL_T(KC_DOT)", "RESET",
+
+ "KC_TRNS" , "KC_TAB",
+ "KC_NO" , "KC_TRNS"
+ ]
+ ],
+ "author": "@pierrec83"
+}
diff --git a/keyboards/ferris/keymaps/default/readme.md b/keyboards/ferris/keymaps/default/readme.md
new file mode 100644
index 0000000000..252f886f52
--- /dev/null
+++ b/keyboards/ferris/keymaps/default/readme.md
@@ -0,0 +1,122 @@
+A usable default keymap for the Ferris keyboard
+===============================================
+
+Keymaps in general are quite personal, so it is difficult to come up with a default that will suit every user.
+
+This keymap makes heavy use of keys behaving differently when tapped and held, so that all the keys one may need remain accessible despite the low number of thumb keys.
+
+It comes with a number of layers to give access to most of the keys one may need on a keyboard. It is not meant to be the best possible keymap, but rather a good base on which to build a keymap that works for you.
+
+This is not the only way to make 34 keys a comfortable typing experience, but it is one way to do so. If you don't already know of a better way, this may be as good a starting point as any :)
+
+Note that this keymap was built from the perspective that it is OK to take a steep learning curve if it results in a keymap that is easier to use in the long run. This means that it may take more effort to learn this keymap than some alternatives. "Easy to use" was assessed against the workflow of the author, so your mileage may vary on some of the details.
+
+What do all these layers do?
+----------------------------
+
+### Layer 0: Base layer
+
+![Layer 0](https://i.imgur.com/HjNHUPL.png)
+
+On tapping the keys, our base layer is qwerty with space on the right homing thumb and backspace on the left homing thumb.
+
+In this layer, the non-homing-thumb positions have 0 and 1. I recommend modifying this to some frequently accessed shortcut such as copy/paste, previous/next tab or anything that makes most sense in your own workflow. O and 1 are place-holders and make it easy to troubleshoot that all keys are working properly before soldering in the switches.
+The reason I recommend convenience shortcuts instead of more commonly used keys like tab or meta is that unhoming of the thumbs was a frequent source of typos for me when I used more than one thumb key frequently in the context of typing.
+
+Despite being missing on this layer, "meta", "tab", "esc" and such are accessible from any other layer: see Layer 7.
+
+The behaviour of some keys differ when held:
+* Both homing pinkies behave as shift.
+* Both bottom-row ring fingers behave as ctrl.
+* Both bottom-row middle fingers behave as alt.
+
+* The homing left ring finger gives access to the Function keys layer
+* The homing right ring finger gives access to the Numbers layer
+* The homing left middle finger gives access to the Mouse layer
+* The homing right middle finger gives access to the Navigation layer
+* The homing left index finger gives access to the Right symbols layer
+* The homing right index finger gives access to the Left symbols layer
+* The homing right thumb gives access to the Always accessible layer
+
+### Layer 1: Mouse
+
+![Layer 1](https://i.imgur.com/0fvTuB9.png)
+
+Layer 1 is a mouse layer: it can be used one-handed or two-handed. The most common way to use it is two handed, with left and right click on the homerow of the left hand and directions on the homerow of the right hand.
+Scrolling is available on the right hand with mid finger up and down for vertical scroll and index and ring finger down for horizontal scroll.
+On the right hand, left click and right click are also available with index and ring finger up to allow one handed operation. This can be particularly handy when enabling the mouse layer permanently (no need to hold the left middle finger), which can be done from Layer 7.
+
+Note that thanks to the transparency, shift, ctrl and alt are all accessible on the left hand while operating the mouse.
+
+### Layer 2: Navigation
+
+![Layer 2](https://i.imgur.com/ZquQJRq.png)
+
+The navigation layer somewhat mirrors the mouse layer. It is accessed by holding the right middle finger and gives access to arrow keys on the left homerow. Page up and down, Home and End mirror the vertical scrolling and horizontal scrolling on the mouse layer.
+
+On the right hand, in addition to ctrl and alt which are available through transparency, ctrl + alt, ctrl + alt + shift and meta are accessible on the homerow to enable common shortcuts in some window managers. This part is quite workflow dependent, so make sure to adapt it to your own workflow as appropriate.
+
+### Layer 3: Right symbols
+
+![Layer 3](https://i.imgur.com/9tLAUqG.png)
+
+When holding down the left index, one may access about half of the symbols. The pinkies store `^` and `$` symbols that represent begin and end in vim. The left homerow hosts `*` and `&`, symbols which are related in the way that they represent some form of indirection in programming languages such as rust. On the right hand, most symbols used when navigating the command line are stored together, organized by columns of related symbols.
+
+### Layer 4: Left symbols
+
+![Layer 4](https://i.imgur.com/CkjUSW6.png)
+
+When holding down the right index, one may access the other symbols. On the left hand, most of the different brackets are laid out. The most frequent ones (round brackets and curly brackets) get a spot on the homerow. The rest of the layer hosts the remaining symbols that are easier to access here than on any other layers.
+
+### Layer 5: Function keys
+
+![Layer 5](https://i.imgur.com/fWgVqc4.png)
+
+By holding down the left ring finger, one may access the function keys, roughly in a numpad layout.
+This means that alt+F4 is easy to type, with F4 being on the homerow.
+There is a shortcut for ctrl+alt on the left hand to enable convenient switching between virtual terminals on Linux.
+
+### Layer 6: Numbers
+
+![Layer 6](https://i.imgur.com/S8gq9Kj.png)
+
+The number layer is accessed by holding the right ring finger. It hosts the numbers and some duplicated symbols that are commonly accessed next to numbers, such as mathematical operators.
+The number are layed out similarly to a numpad, but with the middle row and the homerow swapped so that the most used numbers: 0, 1, 2 and 3 are all available in homing positions.
+
+### Layer 7: Always accessible
+
+![Layer 7](https://i.imgur.com/twqBeBb.png)
+
+Layer 7 is accessed by holding the right homing thumb down. Because this position is left transparent from every other layer, this layer is always accessible.
+It gives access to some essential keys that would typically be accessed on a thumb cluster or pinkies, such as meta, enter, tab, esc and delete.
+
+As the layer hosting esc, we duplicated some symbols here to allow for fast navigation in vim. For instance, esc, :, w, q can be done in a single roll.
+
+Where is the keymap.c?
+----------------------
+
+The keymap.c file is not published to the repository. It is generated from `keymap.json` by the build system.
+
+This avoids duplicating information and allow users to edit their keymap from the qmk configurator web interface.
+
+How do I edit and update the keymap?
+------------------------------------
+
+The `keymap.json` file is generated from the qmk configurator interface and formatted for better readability in the context of the Ferris keyboard.
+
+To edit it, you may:
+* Edit it directly from a text editor.
+* Edit it from the qmk configurator.
+
+If you decide to use the latter workflow, here are the steps to follow:
+
+* From the qmk configurator, hit the "import QMK keymap json file" button (it has a drawing with an up arrow on it).
+* Browse to the location of your keymap (for example, `<your qmk repo>/keyboards/handwired/ferris/keymaps/default/keymap.json`)
+* Perform any modification to the keymap in the web UI
+* Export the keymap to your downloads folder, by hitting the "Export QMK keymap json file" button (it has a drawing with a down arrow on it)
+* Override your original keymap with the output of formatting the exported keymap by running a command such as this one from the root of your qmk repo:
+ ```
+ ./keyboards/handwired/ferris/keymaps/json2crab.py --input <Your download directory>/default.json > ./keyboards/handwired/ferris/keymaps/default/keymap.json
+ ```
+ Note that you may first need to make json2crab executable by using `chmod +x` on it.
+ Also note that you may then want to remove the exported keymap from your dowload directory.
diff --git a/keyboards/ferris/keymaps/json2crab.py b/keyboards/ferris/keymaps/json2crab.py
new file mode 100755
index 0000000000..a32429fae5
--- /dev/null
+++ b/keyboards/ferris/keymaps/json2crab.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+
+import argparse
+import sys
+import json
+
+indent_level=4
+
+def parse_cli():
+ parser = argparse.ArgumentParser(description='Ferris keymap formatter')
+ parser.add_argument("--input", type=argparse.FileType('r'),
+ default=sys.stdin, help="Input keymap (json file produced by qmk configurator)")
+ return parser.parse_args()
+
+def col_index(key_index):
+ if key_index < 30:
+ col = key_index % 5
+ else:
+ col = key_index % 2
+ return col
+
+def format_layers(layers):
+ formatted = indent_level * " " + "\"layers\": [\n"
+ max_key_length = {}
+ for layer in layers:
+ for (index, keycode) in enumerate(layer):
+ col = col_index(index)
+ max_length = max_key_length.get(col)
+ if (not max_length) or len(keycode) > max_length:
+ max_key_length.update({col: len(keycode)})
+ for (layer_index, layer) in enumerate(layers):
+ formatted += 2 * indent_level * " "
+ formatted += "["
+ for (index, keycode) in enumerate(layer):
+ if index > 30 and index % 2 == 0 or index % 5 == 0 and index != 0:
+ formatted += (1 + 2 * indent_level) * " "
+ formatted += json.dumps(keycode)
+ if index == 33:
+ formatted += "\n"
+ elif index > 30 and index % 2 == 1 or index % 5 == 4:
+ formatted += ",\n"
+ else:
+ n_spaces = max_key_length[col_index(index)] - len(keycode)
+ formatted += n_spaces * " "
+ formatted += ", "
+ if index % 10 == 9:
+ formatted += "\n"
+ formatted += 2 * indent_level * " "
+ if layer_index < len(layers) - 1:
+ formatted += "],\n"
+ else:
+ formatted += "]\n"
+ formatted += indent_level * " "
+ formatted += "]"
+
+ return formatted
+
+def format_keymap(keymap_json):
+ formatted = "{"
+ for (index, k) in enumerate(keymap_json):
+ if k == "layers":
+ formatted += format_layers(keymap_json[k])
+ else:
+ formatted += f"{indent_level * ' '}{json.dumps(k)}: {json.dumps(keymap_json[k])}"
+ if index < len(keymap_json) - 1:
+ formatted += ","
+ formatted += "\n"
+ formatted += "}"
+ return formatted
+
+def main():
+ args=parse_cli()
+ keymap_json = json.loads(args.input.read())
+ print(format_keymap(keymap_json))
+
+main()
diff --git a/keyboards/ferris/keymaps/pierrec83/config.h b/keyboards/ferris/keymaps/pierrec83/config.h
new file mode 100644
index 0000000000..cf0fb7478e
--- /dev/null
+++ b/keyboards/ferris/keymaps/pierrec83/config.h
@@ -0,0 +1,39 @@
+/*
+Copyright 2020 Pierre Chevalier <pierrechevalier83@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/>.
+*/
+
+#pragma once
+// Set the mouse settings to a comfortable speed/accuracy trade-off,
+// assuming a screen refresh rate of 60 Htz or higher
+// The default is 50. This makes the mouse ~3 times faster and more accurate
+#define MOUSEKEY_INTERVAL 16
+// The default is 20. Since we made the mouse about 3 times faster with the previous setting,
+// give it more time to accelerate to max speed to retain precise control over short distances.
+#define MOUSEKEY_TIME_TO_MAX 40
+// The default is 300. Let's try and make this as low as possible while keeping the cursor responsive
+#define MOUSEKEY_DELAY 100
+// It makes sense to use the same delay for the mouseweel
+#define MOUSEKEY_WHEEL_DELAY 100
+// The default is 100
+#define MOUSEKEY_WHEEL_INTERVAL 50
+// The default is 40
+#define MOUSEKEY_WHEEL_TIME_TO_MAX 100
+
+// Pick good defaults for enabling homerow modifiers
+#define TAPPING_TERM 200
+#define PERMISSIVE_HOLD
+#define IGNORE_MOD_TAP_INTERRUPT
+#define TAPPING_FORCE_HOLD
diff --git a/keyboards/ferris/keymaps/pierrec83/keymap.json b/keyboards/ferris/keymaps/pierrec83/keymap.json
new file mode 100644
index 0000000000..2372e7e372
--- /dev/null
+++ b/keyboards/ferris/keymaps/pierrec83/keymap.json
@@ -0,0 +1,118 @@
+{ "version": 1,
+ "notes": "My awesome keymap",
+ "documentation": "\"This file is a QMK Configurator export. You can import this at <https://config.qmk.fm>. It can also be used directly with QMK's source code.\n\nTo setup your QMK environment check out the tutorial: <https://docs.qmk.fm/#/newbs>\n\nYou can convert this file to a keymap.c using this command: `qmk json2c {keymap}`\n\nYou can compile this keymap using this command: `qmk compile {keymap}`\"\n",
+ "keyboard": "handwired/ferris",
+ "keymap": "pierrec83",
+ "layout": "LAYOUT",
+ "layers": [
+ ["KC_Q" , "KC_D" , "KC_R" , "KC_W" , "KC_B",
+ "KC_J" , "KC_F" , "KC_U" , "KC_P" , "KC_SCLN",
+
+ "LSFT_T(KC_A)" , "LT(6,KC_S)" , "LT(2,KC_H)" , "LT(4,KC_T)" , "KC_G",
+ "KC_Y" , "LT(5,KC_N)" , "LT(3,KC_E)" , "LT(7,KC_O)" , "LSFT_T(KC_I)",
+
+ "KC_Z" , "LCTL_T(KC_X)" , "LALT_T(KC_M)" , "KC_C" , "KC_V",
+ "KC_K" , "KC_L" , "LALT_T(KC_COMM)", "LCTL_T(KC_DOT)" , "KC_SLSH",
+
+ "LCA(KC_UP)" , "KC_BSPC",
+ "LT(8,KC_SPC)" , "LCA(KC_DOWN)"
+ ],
+ ["KC_Q" , "KC_C" , "KC_M" , "KC_Y" , "KC_COLN",
+ "KC_Z" , "KC_W" , "KC_COMM" , "KC_U" , "KC_J",
+
+ "LSFT_T(KC_R)" , "LT(6,KC_S)" , "LT(2,KC_T)" , "LT(4,KC_H)" , "KC_X",
+ "KC_TRNS" , "LT(5,KC_N)" , "LT(3,KC_A)" , "LT(7,KC_I)" , "LSFT_T(KC_O)",
+
+ "KC_B" , "LCTL_T(KC_F)" , "LALT_T(KC_G)" , "KC_D" , "KC_V",
+ "KC_ESC" , "KC_L" , "LALT_T(KC_DOT)" , "LCTL_T(KC_BSPC)" , "KC_K",
+
+ "LCA(KC_UP)" , "KC_E",
+ "LT(8,KC_SPC)" , "LCA(KC_DOWN)"
+ ],
+ ["KC_TRNS" , "ANY(LCTL(LSFT(KC_C)))", "KC_TRNS" , "ANY(LCTL(LSFT(KC_V)))", "KC_TRNS",
+ "KC_TRNS" , "KC_BTN1" , "KC_WH_U" , "KC_BTN2" , "KC_TRNS",
+
+ "KC_TRNS" , "KC_BTN2" , "KC_NO" , "KC_BTN1" , "KC_TRNS",
+ "KC_TRNS" , "KC_MS_L" , "KC_MS_D" , "KC_MS_U" , "KC_MS_R",
+
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_WH_L" , "KC_WH_D" , "KC_WH_R" , "KC_TRNS",
+
+ "ANY(LCTL(LSFT(KC_TAB)))", "KC_TRNS",
+ "KC_TRNS" , "LCTL(KC_TAB)"
+ ],
+ ["KC_TRNS" , "KC_TRNS" , "KC_PGUP" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_LEFT" , "KC_UP" , "KC_DOWN" , "KC_RGHT" , "KC_TRNS",
+ "KC_TRNS" , "KC_LGUI" , "KC_NO" , "LCTL(KC_LALT)" , "LCA(KC_LSFT)",
+
+ "KC_TRNS" , "KC_HOME" , "KC_PGDN" , "KC_END" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "LGUI(KC_LEFT)" , "KC_TRNS",
+ "KC_TRNS" , "LGUI(KC_RGHT)"
+ ],
+ ["KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_UNDS" , "KC_PIPE" , "KC_QUOT" , "KC_TRNS",
+
+ "KC_CIRC" , "KC_ASTR" , "KC_AMPR" , "KC_NO" , "KC_TRNS",
+ "KC_HASH" , "KC_TILD" , "KC_SLSH" , "KC_DQUO" , "KC_DLR",
+
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_MINS" , "KC_BSLS" , "KC_GRV" , "KC_TRNS",
+
+ "KC_BRID" , "KC_TRNS",
+ "KC_TRNS" , "KC_BRIU"
+ ],
+ ["KC_TRNS" , "KC_COLN" , "KC_LT" , "KC_GT" , "KC_SCLN",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_LCBR" , "KC_RCBR" , "KC_LPRN" , "KC_RPRN" , "KC_AT",
+ "KC_TRNS" , "KC_NO" , "KC_EQL" , "KC_PLUS" , "KC_PERC",
+
+ "KC_TRNS" , "KC_EXLM" , "KC_LBRC" , "KC_RBRC" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_VOLD" , "KC_TRNS",
+ "KC_TRNS" , "KC_VOLU"
+ ],
+ ["KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_F7" , "KC_F8" , "KC_F9" , "KC_F10",
+
+ "KC_TRNS" , "KC_TRNS" , "LCTL(KC_LALT)" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_F4" , "KC_F5" , "KC_F6" , "KC_F11",
+
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_F1" , "KC_F2" , "KC_F3" , "KC_F12",
+
+ "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS"
+ ],
+ ["KC_PSLS" , "KC_7" , "KC_8" , "KC_9" , "KC_PPLS",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_0" , "KC_1" , "KC_2" , "KC_3" , "KC_PMNS",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_NO" , "KC_TRNS",
+
+ "KC_PAST" , "KC_4" , "KC_5" , "KC_6" , "KC_PEQL",
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_TRNS" , "KC_TRNS",
+ "KC_TRNS" , "KC_TRNS"
+ ],
+ ["KC_TRNS" , "KC_ESC" , "KC_COLN" , "KC_TRNS" , "KC_TRNS",
+ "DF(2)" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_DEL",
+
+ "KC_TRNS" , "KC_PERC" , "KC_SLSH" , "KC_ENT" , "KC_EXLM",
+ "DF(1)" , "KC_LGUI" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+
+ "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS" , "KC_TRNS",
+ "DF(0)" , "KC_TRNS" , "RALT_T(KC_COMM)", "RCTL_T(KC_DOT)" , "RESET",
+
+ "KC_TRNS" , "KC_TAB",
+ "KC_NO" , "KC_TRNS"
+ ]
+ ],
+ "author": "@pierrec83"
+}
diff --git a/keyboards/ferris/keymaps/pierrec83/readme.md b/keyboards/ferris/keymaps/pierrec83/readme.md
new file mode 100644
index 0000000000..d96a3bb811
--- /dev/null
+++ b/keyboards/ferris/keymaps/pierrec83/readme.md
@@ -0,0 +1,43 @@
+@pierrec83's personal keymap for the Ferris keyboard
+====================================================
+
+This keymap shares many commonalities with the default keymap.
+See its readme for a write-up on many of the decisions, including
+how to generate the formatted json file with json2crab.py and the
+general philosophy for each layer.
+
+Because this is my own keymap, I didn't refrain from using shortcuts
+that make sense for me and may not make sense for most.
+
+Key differences from the default keymap include:
+
+Alpha layers:
+-------------
+
+Because I only learned to touch type when I switched from qwerty to workman,
+my base layer is workman and my layout doesn't contain a qwerty layer.
+
+My layer 1 hosts a variant of RSTHD that I am developing, inspired from workman's
+focus on reducing side-index-motion. It should become my end game keymap eventually,
+but I still haven't found the time to learn it to a working proficiency.
+
+Secondary thumbs:
+-----------------
+
+Instead of a placeholder 0 and 1, the secondary thumbs on my keymap
+perform the following actions:
+* Navigate to previous and next workspace the base layer
+* Navigate to previous and next tab on the mouse layer
+* Volume control on layer
+* Brightness control on layer
+
+Mouse layer:
+------------
+
+* Copy/Paste shortcuts on the left hand, on the upper row.
+
+Always available layer:
+-----------------------
+
+* Esc and column are placed differently to allow easy vim navigation with the positions of w and q in the workman base layer
+* Enable permanent switch to the RSTHD layer in addition to the mouse layer
diff --git a/keyboards/ferris/readme.md b/keyboards/ferris/readme.md
new file mode 100644
index 0000000000..74a08a38fe
--- /dev/null
+++ b/keyboards/ferris/readme.md
@@ -0,0 +1,19 @@
+# Ferris
+
+![Ferris, top view](https://imgur.com/V4QuaGs.jpg)
+![Ferris, bottom view](https://i.imgur.com/7DJYME8.jpg)
+
+A split 34 keys column staggered keyboard named and decorated after the rustlang mascott. All PCB files and some thoughts on the design are available on the [project's github page](https://github.com/pierrechevalier83/ferris)
+
+* Keyboard Maintainer: [Pierre Chevalier](https://github.com/pierrechevalier83)
+* Hardware Supported:
+ * Ferris 0.1 (With atmega32u4 chip. Comes in 4 variants: base, low, high and compact)
+ * Ferris sweep (With pro-micro. Comes in a couple of PCB edge cuts shapes, but with identical pinout)
+* Hardware Availability: Pierre Chevalier has been selling keyboard kits (see the #ferris channel in the 40% discord chat). Wider availability is on the horizon.
+
+Make examples for this keyboard (after setting up your build environment):
+
+ make ferris/0_1:default
+ make ferris/sweep:default:avrdude-split-right
+
+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).
diff --git a/keyboards/ferris/sweep/config.h b/keyboards/ferris/sweep/config.h
new file mode 100644
index 0000000000..ad960610d1
--- /dev/null
+++ b/keyboards/ferris/sweep/config.h
@@ -0,0 +1,74 @@
+/* Copyright 2018-2020 ENDO Katsuhiro <ka2hiro@curlybracket.co.jp> David Philip Barr <@davidphilipbarr> Pierre Chevalier <pierrechevalier83@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/>.
+*/
+
+#pragma once
+
+#include "config_common.h"
+
+/* USB Device descriptor parameter */
+#define VENDOR_ID 0xC2AB
+#define PRODUCT_ID 0x3939
+#define DEVICE_VER 0x0001
+#define MANUFACTURER DPB
+#define PRODUCT Ferris sweep
+
+/* key matrix size */
+#define MATRIX_ROWS 8
+#define MATRIX_COLS 5
+
+/*
+ * Keyboard Matrix Assignments
+ *
+ * Change this to how you wired your keyboard
+ * COLS: AVR pins used for columns, left to right
+ * ROWS: AVR pins used for rows, top to bottom
+ * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode)
+ * ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
+ * NO_DIODE = switches are directly connected to AVR pins
+ *
+*/
+#define DIRECT_PINS { \
+ { E6, F7, F6, F5, F4 }, \
+ { B1, B3, B2, B6, D3 }, \
+ { D1, D0, D4, C6, D7 }, \
+ { B4, B5, NO_PIN, NO_PIN, NO_PIN } \
+}
+
+#define DIRECT_PINS_RIGHT { \
+ { F4, F5, F6, F7, E6 }, \
+ { D3,B6,B2,B3,B1 }, \
+ { D7,C6,D4,D0,D1}, \
+ { B5, B4, NO_PIN, NO_PIN, NO_PIN } \
+}
+
+
+
+#define UNUSED_PINS
+
+/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
+#define DEBOUNCE 5
+
+/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
+#define LOCKING_SUPPORT_ENABLE
+/* Locking resynchronize hack */
+#define LOCKING_RESYNC_ENABLE
+
+/* Serial settings */
+#define USE_SERIAL
+/* serial.c configuration for split keyboard */
+#define SOFT_SERIAL_PIN D2
+
+#define EE_HANDS
diff --git a/keyboards/ferris/sweep/rules.mk b/keyboards/ferris/sweep/rules.mk
new file mode 100644
index 0000000000..ce4d52156d
--- /dev/null
+++ b/keyboards/ferris/sweep/rules.mk
@@ -0,0 +1,24 @@
+# MCU name
+MCU = atmega32u4
+
+# Bootloader selection
+BOOTLOADER = caterina
+
+# Build Options
+# change yes to no to disable
+#
+BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration
+MOUSEKEY_ENABLE = yes # Mouse keys
+EXTRAKEY_ENABLE = yes # Audio control and System control
+CONSOLE_ENABLE = no # Console for debug
+COMMAND_ENABLE = no # Commands for debug and configuration
+# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
+SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
+# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
+NKRO_ENABLE = no # USB Nkey Rollover
+BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
+RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
+UNICODE_ENABLE = yes # Unicode
+BLUETOOTH_ENABLE = no # Enable Bluetooth
+AUDIO_ENABLE = no # Audio output
+SPLIT_KEYBOARD = yes # Use shared split_common code
diff --git a/keyboards/ferris/sweep/sweep.c b/keyboards/ferris/sweep/sweep.c
new file mode 100644
index 0000000000..5b41bad848
--- /dev/null
+++ b/keyboards/ferris/sweep/sweep.c
@@ -0,0 +1,16 @@
+/* Copyright 2018-2020 ENDO Katsuhiro <ka2hiro@curlybracket.co.jp> David Philip Barr <@davidphilipbarr> Pierre Chevalier <pierrechevalier83@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 "sweep.h"
diff --git a/keyboards/ferris/sweep/sweep.h b/keyboards/ferris/sweep/sweep.h
new file mode 100644
index 0000000000..e8d66ebc67
--- /dev/null
+++ b/keyboards/ferris/sweep/sweep.h
@@ -0,0 +1,47 @@
+/* Copyright 2018-2020 ENDO Katsuhiro <ka2hiro@curlybracket.co.jp> David Philip Barr <@davidphilipbarr> Pierre Chevalier <pierrechevalier83@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 "quantum.h"
+
+/* This a shortcut to help you visually see your layout.
+ *
+ * The first section contains all of the arguments representing the physical
+ * layout of the board and position of the keys.
+ *
+ * The second converts the arguments into a two-dimensional array which
+ * represents the switch matrix.
+ */
+
+// readability
+#define ___ KC_NO
+
+#define LAYOUT( \
+ L01, L02, L03, L04, L05, R01, R02, R03, R04, R05, \
+ L06, L07, L08, L09, L10, R06, R07, R08, R09, R10, \
+ L11, L12, L13, L14, L15, R11, R12, R13, R14, R15, \
+ L16, L17, R16, R17 \
+ ) \
+ { \
+ { L01, L02, L03, L04, L05 }, \
+ { L06, L07, L08, L09, L10 }, \
+ { L11, L12, L13, L14, L15 }, \
+ { L16, L17, ___, ___ , ___}, \
+ { R01, R02, R03, R04, R05 }, \
+ { R06, R07, R08, R09, R10 }, \
+ { R11, R12, R13, R14, R15 }, \
+ { R16, R17, ___, ___, ___ } \
+ }
+