Browse Source

Merge branch 'kimera'

master
Kai Ryu 7 years ago
parent
commit
48cc96168a

+ 165
- 0
keyboard/kimera/Makefile View File

@@ -0,0 +1,165 @@
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device.
# Please customize your programmer settings(PROGRAM_CMD)
#
# make teensy = Download the hex file to the device, using teensy_loader_cli.
# (must have teensy_loader_cli installed).
#
# make dfu = Download the hex file to the device, using dfu-programmer (must
# have dfu-programmer installed).
#
# make flip = Download the hex file to the device, using Atmel FLIP (must
# have Atmel FLIP installed).
#
# make dfu-ee = Download the eeprom file to the device, using dfu-programmer
# (must have dfu-programmer installed).
#
# make flip-ee = Download the eeprom file to the device, using Atmel FLIP
# (must have Atmel FLIP installed).
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------

# Target file name (without extension).
TARGET = kimera_lufa

# Directory common source filess exist
TMK_DIR = ../../tmk_core_custom

# Directory keyboard dependent files exist
TARGET_DIR = .

# project specific files
SRC = keymap_common.c \
matrix.c \
led.c \
backlight.c \
ledmap.c \
twimaster.c \
i2c_wrapper.c \
kimera.c \
light_ws2812.c \
rgb.c

ifdef KEYMAP
SRC := keymap_$(KEYMAP).c $(SRC)
else
SRC := keymap_default.c $(SRC)
endif


CONFIG_H = config.h


# MCU name
#MCU = at90usb1287
MCU = atmega32u4

# 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)

# Interrupt driven control endpoint task(+60)
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT


# Boot Section Size in *bytes*
# Teensy halfKay 512
# Teensy++ halfKay 1024
# Atmel DFU loader 4096
# LUFA bootloader 4096
# USBaspLoader 2048
OPT_DEFS += -DBOOTLOADER_SIZE=4096

# PCB Version
ifdef VER
OPT_DEFS += -DKIMERA_$(REV)
else
OPT_DEFS += -DKIMERA_CORE
endif

# Additional definitions from command line
ifdef DEFS
OPT_DEFS += $(foreach DEF,$(DEFS),-D$(DEF))
endif

# Build Options
# comment out to disable the options.
#
BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
#MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
CONSOLE_ENABLE = yes # Console for debug(+400)
COMMAND_ENABLE = yes # Commands for debug and configuration
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA
USB_6KRO_ENABLE = yes # USB 6key Rollover
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
#PS2_USE_BUSYWAIT = yes
BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality
KEYMAP_IN_EEPROM_ENABLE = yes # External keymap in eeprom
#KEYMAP_SECTION_ENABLE = yes # Fixed address keymap for keymap editor
SOFTPWM_LED_ENABLE = yes # Enable SoftPWM to drive backlight
FADING_LED_ENABLE = yes # Enable fading backlight
BREATHING_LED_ENABLE = yes # Enable breathing backlight
LEDMAP_ENABLE = yes # Enable LED mapping
LEDMAP_IN_EEPROM_ENABLE = yes # Read LED mapping from eeprom


# Optimize size but this may cause error "relocation truncated to fit"
#EXTRALDFLAGS = -Wl,--relax

# Search Path
VPATH += $(TARGET_DIR)
VPATH += $(TMK_DIR)

include $(TMK_DIR)/protocol/lufa.mk
include $(TMK_DIR)/common.mk
include $(TMK_DIR)/rules.mk

+ 122
- 0
keyboard/kimera/Makefile.pjrc View File

@@ -0,0 +1,122 @@
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device.
# Please customize your programmer settings(PROGRAM_CMD)
#
# make teensy = Download the hex file to the device, using teensy_loader_cli.
# (must have teensy_loader_cli installed).
#
# make dfu = Download the hex file to the device, using dfu-programmer (must
# have dfu-programmer installed).
#
# make flip = Download the hex file to the device, using Atmel FLIP (must
# have Atmel FLIP installed).
#
# make dfu-ee = Download the eeprom file to the device, using dfu-programmer
# (must have dfu-programmer installed).
#
# make flip-ee = Download the eeprom file to the device, using Atmel FLIP
# (must have Atmel FLIP installed).
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------

# Target file name (without extension).
TARGET = kimera_pjrc

# Directory common source filess exist
TOP_DIR = ../..

# Directory keyboard dependent files exist
TARGET_DIR = .

# project specific files
SRC = keymap_common.c \
matrix.c \
led.c \
backlight.c \
ledmap.c \
twimaster.c \
kimera.c

ifdef KEYMAP
SRC := keymap_$(KEYMAP).c $(SRC)
else
SRC := keymap_default.c $(SRC)
endif

CONFIG_H = config.h


# MCU name, you MUST set this to match the board you are using
# type "make clean" after changing this, so all files will be rebuilt
MCU = atmega32u4
#MCU = at90usb1286


# Processor frequency.
# Normally the first thing your program should do is set the clock prescaler,
# so your program will run at the correct speed. You should also set this
# variable to same clock speed. The _delay_ms() macro uses this, and many
# examples use this variable to calculate timings. Do not add a "UL" here.
F_CPU = 16000000


# Boot Section Size in *bytes*
# Teensy halfKay 512
# Atmel DFU loader 4096
# LUFA bootloader 4096
OPT_DEFS += -DBOOTLOADER_SIZE=4096

# Additional definitions from command line
ifdef DEFS
OPT_DEFS += $(foreach DEF,$(DEFS),-D$(DEF))
endif

# Build Options
# comment out to disable the options.
#
BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
CONSOLE_ENABLE = yes # Console for debug(+400)
COMMAND_ENABLE = yes # Commands for debug and configuration
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA
USB_6KRO_ENABLE = yes # USB 6key Rollover
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
#PS2_USE_BUSYWAIT = yes
BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality
KEYMAP_IN_EEPROM_ENABLE = yes # External keymap in eeprom
#KEYMAP_SECTION_ENABLE = yes # Fixed address keymap for keymap editor
SOFTPWM_LED_ENABLE = yes # Enable SoftPWM to drive backlight
#FADING_LED_ENABLE = yes # Enable fading backlight
BREATHING_LED_ENABLE = yes # Enable breathing backlight
LEDMAP_ENABLE = yes # Enable LED mapping
LEDMAP_IN_EEPROM_ENABLE = yes # Read LED mapping from eeprom


# Search Path
VPATH += $(TARGET_DIR)
VPATH += $(TOP_DIR)

include $(TOP_DIR)/protocol/pjrc.mk
include $(TOP_DIR)/common.mk
include $(TOP_DIR)/rules.mk

+ 156
- 0
keyboard/kimera/Makefile_8M View File

@@ -0,0 +1,156 @@
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device.
# Please customize your programmer settings(PROGRAM_CMD)
#
# make teensy = Download the hex file to the device, using teensy_loader_cli.
# (must have teensy_loader_cli installed).
#
# make dfu = Download the hex file to the device, using dfu-programmer (must
# have dfu-programmer installed).
#
# make flip = Download the hex file to the device, using Atmel FLIP (must
# have Atmel FLIP installed).
#
# make dfu-ee = Download the eeprom file to the device, using dfu-programmer
# (must have dfu-programmer installed).
#
# make flip-ee = Download the eeprom file to the device, using Atmel FLIP
# (must have Atmel FLIP installed).
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------

# Target file name (without extension).
TARGET = kimera_8m_lufa

# Directory common source filess exist
TOP_DIR = ../..

# Directory keyboard dependent files exist
TARGET_DIR = .

# project specific files
SRC = keymap_common.c \
matrix.c \
led.c \
backlight.c \
ledmap.c \
twimaster.c \
kimera.c

ifdef KEYMAP
SRC := keymap_$(KEYMAP).c $(SRC)
else
SRC := keymap_default.c $(SRC)
endif


CONFIG_H = config.h


# MCU name
#MCU = at90usb1287
MCU = atmega32u4

# 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
F_CPU = 8000000


#
# 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)

# Interrupt driven control endpoint task(+60)
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT


# Boot Section Size in *bytes*
# Teensy halfKay 512
# Teensy++ halfKay 1024
# Atmel DFU loader 4096
# LUFA bootloader 4096
# USBaspLoader 2048
OPT_DEFS += -DBOOTLOADER_SIZE=4096

# Additional definitions from command line
ifdef DEFS
OPT_DEFS += $(foreach DEF,$(DEFS),-D$(DEF))
endif

# Build Options
# comment out to disable the options.
#
BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
CONSOLE_ENABLE = yes # Console for debug(+400)
COMMAND_ENABLE = yes # Commands for debug and configuration
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA
USB_6KRO_ENABLE = yes # USB 6key Rollover
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
#PS2_USE_BUSYWAIT = yes
BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality
KEYMAP_IN_EEPROM_ENABLE = yes # External keymap in eeprom
#KEYMAP_SECTION_ENABLE = yes # Fixed address keymap for keymap editor
SOFTPWM_LED_ENABLE = yes # Enable SoftPWM to drive backlight
#FADING_LED_ENABLE = yes # Enable fading backlight
BREATHING_LED_ENABLE = yes # Enable breathing backlight
LEDMAP_ENABLE = yes # Enable LED mapping
LEDMAP_IN_EEPROM_ENABLE = yes # Read LED mapping from eeprom

# Optimize size but this may cause error "relocation truncated to fit"
#EXTRALDFLAGS = -Wl,--relax

# Search Path
VPATH += $(TARGET_DIR)
VPATH += $(TOP_DIR)

include $(TOP_DIR)/protocol/lufa.mk
include $(TOP_DIR)/protocol.mk
include $(TOP_DIR)/common.mk
include $(TOP_DIR)/rules.mk

+ 236
- 0
keyboard/kimera/backlight.c View File

@@ -0,0 +1,236 @@
/*
Copyright 2014 Kai Ryu <[email protected]>

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 <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "backlight.h"
#ifdef SOFTPWM_LED_ENABLE
#include "softpwm_led.h"
#else
#include "breathing_led.h"
#endif
#include "action.h"
#include "kimera.h"
#include "rgb.h"

#ifdef BACKLIGHT_ENABLE

void backlight_enable(void);
void backlight_disable(void);
inline void backlight_set_raw(uint8_t raw);

static const uint8_t backlight_table[] PROGMEM = {
0, 16, 128, 255
};

extern backlight_config_t backlight_config;
uint8_t backlight_brightness;

/* Backlight pin configuration
* LED4: PB6 (D10) OC1B
*/
#ifndef SOFTPWM_LED_ENABLE
void backlight_enable(void)
{
// Turn on PWM
LED4_DDR |= (1<<LED4_BIT);
cli();
TCCR1A |= ((1<<WGM10) | (1<<COM1B1));
TCCR1B |= ((1<<CS11) | (1<<CS10));
sei();
}
#endif

#ifndef SOFTPWM_LED_ENABLE
void backlight_disable(void)
{
// Turn off PWM
LED4_DDR &= ~(1<<LED4_BIT);
cli();
TCCR1A &= ~((1<<WGM10) | (1<<COM1B1));
TCCR1B &= ~((1<<CS11) | (1<<CS10));
sei();
LED4_OCR = 0;
}
#endif

