~ruther/qmk_firmware

a9c6adb083556ae485dbf1e9f86ad615e32a8b7a — talsu 4 years ago f9d88da
[Keyboard] Add KMAC PAD (#13104)

Co-authored-by: Drashna Jaelre <drashna@live.com>
Co-authored-by: Ryan <fauxpark@gmail.com>
A keyboards/kmac_pad/config.h => keyboards/kmac_pad/config.h +102 -0
@@ 0,0 1,102 @@
/*
Copyright 2021 talsu <talsu84@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 0x4B4D   // KM
#define PRODUCT_ID 0x4143  // AC
#define DEVICE_VER 0x0104
#define MANUFACTURER KBDMania
#define PRODUCT KMAC PAD

/* key matrix size */
#define MATRIX_ROWS 6
#define MATRIX_COLS 4

/*
 * Keyboard Matrix Assignments
 * The KMAC uses demultiplexers for the cols, they are only included here as documentation.
 * See matrix.c for more details.
 */
#define MATRIX_ROW_PINS { E2, D0, D1, D2, D3, D5 }
#define MATRIX_COL_PINS { C7, C6, B6, B5 }
#define UNUSED_PINS

/* COL2ROW, ROW2COL*/
// #define DIODE_DIRECTION COL2ROW

// #define LED_CAPS_LOCK_PIN B0
// #define LED_SCROLL_LOCK_PIN E6
// #define LED_PIN_ON_STATE 0

/* number of backlight levels */
// #define BACKLIGHT_LEVELS 3
// #define BACKLIGHT_PIN B7
// #define BACKLIGHT_BREATHING

/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
#define DEBOUNCE 5

/* define if matrix has ghost (lacks anti-ghosting diodes) */
//#define MATRIX_HAS_GHOST

/* 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

/*
 * Force NKRO
 *
 * Force NKRO (nKey Rollover) to be enabled by default, regardless of the saved
 * state in the bootmagic EEPROM settings. (Note that NKRO must be enabled in the
 * makefile for this to work.)
 *
 * If forced on, NKRO can be disabled via magic key (default = LShift+RShift+N)
 * until the next keyboard reset.
 *
 * NKRO may prevent your keystrokes from being detected in the BIOS, but it is
 * fully operational during normal computer usage.
 *
 * For a less heavy-handed approach, enable NKRO via magic key (LShift+RShift+N)
 * or via bootmagic (hold SPACE+N while plugging in the keyboard). Once set by
 * bootmagic, NKRO mode will always be enabled until it is toggled again during a
 * power-up.
 *
 */
//#define FORCE_NKRO

/*
 * Feature disable options
 *  These options are also useful to firmware size reduction.
 */

/* disable debug print */
//#define NO_DEBUG

/* disable print */
//#define NO_PRINT

/* disable action features */
//#define NO_ACTION_LAYER
//#define NO_ACTION_TAPPING
//#define NO_ACTION_ONESHOT
//#define NO_ACTION_MACRO
//#define NO_ACTION_FUNCTION

A keyboards/kmac_pad/info.json => keyboards/kmac_pad/info.json +35 -0
@@ 0,0 1,35 @@
{
  "keyboard_name": "KMAC PAD",
  "maintainer": "talsu",
  "width": 4,
  "height": 6.5,
  "layouts": {
    "LAYOUT": {
      "layout": [
        {"label":"K00", "x":3, "y":0},

        {"label":"K10", "x":0, "y":1.25},
        {"label":"K11", "x":1, "y":1.25},
        {"label":"K12", "x":2, "y":1.25},
        {"label":"K13", "x":3, "y":1.25},

        {"label":"K20", "x":0, "y":2.25},
        {"label":"K21", "x":1, "y":2.25},
        {"label":"K22", "x":2, "y":2.25},
        {"label":"K23", "x":3, "y":2.25, "h":2},

        {"label":"K30", "x":0, "y":3.25},
        {"label":"K31", "x":1, "y":3.25},
        {"label":"K32", "x":2, "y":3.25},

        {"label":"K40", "x":0, "y":4.25},
        {"label":"K41", "x":1, "y":4.25},
        {"label":"K42", "x":2, "y":4.25},
        {"label":"K43", "x":3, "y":4.25, "h":2},

        {"label":"K50", "x":0, "y":5.25, "w":2},
        {"label":"K52", "x":2, "y":5.25}
      ]
    }
  }
}

A keyboards/kmac_pad/keymaps/default/keymap.c => keyboards/kmac_pad/keymaps/default/keymap.c +143 -0
@@ 0,0 1,143 @@
/*
Copyright 2021 talsu <talsu84@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include QMK_KEYBOARD_H

enum kmac_pad_keycodes {
    MD_BOOT = SAFE_RANGE,
    MCR1,
    MCR2,
    MCR3,
    MCR4,
    MCR5,
    MCR6,
    MCR7,
    MCR8,
    MCR9,
    MCR10,
    MCR11,
    MCR12
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [0] = LAYOUT( /* Base */
                               TG(1),
    KC_NLCK, KC_PSLS, KC_PAST, KC_PMNS,
    KC_P7,   KC_P8,   KC_P9,   KC_PPLS,
    KC_P4,   KC_P5,   KC_P6,
    KC_P1,   KC_P2,   KC_P3,   KC_PENT,
    KC_P0,            KC_PDOT          ),
    [1] = LAYOUT( /* FN  */
                               KC_TRNS,
    MCR1,    MCR2,    MCR3,    KC_TRNS,
    MCR4,    MCR5,    MCR6,    KC_TRNS,
    MCR7,    MCR8,    MCR9,
    MCR10,   MCR11,   MCR12,   KC_TRNS,
    KC_TRNS,          MD_BOOT          )
};

