diff --git a/keyboards/touchpad/config.h b/keyboards/touchpad/config.h new file mode 100644 index 0000000000..04453a3ab1 --- /dev/null +++ b/keyboards/touchpad/config.h @@ -0,0 +1,73 @@ +/* +Copyright 2018 Jack Humbert + +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 . +*/ + +#ifndef CONFIG_H +#define CONFIG_H + +#include "config_common.h" + +/* USB Device descriptor parameter */ +#define VENDOR_ID 0x16D0 +#define PRODUCT_ID 0x0DB8 +#define DEVICE_VER 0x0001 +#define MANUFACTURER JacoBurge +#define PRODUCT TouchPad +#define DESCRIPTION A capacitive touchpad + +/* key matrix size */ +#define MATRIX_ROWS 6 +#define MATRIX_COLS 6 + + +/* define if matrix has ghost */ +//#define MATRIX_HAS_GHOST + +/* number of backlight levels */ +#define BACKLIGHT_LEVELS 3 + +/* Set 0 if debouncing isn't needed */ +#define DEBOUNCING_DELAY 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 + +/* key combination for command */ +#define IS_COMMAND() ( \ + keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ +) + +/* + * 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 + +#endif diff --git a/keyboards/touchpad/keymaps/default/keymap.c b/keyboards/touchpad/keymaps/default/keymap.c new file mode 100644 index 0000000000..92f772aaa8 --- /dev/null +++ b/keyboards/touchpad/keymaps/default/keymap.c @@ -0,0 +1,30 @@ +/* Copyright 2018 Jack Humbert + * + * 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 . + */ + +#include QMK_KEYBOARD_H + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + +[0] = { + { KC_A, KC_B, KC_C, KC_D, KC_E, KC_F }, + { KC_A, KC_B, KC_C, KC_D, KC_E, KC_F }, + { KC_A, KC_B, KC_C, KC_D, KC_E, KC_F }, + { KC_A, KC_B, KC_C, KC_D, KC_E, KC_F }, + { KC_A, KC_B, KC_C, KC_D, KC_E, KC_F }, + { KC_A, KC_B, KC_C, KC_D, KC_E, KC_F } +} + +}; diff --git a/keyboards/touchpad/matrix.c b/keyboards/touchpad/matrix.c new file mode 100644 index 0000000000..a3ce63ee12 --- /dev/null +++ b/keyboards/touchpad/matrix.c @@ -0,0 +1,515 @@ +/* +MIT License +Copyright (c) 2018, JacoBurge +Adapted for QMK by Jack Humbert in 2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "matrix.h" +#include "i2c_master.h" +#include "quantum.h" + +#define VIBRATE_LENGTH 38 //Defines number of interrupts motor will vibrate for, must be bigger than 8 for correct operation +volatile uint8_t vibrate = 0; //Trigger vibration in interrupt + +static matrix_row_t matrix[MATRIX_ROWS]; + +const uint8_t SENr[6] = {1, 2, 3, 5, 6, 7};//Maps capacitive pads to pins +const uint8_t SENc[6] = {0, 4, 8, 9, 10, 11}; + +volatile uint8_t LEDs[6][6] = {{0}};//Stores current LED values +volatile uint8_t col = 0;//Keeps track of current multiplex column for LEDs + +//Setup interrupt to handle LEDs +void interruptSetup(void) { +// cli(); // disable global interrupts +// TCCR1A = 0; // set entire TCCR1A register to 0 +// TCCR1B = 0; // same for TCCR1B +// // set compare match register to desired timer count +// OCR1A = 10; +// // turn on CTC mode: +// TCCR1B |= (1 << WGM12); +// // Set CS10 and CS12 bits for 1024 prescaler +// TCCR1B |= (1 << CS10); +// TCCR1B |= (1 << CS12); +// // enable timer compare interrupt +// TIMSK1 |= (1 << OCIE1A); +// // enable global interrupts +// TCNT1 = 0; +// sei(); +} + +//Read data from the cap touch IC +uint8_t readDataFromTS(uint8_t reg) { + uint8_t tx[1] = { reg }; + i2c_transmit(0x1C, tx, 1, 100); + uint8_t rx[1]; + i2c_receive(0x1C, rx, 1, 100); + return rx[0]; +} + +//Write data to cap touch IC +uint8_t writeDataToTS(uint8_t reg, uint8_t data) { + uint8_t tx[2] = { reg, data }; + i2c_transmit(0x1C, tx, 2, 100); + return 1; +} + + +uint8_t checkTSPres(void) { + uint8_t temp_byte; + temp_byte = readDataFromTS(0x00); + if (temp_byte != 0x3E) + { + return 0; + } + else + { + return 1; + } +} + +uint8_t capSetup(void) { + + uint8_t temp_return = checkTSPres(); + + if (temp_return == 1) + { + // Perform measurements every 16ms + writeDataToTS(0x08, 1); + + // Increase detection integrator value + writeDataToTS(0x0B, 1); + + // Oversample to gain two bits for columns + writeDataToTS(0x28, 0x42); + writeDataToTS(0x29, 0x00); + writeDataToTS(0x2A, 0x00); + writeDataToTS(0x2B, 0x00); + writeDataToTS(0x2C, 0x42); + writeDataToTS(0x2D, 0x00); + writeDataToTS(0x2E, 0x00); + writeDataToTS(0x2F, 0x00); + writeDataToTS(0x30, 0x42); + writeDataToTS(0x31, 0x42); + writeDataToTS(0x32, 0x42); + writeDataToTS(0x33, 0x42); + + // Recalibration if touch detected for more than 8 seconds n*0.16s + writeDataToTS(0x0C, 50); + + // Enable keys and set key groups + writeDataToTS(0x1C, 0x00 | 0x04); + writeDataToTS(0x1D, 0x00 | 0x08); + writeDataToTS(0x1E, 0x00 | 0x08); + writeDataToTS(0x1F, 0x00 | 0x08); + writeDataToTS(0x20, 0x00 | 0x04); + writeDataToTS(0x21, 0x00 | 0x08); + writeDataToTS(0x22, 0x00 | 0x08); + writeDataToTS(0x23, 0x00 | 0x08); + writeDataToTS(0x24, 0x00 | 0x04); + writeDataToTS(0x25, 0x00 | 0x04); + writeDataToTS(0x26, 0x00 | 0x04); + writeDataToTS(0x27, 0x00 | 0x04); + + } + return temp_return; +} + +__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) { + + //pinMode(7, OUTPUT);//Motor enable E6 + setPinOutput(E6); + //pinMode(6, OUTPUT);//Motor PWM D7 + setPinOutput(D7); + + //pinMode(11, OUTPUT);//Power LED B7 + setPinOutput(B7); + writePinHigh(B7); + + //pinMode(A0, OUTPUT);//LEDs Columns F7 + setPinOutput(F7); + //pinMode(A1, OUTPUT); // F6 + setPinOutput(F6); + //pinMode(A2, OUTPUT); // F5 + setPinOutput(F5); + //pinMode(A3, OUTPUT); // F4 + setPinOutput(F4); + //pinMode(A4, OUTPUT); // F1 + setPinOutput(F1); + //pinMode(A5, OUTPUT); // F0 + setPinOutput(F0); + + //pinMode(12, OUTPUT);//LEDs Rows D6 + setPinOutput(D6); + //pinMode(8, OUTPUT); // B4 + setPinOutput(B4); + //pinMode(9, OUTPUT); // B5 + setPinOutput(B5); + //pinMode(10, OUTPUT); // B6 + setPinOutput(B6); + //pinMode(5, OUTPUT); // C6 + setPinOutput(C6); + //pinMode(13, OUTPUT); // C7 + setPinOutput(C7); + + //pinMode(0, INPUT);//Capacitive Interrupt D2 + setPinInput(D2); + + interruptSetup(); + + capSetup(); + writeDataToTS(0x06, 0x12);//Calibrate capacitive touch IC + + memset(matrix, 0, MATRIX_ROWS * sizeof(matrix_row_t)); + + matrix_init_quantum(); +} + + +uint16_t touchDetectionRoutine(void) { + uint16_t data; + uint8_t temp1, temp2; + + temp1 = readDataFromTS(0x04); + temp2 = readDataFromTS(0x03); + data = temp1; + data = (data << 8) | temp2; + return data; + +} + +//Process raw capacitive data, map pins to rows and columns +void decodeArray(uint16_t dataIn, uint8_t *column, uint8_t *row) { + uint8_t i1 = 20, i2 = 20; + for (uint8_t i = 0; i < 12; i++) { + if ((dataIn & 0b1) == 1) { + if (i1 == 20) { + i1 = i; + } else if (i2 == 20) { + i2 = i; + } + } + dataIn = dataIn >> 1; + } + + for (uint8_t j = 0; j < 6; j++) { + if (SENr[j] == i1 || SENr[j] == i2) { + *row = j; + } + if (SENc[j] == i1 || SENc[j] == i2) { + *column = j; + } + } +} + +void touchClearCurrentDetections(void) { + readDataFromTS(0x05); + readDataFromTS(0x02); + readDataFromTS(0x03); + readDataFromTS(0x04); +} + +//Check interrupt pin +uint8_t isTouchChangeDetected(void) { + return !readPin(D2); +} + +uint8_t matrix_scan(void) { + if (isTouchChangeDetected()) { + uint16_t dataIn = touchDetectionRoutine(); + if ((dataIn & 0b111100010001) > 0 && (dataIn & 0b000011101110) > 0) { + uint8_t column = 10, row = 10; + decodeArray(dataIn, &column, &row); + if (column != 10 && row != 10) { + vibrate = VIBRATE_LENGTH; //Trigger vibration + LEDs[column][row] = 1; + matrix[row] = _BV(column); + } else { + memset(matrix, 0, MATRIX_ROWS * sizeof(matrix_row_t)); + } + } + } + touchClearCurrentDetections(); + + + for (uint8_t c = 0; c < 6; c ++) { + switch (c) { + case 0: writePinLow(D6); break; + case 1: writePinLow(B4); break; + case 2: writePinLow(B5); break; + case 3: writePinLow(B6); break; + case 4: writePinLow(C6); break; + case 5: writePinLow(C7); break; + } + } + + switch (col) { + case 0: writePinHigh(F7); break; + case 1: writePinHigh(F5); break; + case 2: writePinHigh(F4); break; + case 3: writePinHigh(F1); break; + case 4: writePinHigh(F0); break; + case 5: writePinHigh(F6); break; + } + + switch (col) { + case 0: writePinLow(F7); break; + case 1: writePinLow(F5); break; + case 2: writePinLow(F4); break; + case 3: writePinLow(F1); break; + case 4: writePinLow(F0); break; + case 5: writePinLow(F6); break; + } + + for (uint8_t c = 0; c < 6; c ++) { + switch (c) { + case 0: writePin(D6, LEDs[col][c]); break; + case 1: writePin(B4, LEDs[col][c]); break; + case 2: writePin(B5, LEDs[col][c]); break; + case 3: writePin(B6, LEDs[col][c]); break; + case 4: writePin(C6, LEDs[col][c]); break; + case 5: writePin(C7, LEDs[col][c]); break; + } + } + + col++; + if (col > 5) { + col = 0; + } + + // if (vibrate == VIBRATE_LENGTH) { + // //digitalWrite(7, HIGH); + // writePinHigh(E6); + // // analogWrite(6, 255); + // writePinHigh(D7); + // vibrate--; + // } else if (vibrate == 8) { + // // analogWrite(6, 0); + // writePinLow(D7); + // vibrate--; + // } else if (vibrate == 1) { + // // analogWrite(6, 127); + // writePinHigh(D7); + // //digitalWrite(7, LOW); + // writePinLow(E6); + // vibrate--; + // } + // else if (vibrate > 0) { + // vibrate--; + // } + + + + + + matrix_scan_quantum(); + + return 1; + +} + +bool matrix_is_on(uint8_t row, uint8_t col) { + return (matrix[row] & (1< 0 && (dataIn & 0b000011101110) > 0) { + // uint8_t column, row; + // decodeArray(dataIn, &column, &row); + + // if (column != 10 && row != 10) { + // vibrate = VIBRATE_LENGTH;//Trigger vibration + + // LEDs[column][row] = 1; + // dataIn = touchDetectionRoutine(); + // // while + // while ((dataIn & _BV(SENr[row])) > 0 || (dataIn & _BV(SENc[column])) > 0) { + // dataIn = touchDetectionRoutine(); + // //Horizontal swipe detect + // if ((dataIn & _BV(SENr[row])) > 0 && (dataIn & _BV(SENc[column])) == 0 && (dataIn & 0b111100010001) > 0 && state == NORMAL) { + // uint8_t columnNew, rowNew; + // decodeArray(dataIn, &columnNew, &rowNew); + + // if (columnNew > column) { + // //===============================================================================================Swipe Right... + + + // //===============================================================================================...Swipe Right + // } else { + // //===============================================================================================Swipe Left... + + + // //===============================================================================================...Swipe Left + // } + + // while ((dataIn & _BV(SENr[row])) > 0 || (dataIn & _BV(SENc[column])) > 0) { + // dataIn = touchDetectionRoutine(); + // } + // break; + // } + // //Vertical swipe detect + // if ((dataIn & _BV(SENc[column])) > 0 && (dataIn & _BV(SENr[row])) == 0 && (dataIn & 0b000011101110) > 0) { + // uint8_t columnNew, rowNew; + // decodeArray(dataIn, &columnNew, &rowNew); + // if (rowNew > row) { + // //===============================================================================================Swipe Up... + + // //===============================================================================================...Swipe Up + // } + // else { + // //===============================================================================================Swipe Down... + + // //===============================================================================================...Swipe Down + + // } + + // while ((dataIn & _BV(SENr[row])) > 0 || (dataIn & _BV(SENc[column])) > 0) { + // dataIn = touchDetectionRoutine(); + // } + // break; + // } + // //===============================================================================================While Pressed... + + + // //===============================================================================================...While Pressed + // } + // touchClearCurrentDetections(); + + // //===============================================================================================When Released... + + // //===============================================================================================...When Released + // return 1; + // } + // } else { + // touchClearCurrentDetections(); + // } + // } + + // analogWrite(11, blinker);//Update LED B7 + +//LED driving interrupt +ISR(TIMER1_COMPA_vect) { + + for (uint8_t c = 0; c < 6; c ++) { + switch (c) { + case 0: writePinLow(D6); break; + case 1: writePinLow(B4); break; + case 2: writePinLow(B5); break; + case 3: writePinLow(B6); break; + case 4: writePinLow(C6); break; + case 5: writePinLow(C7); break; + } + } + + switch (col) { + case 0: writePinHigh(F7); break; + case 1: writePinHigh(F5); break; + case 2: writePinHigh(F4); break; + case 3: writePinHigh(F1); break; + case 4: writePinHigh(F0); break; + case 5: writePinHigh(F6); break; + } + + switch (col) { + case 0: writePinLow(F7); break; + case 1: writePinLow(F5); break; + case 2: writePinLow(F4); break; + case 3: writePinLow(F1); break; + case 4: writePinLow(F0); break; + case 5: writePinLow(F6); break; + } + + for (uint8_t c = 0; c < 6; c ++) { + switch (c) { + case 0: writePin(D6, LEDs[col][c]); break; + case 1: writePin(B4, LEDs[col][c]); break; + case 2: writePin(B5, LEDs[col][c]); break; + case 3: writePin(B6, LEDs[col][c]); break; + case 4: writePin(C6, LEDs[col][c]); break; + case 5: writePin(C7, LEDs[col][c]); break; + } + } + + col++; + if (col > 5) { + col = 0; + } + + if (vibrate == VIBRATE_LENGTH) { + //digitalWrite(7, HIGH); + writePinHigh(E6); + // analogWrite(6, 255); + writePinHigh(D7); + vibrate--; + } else if (vibrate == 8) { + // analogWrite(6, 0); + writePinLow(D7); + vibrate--; + } else if (vibrate == 1) { + // analogWrite(6, 127); + writePinHigh(D7); + //digitalWrite(7, LOW); + writePinLow(E6); + vibrate--; + } + else if (vibrate > 0) { + vibrate--; + } +} diff --git a/keyboards/touchpad/rules.mk b/keyboards/touchpad/rules.mk new file mode 100644 index 0000000000..e4fa2ac133 --- /dev/null +++ b/keyboards/touchpad/rules.mk @@ -0,0 +1,67 @@ +# MCU name +MCU = atmega32u4 + +SRC = matrix.c i2c_master.c + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Bootloader +# This definition is optional, and if your keyboard supports multiple bootloaders of +# different sizes, comment this out, and the correct address will be loaded +# automatically (+60). See bootloader.mk for all options. +BOOTLOADER = caterina + +# Interrupt driven control endpoint task(+60) +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + +# Build Options +# 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 = no # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = no # Mouse keys(+4700) +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = no # Commands for debug and configuration +NKRO_ENABLE = yes # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work +BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality +MIDI_ENABLE = no # MIDI controls +AUDIO_ENABLE = no # Audio output on port C6 +UNICODE_ENABLE = no # Unicode +BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID +RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight. +API_SYSEX_ENABLE = no +CUSTOM_MATRIX = yes + +# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE +SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend diff --git a/keyboards/touchpad/touchpad.c b/keyboards/touchpad/touchpad.c new file mode 100644 index 0000000000..fe96d56b68 --- /dev/null +++ b/keyboards/touchpad/touchpad.c @@ -0,0 +1 @@ +#include "touchpad.h" diff --git a/keyboards/touchpad/touchpad.h b/keyboards/touchpad/touchpad.h new file mode 100644 index 0000000000..010d4b1383 --- /dev/null +++ b/keyboards/touchpad/touchpad.h @@ -0,0 +1,2 @@ +#pragma once +#include "quantum.h"