void backlight_set(uint8_t level)
{
#ifdef SOFTPWM_LED_ENABLE
softpwm_enable();
#endif
#ifdef BREATHING_LED_ENABLE
switch (level) {
case 1:
case 2:
case 3:
#ifdef SOFTPWM_LED_ENABLE
softpwm_led_enable_all();
#ifdef FADING_LED_ENABLE
fading_led_disable_all();
#endif
breathing_led_disable_all();
#else
backlight_enable();
breathing_led_disable();
#endif
backlight_brightness = pgm_read_byte(&backlight_table[level]);
#ifdef RGB_LED_ENABLE
rgb_set_brightness(backlight_brightness);
#endif
backlight_set_raw(backlight_brightness);
break;
case 4:
case 5:
case 6:
#ifdef SOFTPWM_LED_ENABLE
softpwm_led_enable_all();
#ifdef FADING_LED_ENABLE
fading_led_disable_all();
#endif
breathing_led_enable_all();
#else
backlight_enable();
breathing_led_enable();
#endif
breathing_led_set_duration(6 - level);
break;
#ifdef SOFTPWM_LED_ENABLE
#ifdef FADING_LED_ENABLE
case 7:
softpwm_led_enable_all();
fading_led_enable_all();
breathing_led_disable_all();
fading_led_set_direction_all(FADING_LED_FADE_IN);
fading_led_set_duration(3);
break;
case 8:
softpwm_led_enable_all();
fading_led_enable_all();
breathing_led_disable_all();
fading_led_set_direction_all(FADING_LED_FADE_OUT);
fading_led_set_duration(3);
break;
#endif
#endif
case 0:
default:
#ifdef SOFTPWM_LED_ENABLE
#ifdef FADING_LED_ENABLE
fading_led_disable_all();
#endif
breathing_led_disable_all();
backlight_brightness = 0;
backlight_set_raw(backlight_brightness);
softpwm_led_disable_all();
#else
breathing_led_disable();
backlight_disable();
#endif
break;
}
#else
if (level > 0) {
backlight_enable();
backlight_set_raw(pgm_read_byte(&backlight_table[level]));
}
else {
backlight_disable();
}
#endif
}

#ifndef SOFTPWM_LED_ENABLE
#ifdef BREATHING_LED_ENABLE
void breathing_led_set_raw(uint8_t raw)
{
backlight_set_raw(raw);
}
#endif
#endif

inline void backlight_set_raw(uint8_t raw)
{
#ifdef SOFTPWM_LED_ENABLE
softpwm_led_set_all(raw);
#else
LED4_OCR = raw;
#endif
}

#ifndef LEDMAP_ENABLE
#ifdef SOFTPWM_LED_ENABLE
void softpwm_led_init(void)
{
LED4_DDR |= (1<<LED4_BIT);
}

void softpwm_led_on(uint8_t index)
{
LED4_PORT |= (1<<LED4_BIT);
}

void softpwm_led_off(uint8_t index)
{
LED4_PORT &= ~(1<<LED4_BIT);
}
#endif
#endif

#ifdef SOFTPWM_LED_ENABLE
#ifdef FADING_LED_ENABLE
void action_keyevent(keyevent_t event)
{
if (backlight_config.enable) {
if (backlight_config.level == 7) {
if (event.pressed) {
fading_led_set_delay_all(64);
softpwm_led_decrease_all(32);
}
}
if (backlight_config.level == 8) {
if (event.pressed) {
fading_led_set_delay_all(64);
softpwm_led_increase_all(32);
}
}
}
}
#endif

#ifdef RGB_LED_ENABLE
#ifdef CUSTOM_LED_ENABLE
void softpwm_led_custom(void)
{
rgb_fading();
}

void fading_led_custom(uint8_t *value)
{
rgb_set_brightness(value[0]);
}

void breathing_led_custom(uint8_t *value)
{
rgb_set_brightness(value[0]);
}
#endif
#endif
#endif

#endif

+ 96
- 0
keyboard/kimera/config.h View File

@@ -0,0 +1,96 @@
/*
Copyright 2014 Kai Ryu <[email protected]>

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

#ifndef CONFIG_H
#define CONFIG_H


/* USB Device descriptor parameter */
#define VENDOR_ID 0x16c0
#define PRODUCT_ID 0x27db
#define DEVICE_VER 0x0005
#define MANUFACTURER [email protected]
#define PRODUCT Kimera
#define DESCRIPTION t.m.k. keyboard firmware for Kimera

/* key matrix size */
#define MATRIX_ROWS 32
#define MATRIX_COLS 32

/* keymap in eeprom */
#define MATRIX_SIZE 16 * 16
#define FN_ACTIONS_COUNT 32
#define KEYMAPS_COUNT 3
#define EECONFIG_KEYMAP_IN_EEPROM 82

/* define if matrix has ghost */
//#define MATRIX_HAS_GHOST

/* Set 0 if debouncing isn't needed */
#define DEBOUNCE 5

/* number of backlight levels */
#ifdef BREATHING_LED_ENABLE
#ifdef FADING_LED_ENABLE
#define BACKLIGHT_LEVELS 8
#else
#define BACKLIGHT_LEVELS 6
#endif
#else
#define BACKLIGHT_LEVELS 3
#endif

/* enable customized backlight logic */
#define BACKLIGHT_CUSTOM
#define CUSTOM_LED_ENABLE
#define RGB_LED_ENABLE

/* number of leds */
#define LED_COUNT 4

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

#define NO_SUSPEND_POWER_DOWN

#endif

+ 95
- 0
keyboard/kimera/i2c_wrapper.c View File

@@ -0,0 +1,95 @@
/*
Copyright 2016 Kai Ryu <[email protected]>

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 <avr/interrupt.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include "i2cmaster.h"
#include "i2c_wrapper.h"
#include "debug.h"

#define wdt_intr_enable(value) \
__asm__ __volatile__ ( \
"in __tmp_reg__,__SREG__" "\n\t" \
"cli" "\n\t" \
"wdr" "\n\t" \
"sts %0,%1" "\n\t" \
"out __SREG__,__tmp_reg__" "\n\t" \
"sts %0,%2" "\n\t" \
: /* no outputs */ \
: "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
"r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
"r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \
_BV(WDIE) | (value & 0x07)) ) \
: "r0" \
)

#define SCL_CLOCK 400000L
#define SCL_DURATION (1000000L/SCL_CLOCK)/2

static uint8_t i2c_wdt_enabled = 0;

extern uint8_t i2c_force_stop;

static void wdt_init(void);

void i2c_wrapper_init(void)
{
/* init i2c */
i2c_init();

/* init watch dog */
wdt_init();
}

void i2c_wrapper_task(void)
{
/* reset watch dog counter */
wdt_reset();
}

void wdt_init(void)
{
cli();
wdt_reset();
wdt_intr_enable(WDTO_2S);
sei();
}

ISR(WDT_vect)
{
xprintf("i2c timeout\n");

/* let slave to release SDA */
TWCR = 0;
DDRD |= (1<<PD0);
DDRD &= ~(1<<PD1);
if (!(PIND & (1<<PD1))) {
for (uint8_t i = 0; i < 9; i++) {
PORTD &= ~(1<<PD0);
_delay_us(SCL_DURATION);
PORTD |= (1<<PD0);
_delay_us(SCL_DURATION);
}
}

/* send stop condition */
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

/* escape from loop */
i2c_force_stop = 1;
}

+ 25
- 0
keyboard/kimera/i2c_wrapper.h View File

@@ -0,0 +1,25 @@
/*
Copyright 2016 Kai Ryu <[email protected]>

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

#ifndef I2C_WRAPPER_H
#define I2C_WRAPPER_H

void i2c_wrapper_init(void);
void i2c_wrapper_task(void);

#endif


+ 178
- 0
keyboard/kimera/i2cmaster.h View File

@@ -0,0 +1,178 @@
#ifndef _I2CMASTER_H
#define _I2CMASTER_H 1
/*************************************************************************
* Title: C include file for the I2C master interface
* (i2cmaster.S or twimaster.c)
* Author: Peter Fleury <[email protected]> http://jump.to/fleury
* File: $Id: i2cmaster.h,v 1.10 2005/03/06 22:39:57 Peter Exp $
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
* Target: any AVR device
* Usage: see Doxygen manual
**************************************************************************/
#ifdef DOXYGEN
/**
@defgroup pfleury_ic2master I2C Master library
@code #include <i2cmaster.h> @endcode
@brief I2C (TWI) Master Software Library
Basic routines for communicating with I2C slave devices. This single master
implementation is limited to one bus master on the I2C bus.
This I2c library is implemented as a compact assembler software implementation of the I2C protocol
which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).
Since the API for these two implementations is exactly the same, an application can be linked either against the
software I2C implementation or the hardware I2C implementation.
Use 4.7k pull-up resistor on the SDA and SCL pin.
Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module
i2cmaster.S to your target when using the software I2C implementation !
Adjust the CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.
@note
The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted
to GNU assembler and AVR-GCC C call interface.
Replaced the incorrect quarter period delays found in AVR300 with
half period delays.
@author Peter Fleury [email protected] http://jump.to/fleury
@par API Usage Example
The following code shows typical usage of this library, see example test_i2cmaster.c
@code
#include <i2cmaster.h>
#define Dev24C02 0xA2 // device address of EEPROM 24C02, see datasheet
int main(void)
{
unsigned char ret;
i2c_init(); // initialize I2C library
// write 0x75 to EEPROM address 5 (Byte Write)
i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode
i2c_write(0x05); // write address = 5
i2c_write(0x75); // write value 0x75 to EEPROM
i2c_stop(); // set stop conditon = release bus
// read previously written value back from EEPROM address 5
i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode
i2c_write(0x05); // write address = 5
i2c_rep_start(Dev24C02+I2C_READ); // set device address and read mode
ret = i2c_readNak(); // read one byte from EEPROM
i2c_stop();
for(;;);
}
@endcode
*/
#endif /* DOXYGEN */
/**@{*/
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
#endif
#include <avr/io.h>
/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_READ 1
/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_WRITE 0
/**
@brief initialize the I2C master interace. Need to be called only once
@param void
@return none
*/
extern void i2c_init(void);
/**
@brief Terminates the data transfer and releases the I2C bus
@param void
@return none
*/
extern void i2c_stop(void);
/**
@brief Issues a start condition and sends address and transfer direction
@param addr address and transfer direction of I2C device
@retval 0 device accessible
@retval 1 failed to access device
*/
extern unsigned char i2c_start(unsigned char addr);
/**
@brief Issues a repeated start condition and sends address and transfer direction
@param addr address and transfer direction of I2C device
@retval 0 device accessible
@retval 1 failed to access device
*/
extern unsigned char i2c_rep_start(unsigned char addr);
/**
@brief Issues a start condition and sends address and transfer direction
If device is busy, use ack polling to wait until device ready
@param addr address and transfer direction of I2C device
@return none
*/
extern void i2c_start_wait(unsigned char addr);
/**
@brief Send one byte to I2C device
@param data byte to be transfered
@retval 0 write successful
@retval 1 write failed
*/
extern unsigned char i2c_write(unsigned char data);
/**
@brief read one byte from the I2C device, request more data from device
@return byte read from I2C device
*/
extern unsigned char i2c_readAck(void);
/**
@brief read one byte from the I2C device, read is followed by a stop condition
@return byte read from I2C device
*/
extern unsigned char i2c_readNak(void);
/**
@brief read one byte from the I2C device
Implemented as a macro, which calls either i2c_readAck or i2c_readNak
@param ack 1 send ack, request more data from device<br>
0 send nak, read is followed by a stop condition
@return byte read from I2C device
*/
extern unsigned char i2c_read(unsigned char ack);
#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();
/**@}*/
#endif

+ 50
- 0
keyboard/kimera/keymap_common.c View File

@@ -0,0 +1,50 @@
/*
Copyright 2014 Kai Ryu <[email protected]>

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 "keymap_common.h"
#include "matrix.h"

/* translates key to keycode */
uint8_t keymap_key_to_keycode(uint8_t layer, keypos_t key)
{
#ifndef KEYMAP_IN_EEPROM_ENABLE
return pgm_read_byte(&keymaps[(layer)][(key.row) * matrix_cols() + (key.col)]);
#else
return eeconfig_read_keymap_key(layer, key.row, key.col);
#endif
}