bool process_record_user(uint16_t keycode, keyrecord_t *record) {

    switch (keycode) {
        case MD_BOOT:
        {
            static uint32_t key_timer;
            if (record->event.pressed) {
                key_timer = timer_read32();
            } else {
                if (timer_elapsed32(key_timer) >= 2000) {
                    reset_keyboard();
                }
            }
            return false;
        }
        case MCR1:
            if (record->event.pressed) {
                SEND_STRING("Macro 1");
            }
            return false;
        case MCR2:
            if (record->event.pressed) {
                SEND_STRING("Macro 2");
            }
            return false;
        case MCR3:
            if (record->event.pressed) {
                SEND_STRING("Macro 3");
            }
            return false;
        case MCR4:
            if (record->event.pressed) {
                SEND_STRING("Macro 4");
            }
            return false;
        case MCR5:
            if (record->event.pressed) {
                SEND_STRING("Macro 5");
            }
            return false;
        case MCR6:
            if (record->event.pressed) {
                SEND_STRING("Macro 6");
            }
            return false;
        case MCR7:
            if (record->event.pressed) {
                SEND_STRING("Macro 7");
            }
            return false;
        case MCR8:
            if (record->event.pressed) {
                SEND_STRING("Macro 8");
            }
            return false;
        case MCR9:
            if (record->event.pressed) {
                SEND_STRING("Macro 9");
            }
            return false;
        case MCR10:
            if (record->event.pressed) {
                SEND_STRING("Macro 10");
            }
            return false;
        case MCR11:
            if (record->event.pressed) {
                SEND_STRING("Macro 12");
            }
            return false;
        case MCR12:
            if (record->event.pressed) {
                SEND_STRING("Macro 12");
            }
            return false;
        default:
            return true;
    }

}

bool led_update_user(led_t led_state) {
    writePin(B1, led_state.num_lock);
    return false;
}


layer_state_t layer_state_set_user(layer_state_t state) {
    writePin(B3, !IS_LAYER_ON_STATE(state, 0));
    return state;
}

