Compare commits

..

2 Commits
0.7.5 ... 0.7.6

Author SHA1 Message Date
Benjamin Grosse
55bae0a5b4 [Keymap] Satan GH60 with command prompt animation, react to keypresses (#6636)
Co-Authored-By: fauxpark <fauxpark@gmail.com>
Signed-off-by: Benjamin Große <benjamin@midokura.com>
2019-09-03 08:35:43 -07:00
Drashna Jaelre
dab4967f1b Add Dip Switch as a core feature (#6140)
* Add Dip Switches as a core feature

* Add documentation for Dip Switch feature

* Update Preonic Rev3 to use new feature and remove custom matrix

* Apply suggestions from code review

Co-Authored-By: noroadsleft <18669334+noroadsleft@users.noreply.github.com>

* Remove custom matrix line completely

Rather than just disabling it

Co-Authored-By: fauxpark <fauxpark@gmail.com>

* DIP changes

Co-Authored-By: fauxpark <fauxpark@gmail.com>

* Use better check for DIP Switch configuration

* Add to show features

* Add bitmask callback for dip switch

* Fix OLKB Boards dip switch config

* Update docs to include bitmask example

* Fix comments/documentation

Co-Authored-By: fauxpark <fauxpark@gmail.com>

* Fix issues with docs and use example from @tuzonghua

* Fix wording

Co-Authored-By: fauxpark <fauxpark@gmail.com>

* Fix example to use proper formatting

Bad, BAAAAAAD drashna!!!

* Handle dip switch initialization better
2019-09-03 08:34:31 -07:00
24 changed files with 435 additions and 393 deletions

View File

@@ -358,3 +358,9 @@ ifeq ($(strip $(SPACE_CADET_ENABLE)), yes)
SRC += $(QUANTUM_DIR)/process_keycode/process_space_cadet.c
OPT_DEFS += -DSPACE_CADET_ENABLE
endif
ifeq ($(strip $(DIP_SWITCH_ENABLE)), yes)
SRC += $(QUANTUM_DIR)/dip_switch.c
OPT_DEFS += -DDIP_SWITCH_ENABLE
endif

View File

@@ -63,6 +63,7 @@
* [Combos](feature_combo.md)
* [Command](feature_command.md)
* [Debounce API](feature_debounce_type.md)
* [DIP Switch](feature_dip_switch.md)
* [Dynamic Macros](feature_dynamic_macros.md)
* [Encoders](feature_encoders.md)
* [Grave Escape](feature_grave_esc.md)

View File

@@ -0,0 +1,90 @@
# DIP Switches
DIP switches are supported by adding this to your `rules.mk`:
DIP_SWITCH_ENABLE = yes
and this to your `config.h`:
```c
#define DIP_SWITCH_PINS { B14, A15, A10, B9 }
```
## Callbacks
The callback functions can be inserted into your `<keyboard>.c`:
```c
void dip_switch_update_kb(uint8_t index, bool active) {
dip_switch_update_user(index, active);
}
```
or `keymap.c`:
```c
void dip_switch_update_user(uint8_t index, bool active) {
switch (index) {
case 0:
if(active) { audio_on(); } else { audio_off(); }
break;
case 1:
if(active) { clicky_on(); } else { clicky_off(); }
break;
case 2:
if(active) { music_on(); } else { music_off(); }
break;
case 3:
if (active) {
#ifdef AUDIO_ENABLE
PLAY_SONG(plover_song);
#endif
layer_on(_PLOVER);
} else {
#ifdef AUDIO_ENABLE
PLAY_SONG(plover_gb_song);
#endif
layer_off(_PLOVER);
}
break;
}
}
```
Additionally, we support bit mask functions which allow for more complex handling.
```c
void dip_switch_update_mask_kb(uint32_t state) {
dip_switch_update_mask_user(state);
}
```
or `keymap.c`:
```c
void dip_switch_update_mask_user(uint32_t state) {
if (state & (1UL<<0) && state & (1UL<<1)) {
layer_on(_ADJUST); // C on esc
} else {
layer_off(_ADJUST);
}
if (state & (1UL<<0)) {
layer_on(_TEST_A); // A on ESC
} else {
layer_off(_TEST_A);
}
if (state & (1UL<<1)) {
layer_on(_TEST_B); // B on esc
} else {
layer_off(_TEST_B);
}
}
```
## Hardware
One side of the DIP switch should be wired directly to the pin on the MCU, and the other side to ground. It should not matter which side is connected to which, as it should be functionally the same.

View File

@@ -12,6 +12,7 @@ QMK has a staggering number of features for building your keyboard. It can take
* [Combos](feature_combo.md) - Custom actions for multiple key holds.
* [Command](feature_command.md) - Runtime version of bootmagic (Formerly known as "Magic").
* [Debounce API](feature_debounce_type.md) - Customization of debouncing algorithms, and the ability to add more/custom debouncing.
* [DIP Switch](feature_dip_switch.md) - Toggle switches for customizing board function.
* [Dynamic Macros](feature_dynamic_macros.md) - Record and playback macros from the keyboard itself.
* [Encoders](feature_encoders.md) - Rotary encoders!
* [Grave Escape](feature_grave_esc.md) - Lets you use a single key for Esc and Grave.

View File

@@ -54,6 +54,7 @@
* [热改键](feature_bootmagic.md)
* [组合](feature_combo)
* [命令](feature_command.md)
* [拨动开关](feature_dip_switch.md)
* [动态宏指令](feature_dynamic_macros.md)
* [编码器](feature_encoders.md)
* [重音号Esc复合键](feature_grave_esc.md)

View File

@@ -0,0 +1,10 @@
#undef RGBLED_NUM
#define RGBLED_NUM 17
#undef RGBLIGHT_HUE_STEP
#define RGBLIGHT_HUE_STEP 5
#undef RGBLIGHT_SAT_STEP
#define RGBLIGHT_SAT_STEP 5
#undef RGBLIGHT_VAL_STEP
#define RGBLIGHT_VAL_STEP 5
#undef RGBLIGHT_ANIMATIONS

View File

@@ -0,0 +1,161 @@
#include QMK_KEYBOARD_H
#include "rgblight.h"
enum layer_names {
_BL,
_FL
};
/**
* HHKB style.
* Esc on capslock, space-hold is fn.
* Fn layer has hjkl arrows, home on backspace, rgb stuff.
*/
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_BL] = LAYOUT_60_ansi(
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS,
KC_ESC, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT,
_______, KC_LCTL, KC_LALT, LT(_FL,KC_SPC), KC_LGUI, KC_RALT, KC_RCTL, _______
),
[_FL] = LAYOUT_60_ansi(
RESET, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_HOME,
RGB_MOD, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, BL_DEC, BL_INC, BL_TOGG,
_______, _______, _______, _______, _______, _______, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, _______, _______, _______,
_______, RGB_TOG, RGB_HUI, RGB_HUD, RGB_SAI, RGB_SAD, RGB_VAI, RGB_VAD, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______
)
};
/**
* Terminal Prompt
* Mimicks a terminal prompt. On keystrokes, the led bar is filled. Backspace
* removes from bar. Enter clears bar. After some timeout, the bar is also cleared.
* A blinking cursor is displayed at the right of the bar.
* This can't be defined as an animation, because animations only are called on an
* interval, not on keypress. In the future all animations could be enhanced to
* react to keystrokes in QMK.
*/
uint8_t cursor_pos;
uint16_t interval_time = 10; // maybe too short...
uint16_t reset_time = 10000;
uint16_t last_timer = 0;
uint16_t timer_pos = 0;
uint16_t reset_timer = 0;
void reset_chars(void);
void add_char(bool space);
void remove_char(void);
void animate_cursor(uint16_t);
// animate, like the built-in animations, with timer_* functions
void matrix_scan_user(void) {
if (timer_elapsed(reset_timer) > reset_time) {
reset_chars();
reset_timer = timer_read();
return;
}
if (timer_elapsed(last_timer) < interval_time) {
return;
}
last_timer += interval_time;
timer_pos += 4;
if (timer_pos >= 255) {
timer_pos = 0;
last_timer = timer_read();
}
animate_cursor(timer_pos);
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) {
keycode = keycode & 0xFF;
}
switch (keycode) {
case KC_A ... KC_Z:
case KC_1 ... KC_0:
case KC_LBRC:
case KC_RBRC:
case KC_SCLN:
case KC_QUOT:
case KC_COMM:
case KC_DOT:
case KC_SLSH:
case KC_BSLS:
if (record->event.pressed) {
add_char(false);
}
break;
case KC_ENTER:
case KC_ESC:
if (record->event.pressed) {
reset_chars();
}
break;
case KC_BSPC:
if (record->event.pressed) {
remove_char();
}
break;
case KC_SPACE:
if (!record->event.pressed) {
add_char(true);
}
break;
}
reset_timer = timer_read();
return true;
}
void keyboard_post_init_user(void) {
// reset the bar and animation
rgblight_mode(RGBLIGHT_MODE_STATIC_LIGHT);
cursor_pos = 0;
reset_chars();
reset_timer = last_timer = timer_read();
}
void reset_chars(void) {
// flush the whole thing, gets rid of previous animations
for (uint8_t i = 0; i < RGBLED_NUM; i++) {
// don't flicker the cursor if bar was empty on reset_timer
if (i == 0 && cursor_pos == 0) {
continue;
}
rgblight_sethsv_at(0, 0, 0, i);
}
cursor_pos = 0;
}
void add_char(bool space) {
if (cursor_pos == RGBLED_NUM - 1) {
cursor_pos = 0;
reset_chars();
return;
}
if (space) {
rgblight_sethsv_at(0, 0, 0, cursor_pos);
} else {
rgblight_sethsv_at(rgblight_get_hue(), rgblight_get_sat(), rgblight_get_val(), cursor_pos);
}
cursor_pos += 1;
}
void remove_char(void) {
if (cursor_pos == 0) return;
rgblight_sethsv_at(0, 0, 0, cursor_pos);
rgblight_sethsv_at(0, 0, 0, cursor_pos - 1);
cursor_pos -= 1;
}
void animate_cursor(uint16_t pos) {
uint16_t value = pos < 196 ? fmin(255, pos * 16) : (255 - (pos * 2));
rgblight_sethsv_at(rgblight_get_hue(), rgblight_get_sat(), value, cursor_pos);
}