/* translates Fn keycode to action */
action_t keymap_fn_to_action(uint8_t keycode)
{
return (action_t) {
#ifndef KEYMAP_IN_EEPROM_ENABLE
.code = pgm_read_word(&fn_actions[FN_INDEX(keycode)])
#else
.code = eeconfig_read_keymap_fn_action(FN_INDEX(keycode))
#endif
};
}

#ifdef KEYMAP_IN_EEPROM_ENABLE
const uint8_t* keymaps_pointer(void) {
return (const uint8_t*)keymaps;
}

const uint16_t* fn_actions_pointer(void) {
return fn_actions;
}
#endif

+ 179
- 0
keyboard/kimera/keymap_common.h View File

@@ -0,0 +1,179 @@
/*
Copyright 2014 Kai Ryu <[email protected]>

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/>.
*/
#ifndef KEYMAP_COMMON_H
#define KEYMAP_COMMON_H

#include <stdint.h>
#include <stdbool.h>
#include <avr/pgmspace.h>
#include "keycode.h"
#include "action.h"
#include "action_macro.h"
#include "report.h"
#include "host.h"
#include "print.h"
#include "debug.h"
#include "keymap.h"
#include "keymap_in_eeprom.h"


extern const uint8_t keymaps[][MATRIX_SIZE];
extern const uint16_t fn_actions[];

/* 16 rows, 16 cols */
#define KEYMAP_16x16( \
KAA, KAB, KAC, KAD, KAE, KAF, KAG, KAH, KAJ, KAK, KAL, KAM, KAN, KAP, KAQ, KAR, \
KBA, KBB, KBC, KBD, KBE, KBF, KBG, KBH, KBJ, KBK, KBL, KBM, KBN, KBP, KBQ, KBR, \
KCA, KCB, KCC, KCD, KCE, KCF, KCG, KCH, KCJ, KCK, KCL, KCM, KCN, KCP, KCQ, KCR, \
KDA, KDB, KDC, KDD, KDE, KDF, KDG, KDH, KDJ, KDK, KDL, KDM, KDN, KDP, KDQ, KDR, \
KEA, KEB, KEC, KED, KEE, KEF, KEG, KEH, KEJ, KEK, KEL, KEM, KEN, KEP, KEQ, KER, \
KFA, KFB, KFC, KFD, KFE, KFF, KFG, KFH, KFJ, KFK, KFL, KFM, KFN, KFP, KFQ, KFR, \
KGA, KGB, KGC, KGD, KGE, KGF, KGG, KGH, KGJ, KGK, KGL, KGM, KGN, KGP, KGQ, KGR, \
KHA, KHB, KHC, KHD, KHE, KHF, KHG, KHH, KHJ, KHK, KHL, KHM, KHN, KHP, KHQ, KHR, \
KJA, KJB, KJC, KJD, KJE, KJF, KJG, KJH, KJJ, KJK, KJL, KJM, KJN, KJP, KJQ, KJR, \
KKA, KKB, KKC, KKD, KKE, KKF, KKG, KKH, KKJ, KKK, KKL, KKM, KKN, KKP, KKQ, KKR, \
KLA, KLB, KLC, KLD, KLE, KLF, KLG, KLH, KLJ, KLK, KLL, KLM, KLN, KLP, KLQ, KLR, \
KMA, KMB, KMC, KMD, KME, KMF, KMG, KMH, KMJ, KMK, KML, KMM, KMN, KMP, KMQ, KMR, \
KNA, KNB, KNC, KND, KNE, KNF, KNG, KNH, KNJ, KNK, KNL, KNM, KNN, KNP, KNQ, KNR, \
KPA, KPB, KPC, KPD, KPE, KPF, KPG, KPH, KPJ, KPK, KPL, KPM, KPN, KPP, KPQ, KPR, \
KQA, KQB, KQC, KQD, KQE, KQF, KQG, KQH, KQJ, KQK, KQL, KQM, KQN, KQP, KQQ, KQR, \
KRA, KRB, KRC, KRD, KRE, KRF, KRG, KRH, KRJ, KRK, KRL, KRM, KRN, KRP, KRQ, KRR \
) { \
KC_##KAA, KC_##KAB, KC_##KAC, KC_##KAD, KC_##KAE, KC_##KAF, KC_##KAG, KC_##KAH, KC_##KAJ, KC_##KAK, KC_##KAL, KC_##KAM, KC_##KAN, KC_##KAP, KC_##KAQ, KC_##KAR, \
KC_##KBA, KC_##KBB, KC_##KBC, KC_##KBD, KC_##KBE, KC_##KBF, KC_##KBG, KC_##KBH, KC_##KBJ, KC_##KBK, KC_##KBL, KC_##KBM, KC_##KBN, KC_##KBP, KC_##KBQ, KC_##KBR, \
KC_##KCA, KC_##KCB, KC_##KCC, KC_##KCD, KC_##KCE, KC_##KCF, KC_##KCG, KC_##KCH, KC_##KCJ, KC_##KCK, KC_##KCL, KC_##KCM, KC_##KCN, KC_##KCP, KC_##KCQ, KC_##KCR, \
KC_##KDA, KC_##KDB, KC_##KDC, KC_##KDD, KC_##KDE, KC_##KDF, KC_##KDG, KC_##KDH, KC_##KDJ, KC_##KDK, KC_##KDL, KC_##KDM, KC_##KDN, KC_##KDP, KC_##KDQ, KC_##KDR, \
KC_##KEA, KC_##KEB, KC_##KEC, KC_##KED, KC_##KEE, KC_##KEF, KC_##KEG, KC_##KEH, KC_##KEJ, KC_##KEK, KC_##KEL, KC_##KEM, KC_##KEN, KC_##KEP, KC_##KEQ, KC_##KER, \
KC_##KFA, KC_##KFB, KC_##KFC, KC_##KFD, KC_##KFE, KC_##KFF, KC_##KFG, KC_##KFH, KC_##KFJ, KC_##KFK, KC_##KFL, KC_##KFM, KC_##KFN, KC_##KFP, KC_##KFQ, KC_##KFR, \
KC_##KGA, KC_##KGB, KC_##KGC, KC_##KGD, KC_##KGE, KC_##KGF, KC_##KGG, KC_##KGH, KC_##KGJ, KC_##KGK, KC_##KGL, KC_##KGM, KC_##KGN, KC_##KGP, KC_##KGQ, KC_##KGR, \
KC_##KHA, KC_##KHB, KC_##KHC, KC_##KHD, KC_##KHE, KC_##KHF, KC_##KHG, KC_##KHH, KC_##KHJ, KC_##KHK, KC_##KHL, KC_##KHM, KC_##KHN, KC_##KHP, KC_##KHQ, KC_##KHR, \
KC_##KJA, KC_##KJB, KC_##KJC, KC_##KJD, KC_##KJE, KC_##KJF, KC_##KJG, KC_##KJH, KC_##KJJ, KC_##KJK, KC_##KJL, KC_##KJM, KC_##KJN, KC_##KJP, KC_##KJQ, KC_##KJR, \
KC_##KKA, KC_##KKB, KC_##KKC, KC_##KKD, KC_##KKE, KC_##KKF, KC_##KKG, KC_##KKH, KC_##KKJ, KC_##KKK, KC_##KKL, KC_##KKM, KC_##KKN, KC_##KKP, KC_##KKQ, KC_##KKR, \
KC_##KLA, KC_##KLB, KC_##KLC, KC_##KLD, KC_##KLE, KC_##KLF, KC_##KLG, KC_##KLH, KC_##KLJ, KC_##KLK, KC_##KLL, KC_##KLM, KC_##KLN, KC_##KLP, KC_##KLQ, KC_##KLR, \
KC_##KMA, KC_##KMB, KC_##KMC, KC_##KMD, KC_##KME, KC_##KMF, KC_##KMG, KC_##KMH, KC_##KMJ, KC_##KMK, KC_##KML, KC_##KMM, KC_##KMN, KC_##KMP, KC_##KMQ, KC_##KMR, \
KC_##KNA, KC_##KNB, KC_##KNC, KC_##KND, KC_##KNE, KC_##KNF, KC_##KNG, KC_##KNH, KC_##KNJ, KC_##KNK, KC_##KNL, KC_##KNM, KC_##KNN, KC_##KNP, KC_##KNQ, KC_##KNR, \
KC_##KPA, KC_##KPB, KC_##KPC, KC_##KPD, KC_##KPE, KC_##KPF, KC_##KPG, KC_##KPH, KC_##KPJ, KC_##KPK, KC_##KPL, KC_##KPM, KC_##KPN, KC_##KPP, KC_##KPQ, KC_##KPR, \
KC_##KQA, KC_##KQB, KC_##KQC, KC_##KQD, KC_##KQE, KC_##KQF, KC_##KQG, KC_##KQH, KC_##KQJ, KC_##KQK, KC_##KQL, KC_##KQM, KC_##KQN, KC_##KQP, KC_##KQQ, KC_##KQR, \
KC_##KRA, KC_##KRB, KC_##KRC, KC_##KRD, KC_##KRE, KC_##KRF, KC_##KRG, KC_##KRH, KC_##KRJ, KC_##KRK, KC_##KRL, KC_##KRM, KC_##KRN, KC_##KRP, KC_##KRQ, KC_##KRR \
}

/* 8 rows, 24 cols */
#define KEYMAP_8x24( \
KAA, KAB, KAC, KAD, KAE, KAF, KAG, KAH, KAJ, KAK, KAL, KAM, KAN, KAP, KAQ, KAR, KAS, KAT, KAU, KAV, KAW, KAX, KAY, KAZ, \
KBA, KBB, KBC, KBD, KBE, KBF, KBG, KBH, KBJ, KBK, KBL, KBM, KBN, KBP, KBQ, KBR, KBS, KBT, KBU, KBV, KBW, KBX, KBY, KBZ, \
KCA, KCB, KCC, KCD, KCE, KCF, KCG, KCH, KCJ, KCK, KCL, KCM, KCN, KCP, KCQ, KCR, KCS, KCT, KCU, KCV, KCW, KCX, KCY, KCZ, \
KDA, KDB, KDC, KDD, KDE, KDF, KDG, KDH, KDJ, KDK, KDL, KDM, KDN, KDP, KDQ, KDR, KDS, KDT, KDU, KDV, KDW, KDX, KDY, KDZ, \
KEA, KEB, KEC, KED, KEE, KEF, KEG, KEH, KEJ, KEK, KEL, KEM, KEN, KEP, KEQ, KER, KES, KET, KEU, KEV, KEW, KEX, KEY, KEZ, \
KFA, KFB, KFC, KFD, KFE, KFF, KFG, KFH, KFJ, KFK, KFL, KFM, KFN, KFP, KFQ, KFR, KFS, KFT, KFU, KFV, KFW, KFX, KFY, KFZ, \
KGA, KGB, KGC, KGD, KGE, KGF, KGG, KGH, KGJ, KGK, KGL, KGM, KGN, KGP, KGQ, KGR, KGS, KGT, KGU, KGV, KGW, KGX, KGY, KGZ, \
KHA, KHB, KHC, KHD, KHE, KHF, KHG, KHH, KHJ, KHK, KHL, KHM, KHN, KHP, KHQ, KHR, KHS, KHT, KHU, KHV, KHW, KHX, KHY, KHZ \
) KEYMAP_16x16( \
KAA, KAB, KAC, KAD, KAE, KAF, KAG, KAH, KAJ, KAK, KAL, KAM, KAN, KAP, KAQ, KAR, KAS, KAT, KAU, KAV, KAW, KAX, KAY, KAZ, \
KBA, KBB, KBC, KBD, KBE, KBF, KBG, KBH, KBJ, KBK, KBL, KBM, KBN, KBP, KBQ, KBR, KBS, KBT, KBU, KBV, KBW, KBX, KBY, KBZ, \
KCA, KCB, KCC, KCD, KCE, KCF, KCG, KCH, KCJ, KCK, KCL, KCM, KCN, KCP, KCQ, KCR, KCS, KCT, KCU, KCV, KCW, KCX, KCY, KCZ, \
KDA, KDB, KDC, KDD, KDE, KDF, KDG, KDH, KDJ, KDK, KDL, KDM, KDN, KDP, KDQ, KDR, KDS, KDT, KDU, KDV, KDW, KDX, KDY, KDZ, \
KEA, KEB, KEC, KED, KEE, KEF, KEG, KEH, KEJ, KEK, KEL, KEM, KEN, KEP, KEQ, KER, KES, KET, KEU, KEV, KEW, KEX, KEY, KEZ, \
KFA, KFB, KFC, KFD, KFE, KFF, KFG, KFH, KFJ, KFK, KFL, KFM, KFN, KFP, KFQ, KFR, KFS, KFT, KFU, KFV, KFW, KFX, KFY, KFZ, \
KGA, KGB, KGC, KGD, KGE, KGF, KGG, KGH, KGJ, KGK, KGL, KGM, KGN, KGP, KGQ, KGR, KGS, KGT, KGU, KGV, KGW, KGX, KGY, KGZ, \
KHA, KHB, KHC, KHD, KHE, KHF, KHG, KHH, KHJ, KHK, KHL, KHM, KHN, KHP, KHQ, KHR, KHS, KHT, KHU, KHV, KHW, KHX, KHY, KHZ, \
NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO \
)