A keyboards/kmac_pad/keymaps/default/readme.md => keyboards/kmac_pad/keymaps/default/readme.md +61 -0
@@ 0,0 1,61 @@
# The default keymap for KMAC PAD

This is the default keymap. It implements the same features as the official default KMAC PAD firmware.

## Layers

The keymap has two layers. Press the 'FN' key to toggle the Default layer and Function layer.

### Layer 1: Default Layer

                ,---.
                |TG1|
                `---'
    ,---------------.
    |NUM| / | * | - |
    |---------------|
    | 7 | 8 | 9 |   |
    |-----------| + |
    | 4 | 5 | 6 |   |
    |---------------|
    | 1 | 2 | 3 |   |
    |-----------|Ent|
    |   0   | . |   |
    '---------------'

### Layer 2: Function Layer

                ,---.
                |TG1|
                `---'
    ,---------------.
    |M1 |M2 |M3 |   |
    |---------------|
    |M4 |M5 |M6 |   |
    |-----------|   |
    |M7 |M8 |M9 |   |
    |---------------|
    |M10|M11|M12|   |
    |-----------|   |
    |       |   |   |
    '---------------'

## Macros

The default macro is typed with meaningless strings that exist as samples.


| Macro | Action                                 |
|:-----:| -------------------------------------- |
| 1     | Types `Macro 1`                        |
| 2     | Types `Macro 2`                        |
| 3     | Types `Macro 3`                        |
| 4     | Types `Macro 4`                        |
| 5     | Types `Macro 5`                        |
| 6     | Types `Macro 6`                        |
| 7     | Types `Macro 7`                        |
| 8     | Types `Macro 8`                        |
| 9     | Types `Macro 9`                        |
| 10    | Types `Macro 10`                       |
| 11    | Types `Macro 11`                       |
| 12    | Types `Macro 12`                       |

A keyboards/kmac_pad/kmac_pad.c => keyboards/kmac_pad/kmac_pad.c +29 -0
@@ 0,0 1,29 @@
/*
Copyright 2021 talsu <talsu84@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 "kmac_pad.h"

void keyboard_pre_init_kb(void) {

    /* Set Backlight pin as output
     * FN Pin PB3
     * PAD Pin PB1
     */
    setPinOutput(B3);
    setPinOutput(B1);
    keyboard_pre_init_user();
}

A keyboards/kmac_pad/kmac_pad.h => keyboards/kmac_pad/kmac_pad.h +37 -0
@@ 0,0 1,37 @@
/*
Copyright 2021 talsu <talsu84@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"

#define LAYOUT( \
                   K00, \
    K10, K11, K12, K13, \
    K20, K21, K22, K23, \
    K30, K31, K32,      \
    K40, K41, K42, K43, \
    K50,      K52       \
) \
{ \
    { K00, KC_NO, KC_NO, KC_NO }, \
    { K10, K11,   K12,   K13   }, \
    { K20, K21,   K22,   K23   }, \
    { K30, K31,   K32,   KC_NO }, \
    { K40, K41,   K42,   K43   }, \
    { K50, KC_NO, K52,   KC_NO }  \
}

A keyboards/kmac_pad/matrix.c => keyboards/kmac_pad/matrix.c +111 -0
@@ 0,0 1,111 @@
/*
Copyright 2021 talsu <talsu84@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 "wait.h"
#include "matrix.h"
#include "quantum.h"

static const pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;

/* Columns 0 - 3
 * col / pin:
 * 0: C7
 * 1: C6
 * 2: B6
 * 3: B5
 */
static void unselect_cols(void) {
    for (uint8_t col = 0; col < MATRIX_COLS; col++) {
        setPinOutput(col_pins[col]);
        writePinLow(col_pins[col]);
    }
}

static void select_col(uint8_t col) {
    writePinHigh(col_pins[col]);
}