View File

@@ -0,0 +1 @@
# default Satan GH60 layout

View File

@@ -0,0 +1,7 @@
BOOTMAGIC_ENABLE = no
EXTRAKEY_ENABLE = no
CONSOLE_ENABLE = no
COMMAND_ENABLE = no
NKRO_ENABLE = no
UNICODE_ENABLE = yes
SLEEP_LED_ENABLE = yes

View File

@@ -289,7 +289,7 @@ void encoder_update(bool clockwise) {
}
}
void dip_update(uint8_t index, bool active) {
void dip_switch_update_user(uint8_t index, bool active) {
switch (index) {
case 0:
if (active) {

View File

@@ -37,15 +37,20 @@
* ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
*
*/
/* Note: These are not used for arm boards. They're here purely as documentation.
* #define MATRIX_ROW_PINS { PB0, PB1, PB2, PA15, PA10 }
* #define MATRIX_COL_PINS { PA2, PA3, PA6, PB14, PB15, PA8, PA9, PA7, PB3, PB4, PC14, PC15, PC13, PB5, PB6 }
* #define UNUSED_PINS
*/
/* Note: These are not used for arm boards. They're here purely as documentation. */
#undef MATRIX_ROW_PINS
#undef MATRIX_COL_PINS
#define MATRIX_ROW_PINS { A10, A9, A8, B15, C13, C14, C15, A2 }
#define MATRIX_COL_PINS { B11, B10, B2, B1, A7, B0 }
#define UNUSED_PINS
#define ENCODERS_PAD_A { B12 }
#define ENCODERS_PAD_B { B13 }
#define DIP_SWITCH_PINS { B14, A15, A0, B9 }
#define MUSIC_MAP
#undef AUDIO_VOICES
#undef C6_AUDIO

View File

@@ -1,176 +0,0 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "hal.h"
#include "timer.h"
#include "wait.h"
#include "printf.h"
#include "backlight.h"
#include "matrix.h"
#include "action.h"
#include "keycode.h"
#include <string.h>
/*
* col: { B11, B10, B2, B1, A7, B0 }
* row: { A10, A9, A8, B15, C13, C14, C15, A2 }
*/
/* matrix state(1:on, 0:off) */
static matrix_row_t matrix[MATRIX_ROWS];
static matrix_row_t matrix_debouncing[MATRIX_COLS];
static bool debouncing = false;
static uint16_t debouncing_time = 0;
static bool dip_switch[4] = {0, 0, 0, 0};
__attribute__ ((weak))
void matrix_init_user(void) {}
__attribute__ ((weak))
void matrix_scan_user(void) {}
__attribute__ ((weak))
void matrix_init_kb(void) {
matrix_init_user();
}
__attribute__ ((weak))
void matrix_scan_kb(void) {
matrix_scan_user();
}
void matrix_init(void) {
printf("matrix init\n");
//debug_matrix = true;
// dip switch setup
palSetPadMode(GPIOB, 14, PAL_MODE_INPUT_PULLUP);
palSetPadMode(GPIOA, 15, PAL_MODE_INPUT_PULLUP);
palSetPadMode(GPIOA, 10, PAL_MODE_INPUT_PULLUP);
palSetPadMode(GPIOB, 9, PAL_MODE_INPUT_PULLUP);
// actual matrix setup
palSetPadMode(GPIOB, 11, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOB, 10, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOB, 2, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOB, 1, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOA, 7, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOB, 0, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOA, 10, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOA, 9, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOA, 8, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOB, 15, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOC, 13, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOC, 14, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOC, 15, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOA, 2, PAL_MODE_INPUT_PULLDOWN);
memset(matrix, 0, MATRIX_ROWS * sizeof(matrix_row_t));
memset(matrix_debouncing, 0, MATRIX_COLS * sizeof(matrix_row_t));
matrix_init_quantum();
}
__attribute__ ((weak))
void dip_update(uint8_t index, bool active) { }
bool last_dip_switch[4] = {0};
uint8_t matrix_scan(void) {
// dip switch
dip_switch[0] = !palReadPad(GPIOB, 14);
dip_switch[1] = !palReadPad(GPIOA, 15);
dip_switch[2] = !palReadPad(GPIOA, 10);
dip_switch[3] = !palReadPad(GPIOB, 9);
for (uint8_t i = 0; i < 4; i++) {
if (last_dip_switch[i] ^ dip_switch[i])
dip_update(i, dip_switch[i]);
}
memcpy(last_dip_switch, dip_switch, sizeof(&dip_switch));
// actual matrix
for (int col = 0; col < MATRIX_COLS; col++) {
matrix_row_t data = 0;
// strobe col { B11, B10, B2, B1, A7, B0 }
switch (col) {
case 0: palSetPad(GPIOB, 11); break;
case 1: palSetPad(GPIOB, 10); break;
case 2: palSetPad(GPIOB, 2); break;
case 3: palSetPad(GPIOB, 1); break;
case 4: palSetPad(GPIOA, 7); break;
case 5: palSetPad(GPIOB, 0); break;
}
// need wait to settle pin state
wait_us(20);
// read row data { A10, A9, A8, B15, C13, C14, C15, A2 }
data = (
(palReadPad(GPIOA, 10) << 0 ) |
(palReadPad(GPIOA, 9) << 1 ) |
(palReadPad(GPIOA, 8) << 2 ) |
(palReadPad(GPIOB, 15) << 3 ) |
(palReadPad(GPIOC, 13) << 4 ) |
(palReadPad(GPIOC, 14) << 5 ) |
(palReadPad(GPIOC, 15) << 6 ) |
(palReadPad(GPIOA, 2) << 7 )
);
// unstrobe col { B11, B10, B2, B1, A7, B0 }
switch (col) {
case 0: palClearPad(GPIOB, 11); break;
case 1: palClearPad(GPIOB, 10); break;
case 2: palClearPad(GPIOB, 2); break;
case 3: palClearPad(GPIOB, 1); break;
case 4: palClearPad(GPIOA, 7); break;
case 5: palClearPad(GPIOB, 0); break;
}
if (matrix_debouncing[col] != data) {
matrix_debouncing[col] = data;
debouncing = true;
debouncing_time = timer_read();
}
}
if (debouncing && timer_elapsed(debouncing_time) > DEBOUNCE) {
for (int row = 0; row < MATRIX_ROWS; row++) {
matrix[row] = 0;
for (int col = 0; col < MATRIX_COLS; col++) {
matrix[row] |= ((matrix_debouncing[col] & (1 << row) ? 1 : 0) << col);
}
}
debouncing = false;
}
matrix_scan_quantum();
return 1;
}
bool matrix_is_on(uint8_t row, uint8_t col) {
return (matrix[row] & (1<<col));
}
matrix_row_t matrix_get_row(uint8_t row) {
return matrix[row];
}
void matrix_print(void) {
printf("\nr/c 01234567\n");
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
printf("%X0: ", row);
matrix_row_t data = matrix_get_row(row);
for (int col = 0; col < MATRIX_COLS; col++) {
if (data & (1<<col))
printf("1");
else
printf("0");
}
printf("\n");
}
}

View File

@@ -22,3 +22,13 @@ void matrix_init_kb(void) {
void matrix_scan_kb(void) {
matrix_scan_user();
}
#ifdef DIP_SWITCH_ENABLE
__attribute__((weak))
void dip_update(uint8_t index, bool active) {}
__attribute__((weak))
void dip_switch_update_user(uint8_t index, bool active) {
dip_update(index, active);
}
#endif

View File

@@ -1,5 +1,4 @@
# project specific files
SRC = matrix.c
LAYOUTS += ortho_4x12
# Cortex version
@@ -31,9 +30,9 @@ API_SYSEX_ENABLE = no
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
CUSTOM_MATRIX = yes # Custom matrix file
# SERIAL_LINK_ENABLE = yes
ENCODER_ENABLE = yes
DIP_SWITCH_ENABLE = yes
LAYOUTS = ortho_4x12 planck_mit
LAYOUTS_HAS_RGB = no

View File

@@ -259,7 +259,7 @@ void encoder_update_user(uint8_t index, bool clockwise) {
}
}
void dip_update(uint8_t index, bool active) {
void dip_switch_update_user(uint8_t index, bool active) {
switch (index) {
case 0:
if (active) {

View File

@@ -27,25 +27,17 @@
#define MATRIX_ROWS 10
#define MATRIX_COLS 6
/*
* 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)
*
*/
/* Note: These are not used for arm boards. They're here purely as documentation.
* #define MATRIX_ROW_PINS { PB0, PB1, PB2, PA15, PA10 }
* #define MATRIX_COL_PINS { PA2, PA3, PA6, PB14, PB15, PA8, PA9, PA7, PB3, PB4, PC14, PC15, PC13, PB5, PB6 }
* #define UNUSED_PINS
*/
#undef MATRIX_ROW_PINS
#undef MATRIX_COL_PINS
#define MATRIX_ROW_PINS { A10, A9, A8, B15, C13, C14, C15, A2, A3, A6 }
#define MATRIX_COL_PINS { B11, B10, B2, B1, A7, B0 }
#define UNUSED_PINS
#define ENCODERS_PAD_A { B12 }
#define ENCODERS_PAD_B { B13 }
#define DIP_SWITCH_PINS { B14, A15, A0, B9 }
#define MUSIC_MAP
#undef AUDIO_VOICES
#undef C6_AUDIO

View File

@@ -1,187 +0,0 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "hal.h"
#include "timer.h"
#include "wait.h"
#include "printf.h"
#include "backlight.h"
#include "matrix.h"
#include "action.h"
#include "keycode.h"
#include <string.h>
/*
* col: { B11, B10, B2, B1, A7, B0 }
* row: { A10, A9, A8, B15, C13, C14, C15, A2 }
*/
/* matrix state(1:on, 0:off) */
static matrix_row_t matrix[MATRIX_ROWS];
static matrix_col_t matrix_debouncing[MATRIX_COLS];
static bool debouncing = false;
static uint16_t debouncing_time = 0;
static bool dip_switch[4] = {0, 0, 0, 0};
__attribute__ ((weak))
void matrix_init_user(void) {}
__attribute__ ((weak))
void matrix_scan_user(void) {}
__attribute__ ((weak))
void matrix_init_kb(void) {
matrix_init_user();
}
__attribute__ ((weak))
void matrix_scan_kb(void) {
matrix_scan_user();
}
void matrix_init(void) {
printf("matrix init\n");
//debug_matrix = true;
// dip switch setup
palSetPadMode(GPIOB, 14, PAL_MODE_INPUT_PULLUP);
palSetPadMode(GPIOA, 15, PAL_MODE_INPUT_PULLUP);
palSetPadMode(GPIOA, 10, PAL_MODE_INPUT_PULLUP);
palSetPadMode(GPIOB, 9, PAL_MODE_INPUT_PULLUP);
// actual matrix setup
palSetPadMode(GPIOB, 11, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOB, 10, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOB, 2, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOB, 1, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOA, 7, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOB, 0, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOA, 10, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOA, 9, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOA, 8, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOB, 15, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOC, 13, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOC, 14, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOC, 15, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOA, 2, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOA, 3, PAL_MODE_INPUT_PULLDOWN);
palSetPadMode(GPIOA, 6, PAL_MODE_INPUT_PULLDOWN);
memset(matrix, 0, MATRIX_ROWS * sizeof(matrix_row_t));
memset(matrix_debouncing, 0, MATRIX_COLS * sizeof(matrix_col_t));
matrix_init_quantum();
}
__attribute__ ((weak))
void dip_update(uint8_t index, bool active) { }
__attribute__ ((weak))
void encoder_update(bool clockwise) { }
bool last_dip_switch[4] = {0};
#ifndef ENCODER_RESOLUTION
#define ENCODER_RESOLUTION 4
#endif
uint8_t matrix_scan(void) {
// dip switch
dip_switch[0] = !palReadPad(GPIOB, 14);
dip_switch[1] = !palReadPad(GPIOA, 15);
dip_switch[2] = !palReadPad(GPIOA, 10);
dip_switch[3] = !palReadPad(GPIOB, 9);
for (uint8_t i = 0; i < 4; i++) {
if (last_dip_switch[i] ^ dip_switch[i])
dip_update(i, dip_switch[i]);
}
memcpy(last_dip_switch, dip_switch, sizeof(&dip_switch));
// actual matrix
for (int col = 0; col < MATRIX_COLS; col++) {
matrix_col_t data = 0;
// strobe col { B11, B10, B2, B1, A7, B0 }
switch (col) {
case 0: palSetPad(GPIOB, 11); break;
case 1: palSetPad(GPIOB, 10); break;
case 2: palSetPad(GPIOB, 2); break;
case 3: palSetPad(GPIOB, 1); break;
case 4: palSetPad(GPIOA, 7); break;
case 5: palSetPad(GPIOB, 0); break;
}
// need wait to settle pin state
wait_us(20);
// read row data { A10, A9, A8, B15, C13, C14, C15, A2 }
data = (
(palReadPad(GPIOA, 10) << 0 ) |
(palReadPad(GPIOA, 9) << 1 ) |
(palReadPad(GPIOA, 8) << 2 ) |
(palReadPad(GPIOB, 15) << 3 ) |
(palReadPad(GPIOC, 13) << 4 ) |
(palReadPad(GPIOC, 14) << 5 ) |
(palReadPad(GPIOC, 15) << 6 ) |
(palReadPad(GPIOA, 2) << 7 ) |
(palReadPad(GPIOA, 3) << 8 ) |
(palReadPad(GPIOA, 6) << 9 )
);
// unstrobe col { B11, B10, B2, B1, A7, B0 }
switch (col) {
case 0: palClearPad(GPIOB, 11); break;
case 1: palClearPad(GPIOB, 10); break;
case 2: palClearPad(GPIOB, 2); break;
case 3: palClearPad(GPIOB, 1); break;
case 4: palClearPad(GPIOA, 7); break;
case 5: palClearPad(GPIOB, 0); break;
}
if (matrix_debouncing[col] != data) {
matrix_debouncing[col] = data;
debouncing = true;
debouncing_time = timer_read();
}
}
if (debouncing && timer_elapsed(debouncing_time) > DEBOUNCE) {
for (int row = 0; row < MATRIX_ROWS; row++) {
matrix[row] = 0;
for (int col = 0; col < MATRIX_COLS; col++) {
matrix[row] |= ((matrix_debouncing[col] & (1 << row) ? 1 : 0) << col);
}
}
debouncing = false;
}
matrix_scan_quantum();
return 1;
}
bool matrix_is_on(uint8_t row, uint8_t col) {
return (matrix[row] & (1<<col));
}
matrix_row_t matrix_get_row(uint8_t row) {
return matrix[row];
}
void matrix_print(void) {
printf("\nr/c 01234567\n");
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
printf("%X0: ", row);
matrix_row_t data = matrix_get_row(row);
for (int col = 0; col < MATRIX_COLS; col++) {
if (data & (1<<col))
printf("1");
else
printf("0");
}
printf("\n");
}
}

View File

@@ -22,3 +22,13 @@ void matrix_init_kb(void) {
void matrix_scan_kb(void) {
matrix_scan_user();
}
#ifdef DIP_SWITCH_ENABLE
__attribute__((weak))
void dip_update(uint8_t index, bool active) {}
__attribute__((weak))
void dip_switch_update_user(uint8_t index, bool active) {
dip_update(index, active);
}
#endif

View File

@@ -1,11 +1,8 @@
# project specific files
SRC = matrix.c
# Cortex version
MCU = STM32F303
# Build Options
# change to "no" to disable the options, or define them in the Makefile in
# change to "no" to disable the options, or define them in the Makefile in
# the appropriate keymap folder that will get included automatically
#
BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
@@ -27,8 +24,8 @@ API_SYSEX_ENABLE = no
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
#SLEEP_LED_ENABLE = yes
CUSTOM_MATRIX = yes # Custom matrix file
# SERIAL_LINK_ENABLE = yes
ENCODER_ENABLE = yes
DIP_SWITCH_ENABLE = yes
LAYOUTS = ortho_5x12

71
quantum/dip_switch.c Normal file
View File

@@ -0,0 +1,71 @@
/*
* Copyright 2018 Jack Humbert <jack.humb@gmail.com>
* Copyright 2019 Drashna Jaelre (Christopher Courtney) <drashna@live.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 "dip_switch.h"
// for memcpy
#include <string.h>
#if !defined(DIP_SWITCH_PINS)
# error "No DIP switch pads defined by DIP_SWITCH_PINS"
#endif
#define NUMBER_OF_DIP_SWITCHES (sizeof(dip_switch_pad)/sizeof(pin_t))
static pin_t dip_switch_pad[] = DIP_SWITCH_PINS;
static bool dip_switch_state[NUMBER_OF_DIP_SWITCHES] = { 0 };
static bool last_dip_switch_state[NUMBER_OF_DIP_SWITCHES] = { 0 };
__attribute__((weak))
void dip_switch_update_user(uint8_t index, bool active) {}
__attribute__((weak))
void dip_switch_update_kb(uint8_t index, bool active) { dip_switch_update_user(index, active); }
__attribute__((weak))
void dip_switch_update_mask_user(uint32_t state) {}
__attribute__((weak))
void dip_switch_update_mask_kb(uint32_t state) { dip_switch_update_mask_user(state); }
void dip_switch_init(void) {
for (uint8_t i = 0; i < NUMBER_OF_DIP_SWITCHES; i++) {
setPinInputHigh(dip_switch_pad[i]);
}
dip_switch_read(true);
}
void dip_switch_read(bool forced) {
bool has_dip_state_changed = false;
uint32_t dip_switch_mask = 0;
for (uint8_t i = 0; i < NUMBER_OF_DIP_SWITCHES; i++) {
dip_switch_state[i] = !readPin(dip_switch_pad[i]);
dip_switch_mask |= dip_switch_state[i] << i;
if (last_dip_switch_state[i] ^ dip_switch_state[i] || forced) {
has_dip_state_changed = true;
dip_switch_update_kb(i, dip_switch_state[i]);
}
}
if (has_dip_state_changed) {
dip_switch_update_mask_kb(dip_switch_mask);
}
memcpy(last_dip_switch_state, dip_switch_state, sizeof(&dip_switch_state));
}

29
quantum/dip_switch.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* Copyright 2018 Jack Humbert <jack.humb@gmail.com>
* Copyright 2018 Drashna Jaelre (Christopher Courtney) <drashna@live.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"
void dip_switch_update_kb(uint8_t index, bool active);
void dip_switch_update_user(uint8_t index, bool active);
void dip_switch_update_mask_user(uint32_t state);
void dip_switch_update_mask_kb(uint32_t state);
void dip_switch_init(void);
void dip_switch_read(bool forced);

View File

@@ -967,6 +967,10 @@ void matrix_init_quantum() {
#ifdef OUTPUT_AUTO_ENABLE
set_output(OUTPUT_AUTO);
#endif
#ifdef DIP_SWITCH_ENABLE
dip_switch_init();
#endif
matrix_init_kb();
}
@@ -1003,6 +1007,10 @@ void matrix_scan_quantum() {
haptic_task();
#endif
#ifdef DIP_SWITCH_ENABLE
dip_switch_read(false);
#endif
matrix_scan_kb();
}
#if defined(BACKLIGHT_ENABLE) && (defined(BACKLIGHT_PIN) || defined(BACKLIGHT_PINS))

View File

@@ -145,6 +145,11 @@ extern layer_state_t layer_state;
# include "oled_driver.h"
#endif
#ifdef DIP_SWITCH_ENABLE
#include "dip_switch.h"
#endif
// Function substitutions to ease GPIO manipulation
#if defined(__AVR__)
typedef uint8_t pin_t;

View File

@@ -31,7 +31,8 @@ HARDWARE_OPTION_NAMES = \
LED_BREATHING_TABLE \
LED_TABLES \
POINTING_DEVICE_ENABLE \
VISUALIZER_ENABLE
VISUALIZER_ENABLE \
DIP_SWITCH_ENABLE
OTHER_OPTION_NAMES = \
UNICODE_ENABLE \