/* 24 rows, 8 cols */
#define KEYMAP_24x8( \
KAA, KAB, KAC, KAD, KAE, KAF, KAG, KAH, \
KBA, KBB, KBC, KBD, KBE, KBF, KBG, KBH, \
KCA, KCB, KCC, KCD, KCE, KCF, KCG, KCH, \
KDA, KDB, KDC, KDD, KDE, KDF, KDG, KDH, \
KEA, KEB, KEC, KED, KEE, KEF, KEG, KEH, \
KFA, KFB, KFC, KFD, KFE, KFF, KFG, KFH, \
KGA, KGB, KGC, KGD, KGE, KGF, KGG, KGH, \
KHA, KHB, KHC, KHD, KHE, KHF, KHG, KHH, \
KJA, KJB, KJC, KJD, KJE, KJF, KJG, KJH, \
KKA, KKB, KKC, KKD, KKE, KKF, KKG, KKH, \
KLA, KLB, KLC, KLD, KLE, KLF, KLG, KLH, \
KMA, KMB, KMC, KMD, KME, KMF, KMG, KMH, \
KNA, KNB, KNC, KND, KNE, KNF, KNG, KNH, \
KPA, KPB, KPC, KPD, KPE, KPF, KPG, KPH, \
KQA, KQB, KQC, KQD, KQE, KQF, KQG, KQH, \
KRA, KRB, KRC, KRD, KRE, KRF, KRG, KRH, \
KSA, KSB, KSC, KSD, KSE, KSF, KSG, KSH, \
KTA, KTB, KTC, KTD, KTE, KTF, KTG, KTH, \
KUA, KUB, KUC, KUD, KUE, KUF, KUG, KUH, \
KVA, KVB, KVC, KVD, KVE, KVF, KVG, KVH, \
KWA, KWB, KWC, KWD, KWE, KWF, KWG, KWH, \
KXA, KXB, KXC, KXD, KXE, KXF, KXG, KXH, \
KYA, KYB, KYC, KYD, KYE, KYF, KYG, KYH, \
KZA, KZB, KZC, KZD, KZE, KZF, KZG, KZH \
) KEYMAP_16x16( \
KAA, KAB, KAC, KAD, KAE, KAF, KAG, KAH, \
KBA, KBB, KBC, KBD, KBE, KBF, KBG, KBH, \
KCA, KCB, KCC, KCD, KCE, KCF, KCG, KCH, \
KDA, KDB, KDC, KDD, KDE, KDF, KDG, KDH, \
KEA, KEB, KEC, KED, KEE, KEF, KEG, KEH, \
KFA, KFB, KFC, KFD, KFE, KFF, KFG, KFH, \
KGA, KGB, KGC, KGD, KGE, KGF, KGG, KGH, \
KHA, KHB, KHC, KHD, KHE, KHF, KHG, KHH, \
KJA, KJB, KJC, KJD, KJE, KJF, KJG, KJH, \
KKA, KKB, KKC, KKD, KKE, KKF, KKG, KKH, \
KLA, KLB, KLC, KLD, KLE, KLF, KLG, KLH, \
KMA, KMB, KMC, KMD, KME, KMF, KMG, KMH, \
KNA, KNB, KNC, KND, KNE, KNF, KNG, KNH, \
KPA, KPB, KPC, KPD, KPE, KPF, KPG, KPH, \
KQA, KQB, KQC, KQD, KQE, KQF, KQG, KQH, \
KRA, KRB, KRC, KRD, KRE, KRF, KRG, KRH, \
KSA, KSB, KSC, KSD, KSE, KSF, KSG, KSH, \
KTA, KTB, KTC, KTD, KTE, KTF, KTG, KTH, \
KUA, KUB, KUC, KUD, KUE, KUF, KUG, KUH, \
KVA, KVB, KVC, KVD, KVE, KVF, KVG, KVH, \
KWA, KWB, KWC, KWD, KWE, KWF, KWG, KWH, \
KXA, KXB, KXC, KXD, KXE, KXF, KXG, KXH, \
KYA, KYB, KYC, KYD, KYE, KYF, KYG, KYH, \
KZA, KZB, KZC, KZD, KZE, KZF, KZG, KZH, \
NO, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO \
)

/* ANSI 104 keymap */
#define KEYMAP_ANSI_104( \
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PRS, SCL, PAU, \
GRV, _1, _2, _3, _4, _5, _6, _7, _8, _9, _0, MNS, EQU, BSP, INS, HOM, PGU, NUM, PSL, PAS, PMN, \
TAB, Q, W, E, R, T, Y, U, I, O, P, LBR, RBR, BSL, DEL, END, PGD, P7, P8, P9, PPL, \
CAP, A, S, D, F, G, H, J, K, L, SCN, QUT, ENT, P4, P5, P6, \
LSF, Z, X, C, V, B, N, M, COM, DOT, SLS, RSF, UP, P1, P2, P3, PEN, \
LCT, LGU, LAL, SPC, RAL, RGU, APP, RCT, LFT, DOW, RGT, P0, PDT \
) KEYMAP_8x24( \
ESC, NO, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PRS, SCL, PAU, NO, NO, NO, NO, NO, NO, NO, \
GRV, _1, _2, _3, _4, _5, _6, _7, _8, _9, _0, MNS, EQU, BSP, INS, HOM, PGU, NUM, PSL, PAS, PMN, NO, NO, NO, \
TAB, Q, W, E, R, T, Y, U, I, O, P, LBR, RBR, BSL, DEL, END, PGD, P7, P8, P9, PPL, NO, NO, NO, \
CAP, A, S, D, F, G, H, J, K, L, SCN, QUT, NO, ENT, NO, NO, NO, P4, P5, P6, NO, NO, NO, NO, \
LSF, Z, X, C, V, B, N, M, COM, DOT, SLS, NO, NO, RSF, NO, UP, NO, P1, P2, P3, PEN, NO, NO, NO, \
LCT, LGU, LAL, NO, NO, NO, SPC, NO, NO, NO, RAL, RGU, APP, RCT, LFT, DOW, RGT, P0, NO, PDT, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO \
)

#endif

+ 81
- 0
keyboard/kimera/keymap_default.c View File

@@ -0,0 +1,81 @@
#include "keymap_common.h"
#include "rgb.h"