static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
    bool matrix_changed = false;

    // Select col and wait for col selecton to stabilize
    select_col(current_col);
    wait_us(30);

    // row:0 , col:0 FN key is DIRECT_PIN
    if (current_col == 0) {

        matrix_row_t last_row_value = current_matrix[0];
        if (readPin(row_pins[0]) == 0) {
            // Pin LO, set col bit
            current_matrix[0] |= (1 << current_col);
        } else {
            // Pin HI, clear col bit
            current_matrix[0] &= ~(1 << current_col);
        }

        // Determine if the matrix changed state
        if ((last_row_value != current_matrix[0]) && !(matrix_changed)) {
            matrix_changed = true;
        }
    }

    // other row use MATRIX
    for (uint8_t row_index = 1; row_index < MATRIX_ROWS; row_index++) {

        matrix_row_t last_row_value = current_matrix[row_index];
        if (readPin(row_pins[row_index]) == 0) {
            // Pin HI, clear col bit
            current_matrix[row_index] &= ~(1 << current_col);
        } else {
            // Pin LO, set col bit
            current_matrix[row_index] |= (1 << current_col);
        }

        // Determine if the matrix changed state
        if ((last_row_value != current_matrix[row_index]) && !(matrix_changed)) {
            matrix_changed = true;
        }
    }


    // Unselect cols
    unselect_cols();

    return matrix_changed;
}

void matrix_init_custom(void) {
    // initialize hardware and global matrix state here
    unselect_cols();

    // initialize key pins
    for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) {
        setPinInputHigh(row_pins[row_index]);
    }
}

bool matrix_scan_custom(matrix_row_t current_matrix[]) {
    bool changed = false;

    for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
        changed |= read_rows_on_col(current_matrix, current_col);
    }

    return changed;
}

A keyboards/kmac_pad/readme.md => keyboards/kmac_pad/readme.md +56 -0
@@ 0,0 1,56 @@
# KMAC PAD

![kmac_pad](https://i.imgur.com/4P1ybgNl.jpg)

KMAC PAD is a num pad keyboard.
It can be used independently, but can also be used by connecting with KMAC keyboard case.

* Keyboard Maintainer: [talsu](https://github.com/talsu)
* Hardware Supported: KMAC PAD
* Hardware Availability: http://www.kbdmania.net/xe/news/5232321

Make example for this keyboard (after setting up your build environment):

    make kmac_pad:default
    
Flashing example for this keyboard:

    make kmac_pad:default:flash

See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).

## Bootloader

The PCB is hardwired to run the bootloader if the key at the `FN` position (the only key in first row) is held down when connecting the keyboard.

## PCB

![Imgur](https://i.imgur.com/ML66cvfl.jpg)
![Imgur](https://i.imgur.com/Kr2Wdtkl.jpg)

### Switch Pins

The FN key in the `Row 0` is directly connected to the E2 pin.   
The rest of the rows below that use MATRIX. (`Row 1 ~ Row 5`)
| Row   | Pin                    |
|:-----:| ---------------------- |
| 0     | x (Not in Matrix)      |
| 1     | D0                     |
| 2     | D1                     |
| 3     | D2                     |
| 4     | D3                     |
| 5     | D5                     |

| Column | Pin                   |
|:------:| --------------------- |
| 0      | C7                    |
| 1      | C6                    |
| 2      | B6                    |
| 3      | B5                    |

### Backlight Pins

There are 2 pins for backlight.

The LED of the FN key uses pin `B3`.
All other keys are connected to the `B1` pin.

A keyboards/kmac_pad/rules.mk => keyboards/kmac_pad/rules.mk +29 -0
@@ 0,0 1,29 @@
# MCU name
MCU = atmega32u4

# Processor frequency
F_CPU = 8000000

# Bootloader selection
BOOTLOADER = atmel-dfu

# Build Options
#   change yes to no to disable
#
BOOTMAGIC_ENABLE = full     # 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 = yes           # 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
CUSTOM_MATRIX = lite        # Custom matrix file

# Project specific files
SRC += matrix.c