// Default
#ifdef KEYMAP_SECTION_ENABLE
const uint8_t keymaps[KEYMAPS_COUNT][MATRIX_SIZE] __attribute__ ((section (".keymap.keymaps"))) = {
#else
const uint8_t keymaps[][MATRIX_SIZE] PROGMEM = {
#endif
/* Keymap 0: Default Layer
* ,---------------------------------------------------------------------------------------.
* |Esc| | F1| F2| F3| F4| | F5| F6| F7| F8| | F9|F10|F11|F12|Psc|Slk|Pus| |
* |---------------------------------------------------------------------------------------|
* | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backsp |Ins|Hom|PgU|Num| /| *| -|
* |---------------------------------------------------------------------------------------|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \|Del|End|PgD| 7| 8| 9| |
* |-----------------------------------------------------------------------------------| +|
* |Caps | A| S| D| F| G| H| J| K| L| ;| '|Return | | 4| 5| 6| |
* |-----------------------------------------------------------| ,---. |---------------|
* |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift | |Up | | 1| 2| 3| |
* |-----------------------------------------------------------------------------------|Ent|
* |Ctrl|Gui |Alt | Space |Alt |Gui |Fn0 |Ctrl|Lef|Dow|Rig| 0| .| |
* `---------------------------------------------------------------------------------------'
*/
KEYMAP_ANSI_104(
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,PAUS, \
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, \
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, PPLS, \
CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, \
LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3, PENT, \
LCTL,LGUI,LALT, SPC, RALT,RGUI,FN0, RCTL, LEFT,DOWN,RGHT, P0, PDOT ),
};

/*
* Fn action definition
*/
#ifdef KEYMAP_SECTION_ENABLE
const uint16_t fn_actions[FN_ACTIONS_COUNT] __attribute__ ((section (".keymap.fn_actions"))) = {
#else
const uint16_t fn_actions[] PROGMEM = {
#endif
};

#ifdef KEYMAP_IN_EEPROM_ENABLE
uint16_t keys_count(void) {
return sizeof(keymaps) / sizeof(keymaps[0]) * MATRIX_SIZE;
}

uint16_t fn_actions_count(void) {
return sizeof(fn_actions) / sizeof(fn_actions[0]);
}
#endif

#ifndef NO_ACTION_FUNCTION
enum function_id {
AF_RGB_TOGGLE = 0,
AF_RGB_DECREASE,
AF_RGB_INCREASE,
AF_RGB_STEP
};

void action_function(keyrecord_t *record, uint8_t id, uint8_t opt)
{
if (record->event.pressed) {
switch (id) {
case AF_RGB_TOGGLE:
rgb_toggle();
break;
case AF_RGB_DECREASE:
rgb_decrease();
break;
case AF_RGB_INCREASE:
rgb_increase();
break;
case AF_RGB_STEP:
rgb_step();
break;
}
}
}
#endif

+ 62
- 0
keyboard/kimera/keymap_two_headed.c View File

@@ -0,0 +1,62 @@
#include "keymap_common.h"

// Two-headed
#ifdef KEYMAP_SECTION_ENABLE
const uint8_t keymaps[KEYMAPS_COUNT][MATRIX_SIZE] __attribute__ ((section (".keymap.keymaps"))) = {
#else
const uint8_t keymaps[][MATRIX_SIZE] PROGMEM = {
#endif
/* Keymap 0: Default Layer
* ,----------------------------------------. ,------------------------------------------------.
* | | | | ||Esc| | F1| F2| F3| F4| | | F5| F6| F7| F8| | F9|F10|F11|F12||Psc|Slk|Pus|
* |---------------||-----------------------| |-----------------------------------||-----------|
* |Num| /| *| -|| `| 1| 2| 3| 4| 5| | 6| 7| 8| 9| 0| -| =|Backsp ||Ins|Hom|PgU|
* |---------------||-------------------------. `-----------------------------------||-----------|
* | 7| 8| 9| ||Tab | Q| W| E| R| T| | Y| U| I| O| P| [| ]| \||Del|End|PgD|
* |-----------| +||--------------------------. `---------------------------------||-----------|
* | 4| 5| 6| ||Caps | A| S| D| F| G| | H| J| K| L| ;| '|Return || |
* |---------------||----------------------------. `-------------------------------|| ,---. |
* | 1| 2| 3| ||Shift | Z| X| C| V| B| | N| M| ,| .| /|Shift || |Up | |
* |-----------|Ent||----------------------------| |------------------------------||-----------|
* | 0| .| ||Ctrl|Gui |Alt | Space | | Space |Alt |Gui |App |Ctrl||Lef|Dow|Rig|
* `---------------------------------------------' `-------------------------------------------'
*/
KEYMAP_16x16(
NO, NO, NO, NO, ESC, NO, F1, F2, F3, F4, NO, NO, NO, NO, NO, NO, \
NLCK,PSLS,PAST,PMNS,GRV, 1, 2, 3, 4, 5, NO, NO, NO, NO, NO, NO, \
P7, P8, P9, PPLS,TAB, Q, W, E, R, T, NO, NO, NO, NO, NO, NO, \
P4, P5, P6, NO, CAPS,A, S, D, F, G, NO, NO, NO, NO, NO, NO, \
P1, P2, P3, PENT,LSFT,Z, X, C, V, B, NO, NO, NO, NO, NO, NO, \
P0, NO, PDOT,NO, LCTL,LGUI,LALT,NO, SPC, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, \

F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,PAUS,NO, NO, NO, NO, NO, \
6, 7, 8, 9, 0, MINS,EQL, BSPC,INS, HOME,PGUP,NO, NO, NO, NO, NO, \
Y, U, I, O, P, LBRC,RBRC,BSLS,DEL, END, PGDN,NO, NO, NO, NO, NO, \
H, J, K, L, SCLN,QUOT,NO, ENT, NO, NO, NO, NO, NO, NO, NO, NO, \
N, M, COMM,DOT, SLSH,NO, NO, RSFT,NO, UP, NO, NO, NO, NO, NO, NO, \
NO, SPC, NO, RALT,RGUI,APP, RCTL,NO, LEFT,DOWN,RGHT,NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, \
NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO ),
};

/*
* Fn action definition
*/
#ifdef KEYMAP_SECTION_ENABLE
const uint16_t fn_actions[FN_ACTIONS_COUNT] __attribute__ ((section (".keymap.fn_actions"))) = {
#else
const uint16_t fn_actions[] PROGMEM = {
#endif
};

#ifdef KEYMAP_IN_EEPROM_ENABLE
uint16_t keys_count(void) {
return sizeof(keymaps) / sizeof(keymaps[0]) * MATRIX_SIZE;
}

uint16_t fn_actions_count(void) {
return sizeof(fn_actions) / sizeof(fn_actions[0]);
}
#endif

+ 386
- 0
keyboard/kimera/kimera.c View File

@@ -0,0 +1,386 @@
/*
Copyright 2014 Kai Ryu <[email protected]>

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

#define KIMERA_C

#include <stdbool.h>
#include <avr/eeprom.h>
#include "action.h"
#include "i2cmaster.h"
#include "kimera.h"
#include "debug.h"

static uint8_t row_mapping[PX_COUNT] = {
0, 1, 2, 3, 4, 5, 6, 7,
32, 33, 34, 35, 36, 37, 38, 39,
UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED,
UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED
};
static uint8_t col_mapping[PX_COUNT] = {
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55
};
static uint8_t row_count = 16;
static uint8_t col_count = 32;
static uint8_t row_left_count = 8;
static uint8_t col_left_count = 16;
static matrix_row_t col_left_mask;
static uint8_t combining = COMBINING_NONE;
static uint8_t data[EXP_COUNT][EXP_PORT_COUNT];
static uint8_t exp_in_use = 0;
static uint8_t exp_online = 0;

static uint8_t read_matrix_mapping(void);
static void write_matrix_mapping(void);
static void expander_init(uint8_t exp);
static uint8_t expander_write(uint8_t exp, uint8_t command, uint8_t *data);
static uint8_t expander_read(uint8_t exp, uint8_t command, uint8_t *data);
static uint8_t expander_write_output(uint8_t exp, uint8_t *data);
static uint8_t expander_write_inversion(uint8_t exp, uint8_t *data);
static uint8_t expander_write_config(uint8_t exp, uint8_t *data);
static uint8_t expander_read_input(uint8_t exp, uint8_t *data);
static void init_data(uint8_t value);

void kimera_init(void)
{
/* read config */
//write_matrix_mapping(); /* debug */
if (read_matrix_mapping()) {
write_matrix_mapping();
}

/* init i/o expanders */
kimera_scan();
}

uint8_t read_matrix_mapping(void)
{
uint8_t error = 0;

/* read number of rows and cols */
uint8_t rows = eeprom_read_byte(EECONFIG_ROW_COUNT);
uint8_t cols = eeprom_read_byte(EECONFIG_COL_COUNT);
if (rows == 0) error++;
else if (rows == UNCONFIGURED) error++;
else if (rows & COMBINING_BIT) {
if (combining != COMBINING_NONE) error++;
combining = COMBINING_ROW;
rows -= COMBINING_BIT;
}
if (cols == 0) error++;
else if (cols == UNCONFIGURED) error++;
else if (cols & COMBINING_BIT) {
if (combining != COMBINING_NONE) error++;
combining = COMBINING_COL;
cols -= COMBINING_BIT;
}
if (rows + cols > PX_COUNT) error++;
if (error) return error;
row_count = rows;
col_count = cols;
if (combining != COMBINING_NONE) {
row_left_count = (rows + 1) / 2;
col_left_count = (cols + 1) / 2;
col_left_mask = (1 << col_left_count) - 1;
}

/* read row mapping */
uint8_t *mapping = EECONFIG_ROW_COL_MAPPING;
uint8_t exp;
for (uint8_t i = 0; i < PX_COUNT; i++) {
if (i < row_count) {
row_mapping[i] = eeprom_read_byte(mapping++);
if (row_mapping[i] >= PX_COUNT) {
error++;
}
else {
exp = PX_TO_EXP(row_mapping[i]);
exp_in_use |= (1<<exp);
}
}
else {
row_mapping[i] = UNCONFIGURED;
}
}
/* read col mapping*/
for (uint8_t i = 0; i < PX_COUNT; i++) {
if (i < col_count) {
col_mapping[i] = eeprom_read_byte(mapping++);
if (col_mapping[i] >= PX_COUNT) {
error++;
}
else {
exp = PX_TO_EXP(col_mapping[i]);
exp_in_use |= (1<<exp);
}
}
else {
col_mapping[i] = UNCONFIGURED;
}
}

return error;
}

void write_matrix_mapping(void)
{
/* write number of rows and cols */
eeprom_write_byte(EECONFIG_ROW_COUNT, row_count);
eeprom_write_byte(EECONFIG_COL_COUNT, col_count);

/* write row mapping */
uint8_t *mapping = EECONFIG_ROW_COL_MAPPING;
for (uint8_t row = 0; row < row_count; row++) {
eeprom_write_byte(mapping++, row_mapping[row]);
}
/* write col mapping */
for (uint8_t col = 0; col < col_count; col++) {
eeprom_write_byte(mapping++, col_mapping[col]);
}
}

void kimera_scan(void)
{
uint8_t ret;
dprintf("exp in use: %d\n", exp_in_use);
dprintf("exp online: %d\n", exp_online);
for (uint8_t exp = 0; exp < EXP_COUNT; exp++) {
if (exp_in_use & (1<<exp)) {
ret = i2c_start(EXP_ADDR(exp) | I2C_WRITE);
if (ret == 0) {
i2c_stop();
if ((exp_online & (1<<exp)) == 0) {
xprintf("found: %d\n", exp);
exp_online |= (1<<exp);
expander_init(exp);
clear_keyboard();
}
}
else {
if ((exp_online & (1<<exp)) != 0) {
xprintf("lost: %d\n", exp);
exp_online &= ~(1<<exp);
clear_keyboard();
}
}
}
}
}

inline
uint8_t kimera_matrix_rows(void)
{
if (combining == COMBINING_ROW) {
return row_left_count;
}
else {
return row_count;
}
}

inline
uint8_t kimera_matrix_cols(void)
{
if (combining == COMBINING_COL) {
return col_left_count;
}
else {
return col_count;
}
}

void kimera_read_cols(void)
{
/* read all input registers */
init_data(0xFF);
for (uint8_t exp = 0; exp < EXP_COUNT; exp++) {
expander_read_input(exp, data[exp]);
}
}

uint8_t kimera_get_col(uint8_t row, uint8_t col)
{
if (combining == COMBINING_ROW) {
if (row >= row_left_count) {
col += col_left_count;
}
}

uint8_t px = col_mapping[col];
if (px != UNCONFIGURED) {
if (!(data[PX_TO_EXP(px)][PX_TO_PORT(px)] & (1 << PX_TO_PIN(px)))) {
return 1;
}
}
return 0;
}

matrix_row_t kimera_read_row(uint8_t row)
{
kimera_read_cols();

/* make cols */
matrix_row_t cols = 0;
for (uint8_t col = 0; col < col_count; col++) {
uint8_t px = col_mapping[col];
if (px != UNCONFIGURED) {
if (!(data[PX_TO_EXP(px)][PX_TO_PORT(px)] & (1 << PX_TO_PIN(px)))) {
cols |= (1UL << col);
}
}
}

if (combining == COMBINING_COL) {
if (row < row_left_count) {
cols &= col_left_mask;
}
else {
cols >>= col_left_count;
}
}

return cols;
}

void kimera_unselect_rows(void)
{
/* set all output registers to 0xFF */
init_data(0xFF);
for (uint8_t exp = 0; exp < EXP_COUNT; exp++) {
expander_write_config(exp, data[exp]);
}
}

void kimera_select_row(uint8_t row)
{
/* set selected row to low */
init_data(0xFF);
uint8_t px = row_mapping[row];
if (px != UNCONFIGURED) {
uint8_t exp = PX_TO_EXP(px);
data[exp][PX_TO_PORT(px)] &= ~(1 << PX_TO_PIN(px));
expander_write_config(exp, data[exp]);
}

if (combining == COMBINING_ROW) {
if (row < row_left_count) {
kimera_select_row(row + row_left_count);
}
}
}

void expander_init(uint8_t exp)
{
init_data(0x00);

/* write inversion register */
/*
for (uint8_t exp = 0; exp < EXP_COUNT; exp++) {
expander_write_inversion(exp, data[exp]);
}
*/

/* set output bit */
/*
for (uint8_t row = 0; row < row_count; row++) {
uint8_t px = row_mapping[row];
if (px != UNCONFIGURED) {
data[PX_TO_EXP(px)][PX_TO_PORT(px)] &= ~(1 << PX_TO_PIN(px));
}
}
*/

/* write config registers */
//expander_write_config(exp, data[exp]);

/* write output registers */
expander_write_output(exp, data[exp]);
}

uint8_t expander_write(uint8_t exp, uint8_t command, uint8_t *data)
{
if ((exp_online & (1<<exp)) == 0) {
return 0;
}
uint8_t addr = EXP_ADDR(exp);
uint8_t ret;
ret = i2c_start(addr | I2C_WRITE);
if (ret) goto stop;
ret = i2c_write(command);
if (ret) goto stop;
ret = i2c_write(*data++);
if (ret) goto stop;
ret = i2c_write(*data);
stop:
i2c_stop();
return ret;
}

uint8_t expander_read(uint8_t exp, uint8_t command, uint8_t *data)
{
if ((exp_online & (1<<exp)) == 0) {
return 0;
}
uint8_t addr = EXP_ADDR(exp);
uint8_t ret;
ret = i2c_start(addr | I2C_WRITE);
if (ret) goto stop;
ret = i2c_write(command);
if (ret) goto stop;
ret = i2c_rep_start(addr | I2C_READ);
if (ret) goto stop;
*data++ = i2c_readAck();
*data = i2c_readNak();
stop:
i2c_stop();
return ret;
}

inline
uint8_t expander_write_output(uint8_t exp, uint8_t *data)
{
return expander_write(exp, EXP_COMM_OUTPUT_0, data);
}

inline
uint8_t expander_write_inversion(uint8_t exp, uint8_t *data)
{
return expander_write(exp, EXP_COMM_INVERSION_0, data);
}

inline
uint8_t expander_write_config(uint8_t exp, uint8_t *data)
{
return expander_write(exp, EXP_COMM_CONFIG_0, data);
}

inline
uint8_t expander_read_input(uint8_t exp, uint8_t *data)
{
return expander_read(exp, EXP_COMM_INPUT_0, data);
}

void init_data(uint8_t value)
{
for (uint8_t exp = 0; exp < EXP_COUNT; exp++) {
for (uint8_t port = 0; port < EXP_PORT_COUNT; port++) {
data[exp][port] = value;
}
}
}

+ 171
- 0
keyboard/kimera/kimera.h View File

@@ -0,0 +1,171 @@
/*
Copyright 2014 Kai Ryu <[email protected]>

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

#ifndef KIMERA_H
#define KIMERA_H

#include <stdint.h>
#include <avr/pgmspace.h>
#include "matrix.h"

/*
U1 (Pro Micro)
,----------------.
TX --| TX0(PD3) RAW |--
RX --| RX1(PD2) GND |--
--| GND RESET |-- RST
--| GND VCC |--
SDA --| 2(PD1) (PF4)A3 |--
SCL --| 3(PD0) (PF5)A2 |--
(INT) --| 4(PD4) (PF6)A1 |--
--| 5(PC6) (PF7)A0 |--
--| 6(PD7) (PB1)15 |-- SCK
LED2 --| 7(PE6) (PB3)14 |-- MISO
LED1 --| 8(PB4) (PB2)16 |-- MOSI
LED3 --| 9(PB5) (PB6)10 |-- LED4
`----------------'
*/

#ifndef KIMERA_CORE

#define LED1_PORT PORTB
#define LED1_PIN PINB
#define LED1_DDR DDRB
#define LED1_BIT PB4

#define LED2_PORT PORTE
#define LED2_PIN PINE
#define LED2_DDR DDRE
#define LED2_BIT PE6

#define LED3_PORT PORTB
#define LED3_PIN PINB
#define LED3_DDR DDRB
#define LED3_BIT PB5

#define LED4_PORT PORTB
#define LED4_PIN PINB
#define LED4_DDR DDRB
#define LED4_BIT PB6
#define LED4_OCR OCR1B

#else

#define LED1_PORT PORTB
#define LED1_PIN PINB
#define LED1_DDR DDRB
#define LED1_BIT PB5

#define LED2_PORT PORTB
#define LED2_PIN PINB
#define LED2_DDR DDRB
#define LED2_BIT PB6

#define LED3_PORT PORTC
#define LED3_PIN PINC
#define LED3_DDR DDRC
#define LED3_BIT PC6

#define LED4_PORT PORTC
#define LED4_PIN PINC
#define LED4_DDR DDRC
#define LED4_BIT PC7
#define LED4_OCR OCR4D

#endif

/*
IC1 (PCA9555) IC2 (PCA9555)
,----------. ,----------.
SDA --| SDA P00 |-- P1 SDA --| SDA P00 |-- P9
SCL --| SCL P01 |-- P2 SCL --| SCL P01 |-- P10
INT --| INT P02 |-- P3 INT --| INT P02 |-- P11
| P03 |-- P4 | P03 |-- P12
GND --| A0 P04 |-- P5 VCC --| A0 P04 |-- P13
SJ1 --| A1 P05 |-- P6 SJ1 --| A1 P05 |-- P14
SJ2 --| A2 P06 |-- P7 SJ2 --| A2 P06 |-- P15
| P07 |-- P8 | P07 |-- P16
| | | |
| P10 |-- P25 | P10 |-- P17
| P11 |-- P26 | P11 |-- P18
| P12 |-- P27 | P12 |-- P19
| P13 |-- P28 | P13 |-- P20
| P14 |-- P29 | P14 |-- P21
| P15 |-- P30 | P15 |-- P22
| P16 |-- P31 | P16 |-- P23
| P17 |-- P32 | P17 |-- P24
`----------' `----------'
*/

#define EXP_COUNT 4
#define EXP_ADDR(n) ((0x20+(n))<<1)
#define EXP_OUTPUT 0
#define EXP_INPUT 1
#define EXP_PORT_COUNT 2
#define EXP_PIN_PER_PORT 8
enum {
EXP_COMM_INPUT_0 = 0,
EXP_COMM_INPUT_1,
EXP_COMM_OUTPUT_0,
EXP_COMM_OUTPUT_1,
EXP_COMM_INVERSION_0,
EXP_COMM_INVERSION_1,
EXP_COMM_CONFIG_0,
EXP_COMM_CONFIG_1
};
#ifndef KIMERA_CORE
#define PX_TO_EXP(x) (((x)>>5<<1)+((((x)>>3)&1)^(((x)>>4)&1)))
#define PX_TO_PORT(x) (((x)>>4)&1)
#else
#define PX_TO_EXP(x) ((x)>>4)
#define PX_TO_PORT(x) (((x)>>3)&1)
#endif
#define PX_TO_PIN(x) ((x)&7)
#define PX_COUNT (EXP_PIN_PER_PORT * EXP_PORT_COUNT * EXP_COUNT)

#ifdef KIMERA_C
const uint16_t PROGMEM dummy[] = {
};
#endif

/* Matrix Mapping in EEPROM */

#define EECONFIG_ROW_COUNT (uint8_t *)16
#define EECONFIG_COL_COUNT (uint8_t *)17
#define EECONFIG_ROW_COL_MAPPING (uint8_t *)18
#define UNCONFIGURED 0xFF

enum {
COMBINING_NONE = 0,
COMBINING_COL,
COMBINING_ROW
};
#define COMBINING_BIT (0x80)

/* Functions */

void kimera_init(void);
void kimera_scan(void);
uint8_t kimera_matrix_rows(void);
uint8_t kimera_matrix_cols(void);
void kimera_read_cols(void);
uint8_t kimera_get_col(uint8_t row, uint8_t col);
matrix_row_t kimera_read_row(uint8_t row);
void kimera_unselect_rows(void);
void kimera_select_row(uint8_t row);

#endif

+ 56
- 0
keyboard/kimera/led.c View File

@@ -0,0 +1,56 @@
/*
Copyright 2014 Kai Ryu <[email protected]>

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 <avr/io.h>
#include "stdint.h"
#include "led.h"
#include "kimera.h"

#ifndef LEDMAP_ENABLE

void led_set(uint8_t usb_led)
{
if (usb_led & (1<<USB_LED_NUM_LOCK)) {
// output low
LED1_DDR |= (1<<LED1_BIT);
LED1_PORT &= ~(1<<LED1_BIT);
} else {
// Hi-Z
LED1_DDR &= ~(1<<LED1_BIT);
LED1_PORT &= ~(1<<LED1_BIT);
}
if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
// output low
LED2_DDR |= (1<<LED2_BIT);
LED2_PORT &= ~(1<<LED2_BIT);
} else {
// Hi-Z
LED2_DDR &= ~(1<<LED2_BIT);
LED2_PORT &= ~(1<<LED2_BIT);
}
if (usb_led & (1<<USB_LED_SCROLL_LOCK)) {
// output low
LED3_DDR |= (1<<LED3_BIT);
LED3_PORT &= ~(1<<LED3_BIT);
} else {
// Hi-Z
LED3_DDR &= ~(1<<LED3_BIT);
LED3_PORT &= ~(1<<LED3_BIT);
}
}

#endif

+ 88
- 0
keyboard/kimera/ledmap.c View File

@@ -0,0 +1,88 @@
/*
Copyright 2014 Kai Ryu <[email protected]>

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 <avr/pgmspace.h>
#include "ledmap.h"
#include "kimera.h"

#ifdef LEDMAP_ENABLE

static const uint16_t ledmaps[LED_COUNT] PROGMEM = {
[0] = LEDMAP_NUM_LOCK, // LED1
[1] = LEDMAP_CAPS_LOCK, // LED2
[2] = LEDMAP_SCROLL_LOCK, // LED3
[3] = LEDMAP_BACKLIGHT, // LED4
};

ledmap_t ledmap_get_code(uint8_t index)
{
return (ledmap_t) { .code = pgm_read_word(&ledmaps[index]) };
}

void ledmap_led_init(void)
{
LED1_DDR |= (1<<LED1_BIT);
LED1_PORT |= (1<<LED1_BIT);
LED2_DDR |= (1<<LED2_BIT);
LED2_PORT |= (1<<LED2_BIT);
LED3_DDR |= (1<<LED3_BIT);
LED3_PORT |= (1<<LED3_BIT);
LED4_DDR |= (1<<LED4_BIT);
LED4_PORT &= ~(1<<LED4_BIT);
}

void ledmap_led_on(uint8_t index)
{
switch (index) {
case 0:
LED1_PORT &= ~(1<<LED1_BIT);
break;
case 1:
LED2_PORT &= ~(1<<LED2_BIT);
break;
case 2:
#if 0
LED3_PORT &= ~(1<<LED3_BIT);
#endif
break;
case 3:
LED4_PORT |= (1<<LED4_BIT);
break;
}
}

void ledmap_led_off(uint8_t index)
{
switch (index) {
case 0:
LED1_PORT |= (1<<LED1_BIT);
break;
case 1:
LED2_PORT |= (1<<LED2_BIT);
break;
case 2:
#if 0
LED3_PORT |= (1<<LED3_BIT);
#endif
break;
case 3:
LED4_PORT &= ~(1<<LED4_BIT);
break;
}
}

#endif

+ 170
- 0
keyboard/kimera/light_ws2812.c View File

@@ -0,0 +1,170 @@
/*
* light weight WS2812 lib V2.0b
*
* Controls WS2811/WS2812/WS2812B RGB-LEDs
* Author: Tim ([email protected])
*
* Jan 18th, 2014 v2.0b Initial Version
*
* License: GNU GPL v2 (see License.txt)
*/

#include "light_ws2812.h"
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds)
{
ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));
}

void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask)
{
ws2812_DDRREG |= pinmask; // Enable DDR
ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask);
_delay_us(50);
}

void ws2812_sendarray(uint8_t *data,uint16_t datlen)
{
ws2812_sendarray_mask(data,datlen,_BV(ws2812_pin));
}

/*
This routine writes an array of bytes with RGB values to the Dataout pin
using the fast 800kHz clockless WS2811/2812 protocol.
*/

// Timing in ns
#define w_zeropulse 350
#define w_onepulse 900
#define w_totalperiod 1250

// Fixed cycles used by the inner loop
#define w_fixedlow 2
#define w_fixedhigh 4
#define w_fixedtotal 8

// Insert NOPs to match the timing, if possible
#define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000)
#define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000)
#define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000)

// w1 - nops between rising edge and falling edge - low
#define w1 (w_zerocycles-w_fixedlow)
// w2 nops between fe low and fe high
#define w2 (w_onecycles-w_fixedhigh-w1)
// w3 nops to complete loop
#define w3 (w_totalcycles-w_fixedtotal-w1-w2)

#if w1>0
#define w1_nops w1
#else
#define w1_nops 0
#endif

// The only critical timing parameter is the minimum pulse length of the "0"
// Warn or throw error if this timing can not be met with current F_CPU settings.
#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
#if w_lowtime>550
#error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
#elif w_lowtime>450
#warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
#warning "Please consider a higher clockspeed, if possible"
#endif

#if w2>0
#define w2_nops w2
#else
#define w2_nops 0
#endif

#if w3>0
#define w3_nops w3
#else
#define w3_nops 0
#endif

#define w_nop1 "nop \n\t"
#define w_nop2 "rjmp .+0 \n\t"
#define w_nop4 w_nop2 w_nop2
#define w_nop8 w_nop4 w_nop4
#define w_nop16 w_nop8 w_nop8

void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi)
{
uint8_t curbyte,ctr,masklo;
uint8_t sreg_prev;
masklo =~maskhi&ws2812_PORTREG;
maskhi |= ws2812_PORTREG;
sreg_prev=SREG;
cli();

while (datlen--) {
curbyte=*data++;
asm volatile(
" ldi %0,8 \n\t"
"loop%=: \n\t"
" out %2,%3 \n\t" // '1' [01] '0' [01] - re
#if (w1_nops&1)
w_nop1
#endif
#if (w1_nops&2)
w_nop2
#endif
#if (w1_nops&4)
w_nop4
#endif
#if (w1_nops&8)
w_nop8
#endif
#if (w1_nops&16)
w_nop16
#endif
" sbrs %1,7 \n\t" // '1' [03] '0' [02]
" out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low
" lsl %1 \n\t" // '1' [04] '0' [04]
#if (w2_nops&1)
w_nop1
#endif
#if (w2_nops&2)
w_nop2
#endif
#if (w2_nops&4)
w_nop4
#endif
#if (w2_nops&8)
w_nop8
#endif
#if (w2_nops&16)
w_nop16
#endif
" out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high
#if (w3_nops&1)
w_nop1
#endif
#if (w3_nops&2)
w_nop2
#endif
#if (w3_nops&4)
w_nop4
#endif
#if (w3_nops&8)
w_nop8
#endif
#if (w3_nops&16)
w_nop16
#endif

" dec %0 \n\t" // '1' [+2] '0' [+2]
" brne loop%=\n\t" // '1' [+3] '0' [+4]
: "=&d" (ctr)
: "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo)
);
}
SREG=sreg_prev;
}

+ 63
- 0
keyboard/kimera/light_ws2812.h View File

@@ -0,0 +1,63 @@
/*
* light weight WS2812 lib include
*
* Version 2.0a3 - Jan 18th 2014
* Author: Tim ([email protected])
*
* Please do not change this file! All configuration is handled in "ws2812_config.h"
*
* License: GNU GPL v2 (see License.txt)
+
*/

#ifndef LIGHT_WS2812_H_
#define LIGHT_WS2812_H_

#include <avr/io.h>
#include <avr/interrupt.h>
#include "ws2812_config.h"

/*
* Structure of the LED array
*/

struct cRGB { uint8_t g; uint8_t r; uint8_t b; };

/* User Interface
*
* Input:
* ledarray: An array of GRB data describing the LED colors
* number_of_leds: The number of LEDs to write
* pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0)
*
* The functions will perform the following actions:
* - Set the data-out pin as output
* - Send out the LED data
* - Wait 50µs to reset the LEDs
*/

void ws2812_setleds (struct cRGB *ledarray, uint16_t number_of_leds);
void ws2812_setleds_pin(struct cRGB *ledarray, uint16_t number_of_leds,uint8_t pinmask);

/*
* Old interface / Internal functions
*
* The functions take a byte-array and send to the data output as WS2812 bitstream.
* The length is the number of bytes to send - three per LED.
*/

void ws2812_sendarray (uint8_t *array,uint16_t length);
void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask);


/*
* Internal defines
*/

#define CONCAT(a, b) a ## b
#define CONCAT_EXP(a, b) CONCAT(a, b)

#define ws2812_PORTREG CONCAT_EXP(PORT,ws2812_port)
#define ws2812_DDRREG CONCAT_EXP(DDR,ws2812_port)

#endif /* LIGHT_WS2812_H_ */

+ 286
- 0
keyboard/kimera/matrix.c View File

@@ -0,0 +1,286 @@
/*
Copyright 2014 Kai Ryu <[email protected]>

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

/*
* scan matrix
*/
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <util/delay.h>
#include "print.h"
#include "debug.h"
#include "util.h"
#include "matrix.h"
#include "i2c_wrapper.h"
#include "kimera.h"
#include "keymap_in_eeprom.h"
#include "timer.h"


#ifndef DEBOUNCE
# define DEBOUNCE 5
#endif

/* matrix state(1:on, 0:off) */
static matrix_row_t matrix[MATRIX_ROWS];

#define IMPROVED_DEBOUNCE 1

#if IMPROVED_DEBOUNCE
#define DEBOUNCE_MASK ((1 << DEBOUNCE) - 1)
static uint8_t matrix_current_row;
static uint16_t matrix_row_timestamp[MATRIX_ROWS];
static uint8_t matrix_debouncing[MATRIX_ROWS][MATRIX_COLS];
#else
static uint8_t debouncing = DEBOUNCE;
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
#endif

static uint16_t kimera_scan_timestamp;

inline
uint8_t matrix_rows(void)
{
return kimera_matrix_rows();
}

inline
uint8_t matrix_cols(void)
{
return kimera_matrix_cols();
}

void matrix_init(void)
{
// disable JTAG
MCUCR = (1<<JTD);
MCUCR = (1<<JTD);

i2c_wrapper_init();
_delay_ms(1);

kimera_init();
kimera_scan_timestamp = timer_read();

// initialize row and col
kimera_unselect_rows();

// initialize matrix state: all keys off
#if IMPROVED_DEBOUNCE
for (uint8_t i = 0; i < matrix_rows(); i++) {
matrix[i] = 0;
matrix_current_row = 0;
matrix_row_timestamp[i] = timer_read();
for (uint8_t j = 0; j < matrix_cols(); j++) {
matrix_debouncing[i][j] = 0;
}
}
#else
for (uint8_t i=0; i < matrix_rows(); i++) {
matrix[i] = 0;
matrix_debouncing[i] = 0;
}
#endif

PORTD &= ~(1<<PD4);

}

uint8_t matrix_scan(void)
{
i2c_wrapper_task();

/* xprintf("Row: %d, %u\n", matrix_current_row, timer_read()); */

if (timer_elapsed(kimera_scan_timestamp) >= 1000) {
xprintf("Scan, %u\n", kimera_scan_timestamp);
kimera_scan_timestamp = timer_read();
kimera_scan();
}

#if IMPROVED_DEBOUNCE
uint16_t elapsed = timer_elapsed(matrix_row_timestamp[matrix_current_row]);
if (elapsed >= 1) {
matrix_row_timestamp[matrix_current_row] = timer_read();
kimera_select_row(matrix_current_row);
_delay_us(30);
kimera_read_cols();
for (uint8_t i = 0; i < matrix_cols(); i++) {
uint8_t *debounce = &matrix_debouncing[matrix_current_row][i];
uint8_t col = kimera_get_col(matrix_current_row, i);
uint8_t count = elapsed;
do {
*debounce <<= 1;
*debounce |= col;
} while (--count);
matrix_row_t *row = &matrix[matrix_current_row];
matrix_row_t mask = ((matrix_row_t)1 << i);
switch (*debounce & DEBOUNCE_MASK) {
case DEBOUNCE_MASK:
#if DEBOUNCE > 1
case (DEBOUNCE_MASK >> 1):
#if DEBOUNCE > 2
case (DEBOUNCE_MASK >> 2):
#if DEBOUNCE > 3
case (DEBOUNCE_MASK >> 3):
#if DEBOUNCE > 4
case (DEBOUNCE_MASK >> 4):
#if DEBOUNCE > 5
case (DEBOUNCE_MASK >> 5):
#if DEBOUNCE > 6
case (DEBOUNCE_MASK >> 6):
#if DEBOUNCE > 7
case (DEBOUNCE_MASK >> 7):
#if DEBOUNCE > 8
case (DEBOUNCE_MASK >> 8):
#if DEBOUNCE > 9
case (DEBOUNCE_MASK >> 9):
#if DEBOUNCE > 10
case (DEBOUNCE_MASK >> 10):
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
if ((*row & mask) == 0) {
*row |= mask;
}
break;
#if DEBOUNCE > 1
case ((DEBOUNCE_MASK << 1) & DEBOUNCE_MASK):
#if DEBOUNCE > 2
case ((DEBOUNCE_MASK << 2) & DEBOUNCE_MASK):
#if DEBOUNCE > 3
case ((DEBOUNCE_MASK << 3) & DEBOUNCE_MASK):
#if DEBOUNCE > 4
case ((DEBOUNCE_MASK << 4) & DEBOUNCE_MASK):
#if DEBOUNCE > 5
case ((DEBOUNCE_MASK << 5) & DEBOUNCE_MASK):
#if DEBOUNCE > 6
case ((DEBOUNCE_MASK << 6) & DEBOUNCE_MASK):
#if DEBOUNCE > 7
case ((DEBOUNCE_MASK << 7) & DEBOUNCE_MASK):
#if DEBOUNCE > 8
case ((DEBOUNCE_MASK << 8) & DEBOUNCE_MASK):
#if DEBOUNCE > 9
case ((DEBOUNCE_MASK << 9) & DEBOUNCE_MASK):
#if DEBOUNCE > 10
case ((DEBOUNCE_MASK << 10) & DEBOUNCE_MASK):
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
break;
case 0:
if ((*row & mask) != 0) {
*row &= ~mask;
}
break;
default:
debug("bounce!: ");
debug_bin8(*debounce & DEBOUNCE_MASK);
debug("\n");
break;
}
}
kimera_unselect_rows();
}

matrix_current_row++;
if (matrix_current_row >= matrix_rows()) {
matrix_current_row = 0;
}
#else
for (uint8_t i = 0; i < matrix_rows(); i++) {
kimera_select_row(i);
_delay_us(30); // without this wait read unstable value.
matrix_row_t cols = kimera_read_row(i);
if (matrix_debouncing[i] != cols) {
matrix_debouncing[i] = cols;
if (debouncing) {
debug("bounce!: "); debug_hex(debouncing); debug("\n");
}
debouncing = DEBOUNCE;
}
kimera_unselect_rows();
}

if (debouncing) {
if (--debouncing) {
_delay_ms(1);
} else {
for (uint8_t i = 0; i < matrix_rows(); i++) {
matrix[i] = matrix_debouncing[i];
}
}
}
#endif

return 1;
}

#if IMPROVED_DEBOUNCE
#else
bool matrix_is_modified(void)
{
if (debouncing) return false;
return true;
}
#endif

inline
bool matrix_is_on(uint8_t row, uint8_t col)
{
return (matrix[row] & ((matrix_row_t)1<<col));
}

inline
matrix_row_t matrix_get_row(uint8_t row)
{
return matrix[row];
}

void matrix_print(void)
{
print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n");
for (uint8_t row = 0; row < matrix_rows(); row++) {
phex(row); print(": ");
print_bin_reverse32(matrix_get_row(row));
print("\n");
}
}

uint8_t matrix_key_count(void)
{
uint8_t count = 0;
for (uint8_t i = 0; i < matrix_rows(); i++) {
count += bitpop32(matrix[i]);
}
return count;
}

+ 237
- 0
keyboard/kimera/rgb.c View File

@@ -0,0 +1,237 @@
/*
Copyright 2016 Kai Ryu <[email protected]>

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 <avr/pgmspace.h>
#include <avr/eeprom.h>
#include "softpwm_led.h"
#include "backlight.h"
#include "rgb.h"
#include "light_ws2812.h"
#include "debug.h"

#ifdef RGB_LED_ENABLE

volatile static uint8_t rgb_fading_enable = 0;
static rgb_config_t rgb_config;
static struct cRGB rgb_color[RGB_LED_COUNT];
static uint16_t rgb_hue = 0;
static uint8_t rgb_saturation = 255;
static uint8_t rgb_brightness = 16;
static uint8_t rgb_rainbow = 0;

extern backlight_config_t backlight_config;
extern uint8_t backlight_brightness;

static void rgb_write_config(void);
static void rgb_read_config(void);
static void rgb_set_level(uint8_t level);
static void rgb_refresh(void);
static void hue_to_rgb(uint16_t hue, struct cRGB *rgb);
static void hsb_to_rgb(uint16_t hue, uint8_t saturation, uint8_t brightness, struct cRGB *rgb);

void rgb_init(void)
{
rgb_read_config();
if (rgb_config.raw == RGB_UNCONFIGURED) {
rgb_config.enable = 0;
rgb_config.level = RGB_OFF;
rgb_write_config();
}
if (rgb_config.enable) {
rgb_set_level(rgb_config.level);
}
}

void rgb_read_config(void)
{
rgb_config.raw = eeprom_read_byte(EECONFIG_RGB);
}

void rgb_write_config(void)
{
eeprom_write_byte(EECONFIG_RGB, rgb_config.raw);
}

void rgb_toggle(void)
{
if (rgb_config.enable) {
rgb_off();
}
else {
rgb_on();
}
}

void rgb_on(void)
{
rgb_config.enable = 1;
rgb_set_level(rgb_config.level);
rgb_write_config();
}

void rgb_off(void)
{
rgb_config.enable = 0;
rgb_set_level(RGB_OFF);
rgb_write_config();
}

void rgb_decrease(void)
{
if(rgb_config.level > 0) {
rgb_config.level--;
rgb_config.enable = (rgb_config.level != 0);
rgb_write_config();
}
rgb_set_level(rgb_config.level);
}

void rgb_increase(void)
{
if(rgb_config.level < RGB_LEVELS) {
rgb_config.level++;
rgb_config.enable = 1;
rgb_write_config();
}
rgb_set_level(rgb_config.level);
}

void rgb_step(void)
{
rgb_config.level++;
if(rgb_config.level > RGB_LEVELS)
{
rgb_config.level = 0;
}
rgb_config.enable = (rgb_config.level != 0);
rgb_set_level(rgb_config.level);
}

void rgb_set_level(uint8_t level)
{
dprintf("RGB Level: %d\n", level);
if (level <= RGB_WHITE) {
rgb_fading_enable = 0;
rgb_rainbow = 0;
if (level == RGB_OFF) {
rgb_brightness = 0;
}
else {
if (level == RGB_WHITE) {
rgb_saturation = 0;
}
else {
rgb_hue = (level - 1) * 128;
rgb_saturation = 255;
}
if (backlight_config.enable) {
if (backlight_config.level >= 1 && backlight_config.level <= 3) {
rgb_brightness = backlight_brightness;
}
}
else {
rgb_brightness = 16;
}
}
rgb_refresh();
}
else {
rgb_saturation = 255;
rgb_fading_enable = 1;
rgb_rainbow = (level >= RGB_RAINBOW) ? 1 : 0;
}
}

void rgb_set_brightness(uint8_t brightness)
{
if (rgb_config.enable) {
rgb_brightness = brightness;
rgb_refresh();
}
}

void rgb_refresh(void)
{
struct cRGB rgb;
uint16_t hue;
uint8_t i;
if (rgb_rainbow) {
for (i = 0; i < RGB_LED_COUNT; i++) {
hue = rgb_hue + (768 / RGB_LED_COUNT) * i;
hsb_to_rgb(hue, rgb_saturation, rgb_brightness, &rgb);
rgb_color[i] = rgb;
}
}
else {
hsb_to_rgb(rgb_hue, rgb_saturation, rgb_brightness, &rgb);
for (i = 0; i < RGB_LED_COUNT; i++) {
rgb_color[i] = rgb;
}
}
/* xprintf("R%d G%d B%d\n", rgb_color[0].r, rgb_color[0].g, rgb_color[0].b); */
ws2812_setleds(rgb_color, RGB_LED_COUNT);
}

void hue_to_rgb(uint16_t hue, struct cRGB *rgb)
{
uint8_t hi = hue / 60;
uint16_t f = (hue % 60) * 425 / 100;
uint8_t q = 255 - f;
switch (hi) {
case 0: rgb->r = 255; rgb->g = f; rgb->b = 0; break;
case 1: rgb->r = q; rgb->g = 255; rgb->b = 0; break;
case 2: rgb->r = 0; rgb->g = 255; rgb->b = f; break;
case 3: rgb->r = 0; rgb->g = q; rgb->b = 255; break;
case 4: rgb->r = f; rgb->g = 0; rgb->b = 255; break;
case 5: rgb->r = 255; rgb->g = 0; rgb->b = q; break;
}
}

/*
* original code: https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/
*/
void hsb_to_rgb(uint16_t hue, uint8_t saturation, uint8_t brightness, struct cRGB *rgb)
{
uint8_t temp[5];
uint8_t n = (hue >> 8) % 3;
uint8_t x = ((((hue & 255) * saturation) >> 8) * brightness) >> 8;
uint8_t s = ((256 - saturation) * brightness) >> 8;
temp[0] = temp[3] = s;
temp[1] = temp[4] = x + s;
temp[2] = brightness - x;
rgb->r = temp[n + 2];
rgb->g = temp[n + 1];
rgb->b = temp[n];
}

void rgb_fading(void)
{
static uint8_t step = 0;
static uint16_t hue = 0;
if (rgb_fading_enable) {
if (++step > rgb_fading_enable) {
step = 0;
rgb_hue = hue;
rgb_refresh();
if (++hue >= 768) {
hue = 0;
}
}
}
}

#endif

+ 60
- 0
keyboard/kimera/rgb.h View File

@@ -0,0 +1,60 @@
/*
Copyright 2016 Kai Ryu <[email protected]>

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

#ifndef RGB_H
#define RGB_H

#include <stdint.h>
#include <stdbool.h>

typedef union {
uint8_t raw;
struct {
uint8_t level :7;
bool enable :1;
};
} rgb_config_t;

enum {
RGB_OFF = 0,
RGB_RED,
RGB_YELLOW,
RGB_GREEN,
RGB_CYAN,
RGB_BLUE,
RGB_MAGENTA,
RGB_WHITE,
RGB_FADE,
RGB_RAINBOW,
RGB_LEVELS = RGB_RAINBOW
};

#define EECONFIG_RGB (uint8_t *)15
#define RGB_UNCONFIGURED 0xFF
#define RGB_LED_COUNT 16

void rgb_init(void);
void rgb_toggle(void);
void rgb_on(void);
void rgb_off(void);
void rgb_decrease(void);
void rgb_increase(void);
void rgb_step(void);
void rgb_set_brightness(uint8_t brightness);
void rgb_fading(void);

#endif

+ 205
- 0
keyboard/kimera/twimaster.c View File

@@ -0,0 +1,205 @@
/*************************************************************************
* Title: I2C master library using hardware TWI interface
* Author: Peter Fleury <[email protected]> http://jump.to/fleury
* File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
* Target: any AVR device with hardware TWI
* Usage: API compatible with I2C Software Library i2cmaster.h
**************************************************************************/
#include <inttypes.h>
#include <compat/twi.h>
#include <i2cmaster.h>
#include "debug.h"
/* define CPU frequency in Mhz here if not defined in Makefile */
#ifndef F_CPU
#define F_CPU 4000000UL
#endif
/* I2C clock in Hz */
#define SCL_CLOCK 400000L
volatile uint8_t i2c_force_stop = 0;
#define CHECK_FORCE_STOP() if(i2c_force_stop){i2c_force_stop=0;break;}
/*************************************************************************
Initialization of the I2C bus interface. Need to be called only once
*************************************************************************/
void i2c_init(void)
{
/* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
TWSR = 0; /* no prescaler */
TWBR = ((F_CPU/SCL_CLOCK)-16)/2; /* must be > 10 for stable operation */
}/* i2c_init */
/*************************************************************************
Issues a start condition and sends address and transfer direction.
return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char i2c_start(unsigned char address)
{
uint8_t twst;
// send START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
// wait until transmission completed
while(!(TWCR & (1<<TWINT))) { CHECK_FORCE_STOP(); };
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
// send device address
TWDR = address;
TWCR = (1<<TWINT) | (1<<TWEN);
// wail until transmission completed and ACK/NACK has been received
while(!(TWCR & (1<<TWINT))) { CHECK_FORCE_STOP(); };
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
return 0;
}/* i2c_start */
/*************************************************************************
Issues a start condition and sends address and transfer direction.
If device is busy, use ack polling to wait until device is ready
Input: address and transfer direction of I2C device
*************************************************************************/
void i2c_start_wait(unsigned char address)
{
uint8_t twst;
while ( 1 )
{
// send START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
// wait until transmission completed
while(!(TWCR & (1<<TWINT)));
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
// send device address
TWDR = address;
TWCR = (1<<TWINT) | (1<<TWEN);
// wail until transmission completed
while(!(TWCR & (1<<TWINT)));
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) )
{
/* device busy, send stop condition to terminate write operation */
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
// wait until stop condition is executed and bus released
while(TWCR & (1<<TWSTO)) { CHECK_FORCE_STOP(); };
continue;
}
//if( twst != TW_MT_SLA_ACK) return 1;
break;
}
}/* i2c_start_wait */
/*************************************************************************
Issues a repeated start condition and sends address and transfer direction
Input: address and transfer direction of I2C device
Return: 0 device accessible
1 failed to access device
*************************************************************************/
unsigned char i2c_rep_start(unsigned char address)
{
return i2c_start( address );
}/* i2c_rep_start */
/*************************************************************************
Terminates the data transfer and releases the I2C bus
*************************************************************************/
void i2c_stop(void)
{
/* send stop condition */
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
// wait until stop condition is executed and bus released
while(TWCR & (1<<TWSTO)) { CHECK_FORCE_STOP(); };
}/* i2c_stop */
/*************************************************************************
Send one byte to I2C device
Input: byte to be transfered
Return: 0 write successful
1 write failed
*************************************************************************/
unsigned char i2c_write( unsigned char data )
{
uint8_t twst;
// send data to the previously addressed device
TWDR = data;
TWCR = (1<<TWINT) | (1<<TWEN);
// wait until transmission completed
while(!(TWCR & (1<<TWINT))) { CHECK_FORCE_STOP() };
// check value of TWI Status Register. Mask prescaler bits
twst = TW_STATUS & 0xF8;
if( twst != TW_MT_DATA_ACK) return 1;
return 0;
}/* i2c_write */
/*************************************************************************
Read one byte from the I2C device, request more data from device
Return: byte read from I2C device
*************************************************************************/
unsigned char i2c_readAck(void)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT))) { CHECK_FORCE_STOP(); };
return TWDR;
}/* i2c_readAck */
/*************************************************************************
Read one byte from the I2C device, read is followed by a stop condition
Return: byte read from I2C device
*************************************************************************/
unsigned char i2c_readNak(void)
{
TWCR = (1<<TWINT) | (1<<TWEN);
while(!(TWCR & (1<<TWINT))) { CHECK_FORCE_STOP(); };
return TWDR;
}/* i2c_readNak */

+ 21
- 0
keyboard/kimera/ws2812_config.h View File

@@ -0,0 +1,21 @@
/*
* light_ws2812_config.h
*
* Created: 18.01.2014 09:58:15
*
* User Configuration file for the light_ws2812_lib
*
*/


#ifndef WS2812_CONFIG_H_
#define WS2812_CONFIG_H_

///////////////////////////////////////////////////////////////////////
// Define I/O pin
///////////////////////////////////////////////////////////////////////

#define ws2812_port C // Data port
#define ws2812_pin 6 // Data out pin

#endif /* WS2812_CONFIG_H_ */