Pārlūkot izejas kodu

Add support for Meira

Cole Markham 7 gadi atpakaļ
vecāks
revīzija
a9a46adba0

+ 287 - 0
keyboards/meira/TWIlib.c

@@ -0,0 +1,287 @@
+/*
+ * TWIlib.c
+ *
+ *  Created: 6/01/2014 10:41:33 PM
+ *  Author: Chris Herring
+ */
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include "TWIlib.h"
+#include "util/delay.h"
+#include "print.h"
+
+void TWIInit()
+{
+	TWIInfo.mode = Ready;
+	TWIInfo.errorCode = 0xFF;
+	TWIInfo.repStart = 0;
+	// Set pre-scalers (no pre-scaling)
+	TWSR = 0;
+	// Set bit rate
+	TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
+	// Enable TWI and interrupt
+	TWCR = (1 << TWIE) | (1 << TWEN);
+}
+
+uint8_t isTWIReady()
+{
+	if ( (TWIInfo.mode == Ready) | (TWIInfo.mode == RepeatedStartSent) )
+	{
+
+//        xprintf("i2c ready\n");
+		return 1;
+	}
+	else
+	{
+		if(TWIInfo.mode == Initializing){
+			switch(TWIInfo.errorCode){
+		        case TWI_SUCCESS:
+		            break;
+		        case TWI_NO_RELEVANT_INFO:
+
+		        	break;
+				case TWI_LOST_ARBIT:
+				case TWI_MT_DATA_NACK:
+					// Some kind of I2C error, reset and re-init
+		        	xprintf("I2C init error: %d\n", TWIInfo.errorCode);
+			        TWCR = (1 << TWINT)|(1 << TWSTO);
+		        	TWIInit();
+		        	break;
+		        default:
+		        	xprintf("Other i2c init error: %d\n", TWIInfo.errorCode);
+			}
+		}
+		return 0;
+	}
+}
+
+
+void TWITransmitData(void *const TXdata, uint8_t dataLen, uint8_t repStart, uint8_t blocking)
+{
+	// Wait until ready
+	while (!isTWIReady()) {_delay_us(1);}
+	// Reset the I2C stuff
+	TWCR = (1 << TWINT)|(1 << TWSTO);
+	TWIInit();
+	// Set repeated start mode
+	TWIInfo.repStart = repStart;
+	// Copy transmit info to global variables
+	TWITransmitBuffer = (uint8_t *)TXdata;
+	TXBuffLen = dataLen;
+	TXBuffIndex = 0;
+
+	// If a repeated start has been sent, then devices are already listening for an address
+	// and another start does not need to be sent.
+	if (TWIInfo.mode == RepeatedStartSent)
+	{
+		TWIInfo.mode = Initializing;
+		TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer
+		TWISendTransmit(); // Send the data
+	}
+	else // Otherwise, just send the normal start signal to begin transmission.
+	{
+		TWIInfo.mode = Initializing;
+		TWISendStart();
+	}
+	if(blocking){
+		// Wait until ready
+		while (!isTWIReady()){_delay_us(1);}
+	}
+}
+
+
+// uint8_t TWITransmitData(void *const TXdata, uint8_t dataLen, uint8_t repStart)
+// {
+// 	if (dataLen <= TXMAXBUFLEN)
+// 	{
+// 		// Wait until ready
+// 		while (!isTWIReady()) {_delay_us(1);}
+// 		// Set repeated start mode
+// 		TWIInfo.repStart = repStart;
+// 		// Copy data into the transmit buffer
+// 		uint8_t *data = (uint8_t *)TXdata;
+// 		for (int i = 0; i < dataLen; i++)
+// 		{
+// 			TWITransmitBuffer[i] = data[i];
+// 		}
+// 		// Copy transmit info to global variables
+// 		TXBuffLen = dataLen;
+// 		TXBuffIndex = 0;
+
+// 		// If a repeated start has been sent, then devices are already listening for an address
+// 		// and another start does not need to be sent.
+// 		if (TWIInfo.mode == RepeatedStartSent)
+// 		{
+// 			TWIInfo.mode = Initializing;
+// 			TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer
+// 			TWISendTransmit(); // Send the data
+// 		}
+// 		else // Otherwise, just send the normal start signal to begin transmission.
+// 		{
+// 			TWIInfo.mode = Initializing;
+// 			TWISendStart();
+// 		}
+
+// 	}
+// 	else
+// 	{
+// 		return 1; // return an error if data length is longer than buffer
+// 	}
+// 	return 0;
+// }
+
+uint8_t TWIReadData(uint8_t TWIaddr, uint8_t bytesToRead, uint8_t repStart)
+{
+	// Check if number of bytes to read can fit in the RXbuffer
+	if (bytesToRead < RXMAXBUFLEN)
+	{
+		// Reset buffer index and set RXBuffLen to the number of bytes to read
+		RXBuffIndex = 0;
+		RXBuffLen = bytesToRead;
+		// Create the one value array for the address to be transmitted
+		uint8_t TXdata[1];
+		// Shift the address and AND a 1 into the read write bit (set to write mode)
+		TXdata[0] = (TWIaddr << 1) | 0x01;
+		// Use the TWITransmitData function to initialize the transfer and address the slave
+		TWITransmitData(TXdata, 1, repStart, 0);
+	}
+	else
+	{
+		return 0;
+	}
+	return 1;
+}
+
+ISR (TWI_vect)
+{
+	switch (TWI_STATUS)
+	{
+		// ----\/ ---- MASTER TRANSMITTER OR WRITING ADDRESS ----\/ ----  //
+		case TWI_MT_SLAW_ACK: // SLA+W transmitted and ACK received
+		// Set mode to Master Transmitter
+		TWIInfo.mode = MasterTransmitter;
+		case TWI_START_SENT: // Start condition has been transmitted
+		case TWI_MT_DATA_ACK: // Data byte has been transmitted, ACK received
+			if (TXBuffIndex < TXBuffLen) // If there is more data to send
+			{
+				TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer
+				TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
+				TWISendTransmit(); // Send the data
+			}
+			// This transmission is complete however do not release bus yet
+			else if (TWIInfo.repStart)
+			{
+				TWIInfo.errorCode = 0xFF;
+				TWISendStart();
+			}
+			// All transmissions are complete, exit
+			else
+			{
+				TWIInfo.mode = Ready;
+				TWIInfo.errorCode = 0xFF;
+				TWISendStop();
+			}
+			break;
+
+		// ----\/ ---- MASTER RECEIVER ----\/ ----  //
+
+		case TWI_MR_SLAR_ACK: // SLA+R has been transmitted, ACK has been received
+			// Switch to Master Receiver mode
+			TWIInfo.mode = MasterReceiver;
+			// If there is more than one byte to be read, receive data byte and return an ACK
+			if (RXBuffIndex < RXBuffLen-1)
+			{
+				TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
+				TWISendACK();
+			}
+			// Otherwise when a data byte (the only data byte) is received, return NACK
+			else
+			{
+				TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
+				TWISendNACK();
+			}
+			break;
+
+		case TWI_MR_DATA_ACK: // Data has been received, ACK has been transmitted.
+
+			/// -- HANDLE DATA BYTE --- ///
+			TWIReceiveBuffer[RXBuffIndex++] = TWDR;
+			// If there is more than one byte to be read, receive data byte and return an ACK
+			if (RXBuffIndex < RXBuffLen-1)
+			{
+				TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
+				TWISendACK();
+			}
+			// Otherwise when a data byte (the only data byte) is received, return NACK
+			else
+			{
+				TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
+				TWISendNACK();
+			}
+			break;
+
+		case TWI_MR_DATA_NACK: // Data byte has been received, NACK has been transmitted. End of transmission.
+
+			/// -- HANDLE DATA BYTE --- ///
+			TWIReceiveBuffer[RXBuffIndex++] = TWDR;
+			// This transmission is complete however do not release bus yet
+			if (TWIInfo.repStart)
+			{
+				TWIInfo.errorCode = 0xFF;
+				TWISendStart();
+			}
+			// All transmissions are complete, exit
+			else
+			{
+				TWIInfo.mode = Ready;
+				TWIInfo.errorCode = 0xFF;
+				TWISendStop();
+			}
+			break;
+
+		// ----\/ ---- MT and MR common ----\/ ---- //
+
+		case TWI_MR_SLAR_NACK: // SLA+R transmitted, NACK received
+		case TWI_MT_SLAW_NACK: // SLA+W transmitted, NACK received
+		case TWI_MT_DATA_NACK: // Data byte has been transmitted, NACK received
+		case TWI_LOST_ARBIT: // Arbitration has been lost
+			// Return error and send stop and set mode to ready
+			if (TWIInfo.repStart)
+			{
+				TWIInfo.errorCode = TWI_STATUS;
+				TWISendStart();
+			}
+			// All transmissions are complete, exit
+			else
+			{
+				TWIInfo.mode = Ready;
+				TWIInfo.errorCode = TWI_STATUS;
+				TWISendStop();
+			}
+			break;
+		case TWI_REP_START_SENT: // Repeated start has been transmitted
+			// Set the mode but DO NOT clear TWINT as the next data is not yet ready
+			TWIInfo.mode = RepeatedStartSent;
+			break;
+
+		// ----\/ ---- SLAVE RECEIVER ----\/ ----  //
+
+		// TODO  IMPLEMENT SLAVE RECEIVER FUNCTIONALITY
+
+		// ----\/ ---- SLAVE TRANSMITTER ----\/ ----  //
+
+		// TODO  IMPLEMENT SLAVE TRANSMITTER FUNCTIONALITY
+
+		// ----\/ ---- MISCELLANEOUS STATES ----\/ ----  //
+		case TWI_NO_RELEVANT_INFO: // It is not really possible to get into this ISR on this condition
+								   // Rather, it is there to be manually set between operations
+			break;
+		case TWI_ILLEGAL_START_STOP: // Illegal START/STOP, abort and return error
+			TWIInfo.errorCode = TWI_ILLEGAL_START_STOP;
+			TWIInfo.mode = Ready;
+			TWISendStop();
+			break;
+	}
+
+}

+ 81 - 0
keyboards/meira/TWIlib.h

@@ -0,0 +1,81 @@
+/*
+ * TWIlib.h
+ *
+ * Created: 6/01/2014 10:38:42 PM
+ *  Author: Chris Herring
+ */
+
+
+#ifndef TWILIB_H_
+#define TWILIB_H_
+// TWI bit rate
+#define TWI_FREQ 400000
+// Get TWI status
+#define TWI_STATUS	(TWSR & 0xF8)
+// Transmit buffer length
+#define TXMAXBUFLEN 20
+// Receive buffer length
+#define RXMAXBUFLEN 20
+// Global transmit buffer
+volatile uint8_t *TWITransmitBuffer;
+// Global receive buffer
+volatile uint8_t TWIReceiveBuffer[RXMAXBUFLEN];
+// Buffer indexes
+volatile int TXBuffIndex; // Index of the transmit buffer. Is volatile, can change at any time.
+int RXBuffIndex; // Current index in the receive buffer
+// Buffer lengths
+int TXBuffLen; // The total length of the transmit buffer
+int RXBuffLen; // The total number of bytes to read (should be less than RXMAXBUFFLEN)
+
+typedef enum {
+	Ready,
+	Initializing,
+	RepeatedStartSent,
+	MasterTransmitter,
+	MasterReceiver,
+	SlaceTransmitter,
+	SlaveReciever
+	} TWIMode;
+
+ typedef struct TWIInfoStruct{
+	TWIMode mode;
+	uint8_t errorCode;
+	uint8_t repStart;
+	}TWIInfoStruct;
+TWIInfoStruct TWIInfo;
+
+
+// TWI Status Codes
+#define TWI_START_SENT			0x08 // Start sent
+#define TWI_REP_START_SENT		0x10 // Repeated Start sent
+// Master Transmitter Mode
+#define TWI_MT_SLAW_ACK			0x18 // SLA+W sent and ACK received
+#define TWI_MT_SLAW_NACK		0x20 // SLA+W sent and NACK received
+#define TWI_MT_DATA_ACK			0x28 // DATA sent and ACK received
+#define TWI_MT_DATA_NACK		0x30 // DATA sent and NACK received
+// Master Receiver Mode
+#define TWI_MR_SLAR_ACK			0x40 // SLA+R sent, ACK received
+#define TWI_MR_SLAR_NACK		0x48 // SLA+R sent, NACK received
+#define TWI_MR_DATA_ACK			0x50 // Data received, ACK returned
+#define TWI_MR_DATA_NACK		0x58 // Data received, NACK returned
+
+// Miscellaneous States
+#define TWI_LOST_ARBIT			0x38 // Arbitration has been lost
+#define TWI_NO_RELEVANT_INFO	0xF8 // No relevant information available
+#define TWI_ILLEGAL_START_STOP	0x00 // Illegal START or STOP condition has been detected
+#define TWI_SUCCESS				0xFF // Successful transfer, this state is impossible from TWSR as bit2 is 0 and read only
+
+
+#define TWISendStart()		(TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)|(1<<TWIE)) // Send the START signal, enable interrupts and TWI, clear TWINT flag to resume transfer.
+#define TWISendStop()		(TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN)|(1<<TWIE)) // Send the STOP signal, enable interrupts and TWI, clear TWINT flag.
+#define TWISendTransmit()	(TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)) // Used to resume a transfer, clear TWINT and ensure that TWI and interrupts are enabled.
+#define TWISendACK()		(TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)|(1<<TWEA)) // FOR MR mode. Resume a transfer, ensure that TWI and interrupts are enabled and respond with an ACK if the device is addressed as a slave or after it receives a byte.
+#define TWISendNACK()		(TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)) // FOR MR mode. Resume a transfer, ensure that TWI and interrupts are enabled but DO NOT respond with an ACK if the device is addressed as a slave or after it receives a byte.
+
+// Function declarations
+void TWITransmitData(void *const TXdata, uint8_t dataLen, uint8_t repStart, uint8_t blocking);
+void TWIInit(void);
+uint8_t TWIReadData(uint8_t TWIaddr, uint8_t bytesToRead, uint8_t repStart);
+uint8_t isTWIReady(void);
+
+#endif // TWICOMMS_H_

+ 53 - 0
keyboards/meira/config.h

@@ -0,0 +1,53 @@
+/*
+Copyright 2017 Cole Markham
+
+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
+
+#include "config_common.h"
+
+/* USB Device descriptor parameter */
+#define VENDOR_ID       0xFEED
+#define PRODUCT_ID      0x6061
+#define DEVICE_VER      0x0001
+#define MANUFACTURER    WoodKeys.click
+#define PRODUCT         Meira
+#define DESCRIPTION     Low-profile Ortholinear Compact keyboard
+
+/* key matrix size */
+#define MATRIX_ROWS 4
+#define MATRIX_COLS 12
+
+/* COL2ROW, ROW2COL, or CUSTOM_MATRIX */
+#define DIODE_DIRECTION CUSTOM_MATRIX
+
+#define BACKLIGHT_LEVELS 10
+#define BACKLIGHT_PWM_MAP {2, 4, 8, 16, 40, 55, 70, 128, 200, 255}
+#define BACKLIGHT_BREATHING
+
+#define RGB_DI_PIN D3
+#define RGBLIGHT_TIMER
+#define RGBLED_NUM 15    // Number of LEDs
+
+#ifdef SUBPROJECT_promicro
+    #include "promicro/config.h"
+#endif
+#ifdef SUBPROJECT_featherble
+    #include "featherble/config.h"
+#endif
+
+#endif

+ 175 - 0
keyboards/meira/featherble/config.h

@@ -0,0 +1,175 @@
+/*
+Copyright 2017 REPLACE_WITH_YOUR_NAME
+
+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 FEATHERBLECONFIG_H
+#define FEATHERBLECONFIG_H
+
+#include "config_common.h"
+
+/*
+ * Keyboard Matrix Assignments
+ *
+ * Change this to how you wired your keyboard
+ * COLS: AVR pins used for columns, left to right
+ * ROWS: AVR pins used for rows, top to bottom
+ * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode)
+ *                  ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
+ *
+*/
+#define MATRIX_ROW_PINS { F7, F6, F5, F4 }
+// Column pins to demux in LSB order
+#define MATRIX_COL_PINS { C7, B7, B6, C6 }
+#define LED_EN_PIN D2
+#define UNUSED_PINS
+
+#define CATERINA_BOOTLOADER
+
+ 
+// #define BACKLIGHT_PIN B7
+// #define BACKLIGHT_BREATHING
+//#define BACKLIGHT_LEVELS 3
+
+
+/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
+#define DEBOUNCING_DELAY 5
+
+/* define if matrix has ghost (lacks anti-ghosting diodes) */
+//#define MATRIX_HAS_GHOST
+
+/* number of backlight levels */
+
+/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
+#define LOCKING_SUPPORT_ENABLE
+/* Locking resynchronize hack */
+#define LOCKING_RESYNC_ENABLE
+
+/*
+ * Force NKRO
+ *
+ * Force NKRO (nKey Rollover) to be enabled by default, regardless of the saved
+ * state in the bootmagic EEPROM settings. (Note that NKRO must be enabled in the
+ * makefile for this to work.)
+ *
+ * If forced on, NKRO can be disabled via magic key (default = LShift+RShift+N)
+ * until the next keyboard reset.
+ *
+ * NKRO may prevent your keystrokes from being detected in the BIOS, but it is
+ * fully operational during normal computer usage.
+ *
+ * For a less heavy-handed approach, enable NKRO via magic key (LShift+RShift+N)
+ * or via bootmagic (hold SPACE+N while plugging in the keyboard). Once set by
+ * bootmagic, NKRO mode will always be enabled until it is toggled again during a
+ * power-up.
+ *
+ */
+//#define FORCE_NKRO
+
+/*
+ * Magic Key Options
+ *
+ * Magic keys are hotkey commands that allow control over firmware functions of
+ * the keyboard. They are best used in combination with the HID Listen program,
+ * found here: https://www.pjrc.com/teensy/hid_listen.html
+ *
+ * The options below allow the magic key functionality to be changed. This is
+ * useful if your keyboard/keypad is missing keys and you want magic key support.
+ *
+ */
+
+/* key combination for magic key command */
+#define IS_COMMAND() ( \
+    keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
+)
+
+/* control how magic key switches layers */
+//#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS  true
+//#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS  true
+//#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM false
+
+/* override magic key keymap */
+//#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
+//#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
+//#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
+//#define MAGIC_KEY_HELP1          H
+//#define MAGIC_KEY_HELP2          SLASH
+//#define MAGIC_KEY_DEBUG          D
+//#define MAGIC_KEY_DEBUG_MATRIX   X
+//#define MAGIC_KEY_DEBUG_KBD      K
+//#define MAGIC_KEY_DEBUG_MOUSE    M
+//#define MAGIC_KEY_VERSION        V
+//#define MAGIC_KEY_STATUS         S
+//#define MAGIC_KEY_CONSOLE        C
+//#define MAGIC_KEY_LAYER0_ALT1    ESC
+//#define MAGIC_KEY_LAYER0_ALT2    GRAVE
+//#define MAGIC_KEY_LAYER0         0
+//#define MAGIC_KEY_LAYER1         1
+//#define MAGIC_KEY_LAYER2         2
+//#define MAGIC_KEY_LAYER3         3
+//#define MAGIC_KEY_LAYER4         4
+//#define MAGIC_KEY_LAYER5         5
+//#define MAGIC_KEY_LAYER6         6
+//#define MAGIC_KEY_LAYER7         7
+//#define MAGIC_KEY_LAYER8         8
+//#define MAGIC_KEY_LAYER9         9
+//#define MAGIC_KEY_BOOTLOADER     PAUSE
+//#define MAGIC_KEY_LOCK           CAPS
+//#define MAGIC_KEY_EEPROM         E
+//#define MAGIC_KEY_NKRO           N
+//#define MAGIC_KEY_SLEEP_LED      Z
+
+/*
+ * 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
+
+/*
+ * MIDI options
+ */
+
+/* Prevent use of disabled MIDI features in the keymap */
+//#define MIDI_ENABLE_STRICT 1
+
+/* enable basic MIDI features:
+   - MIDI notes can be sent when in Music mode is on
+*/
+//#define MIDI_BASIC
+
+/* enable advanced MIDI features:
+   - MIDI notes can be added to the keymap
+   - Octave shift and transpose
+   - Virtual sustain, portamento, and modulation wheel
+   - etc.
+*/
+//#define MIDI_ADVANCED
+
+/* override number of MIDI tone keycodes (each octave adds 12 keycodes and allocates 12 bytes) */
+//#define MIDI_TONE_KEYCODE_OCTAVES 1
+
+#endif

+ 1 - 0
keyboards/meira/featherble/featherble.c

@@ -0,0 +1 @@
+#include "meira.h"

+ 9 - 0
keyboards/meira/featherble/featherble.h

@@ -0,0 +1,9 @@
+#ifndef FEATHERBLE_H
+#define FEATHERBLE_H
+
+#include "../meira.h"
+
+#include "quantum.h"
+
+
+#endif

+ 4 - 0
keyboards/meira/featherble/rules.mk

@@ -0,0 +1,4 @@
+BLUETOOTH_ENABLE = yes
+BACKLIGHT_ENABLE = yes
+F_CPU = 8000000
+

+ 286 - 0
keyboards/meira/issi.c

@@ -0,0 +1,286 @@
+#ifdef ISSI_ENABLE
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <util/delay.h>
+#include <avr/sfr_defs.h>
+#include <avr/io.h>
+#include <util/twi.h>
+#include "issi.h"
+#include "print.h"
+#include "TWIlib.h"
+
+#define ISSI_ADDR_DEFAULT 0xE8
+
+#define ISSI_REG_CONFIG 0x00
+#define ISSI_REG_CONFIG_PICTUREMODE 0x00
+#define ISSI_REG_CONFIG_AUTOPLAYMODE 0x08
+
+#define ISSI_CONF_PICTUREMODE 0x00
+#define ISSI_CONF_AUTOFRAMEMODE 0x04
+#define ISSI_CONF_AUDIOMODE 0x08
+
+#define ISSI_REG_PICTUREFRAME 0x01
+
+#define ISSI_REG_SHUTDOWN 0x0A
+#define ISSI_REG_AUDIOSYNC 0x06
+
+#define ISSI_COMMANDREGISTER 0xFD
+#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine'
+uint8_t control[8][9] = {
+    {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+ISSIDeviceStruct *issi_devices[4] = {0, 0, 0, 0};
+
+#ifndef cbi
+#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
+#endif
+
+#ifndef sbi
+#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
+#endif
+
+#define I2C_WRITE 0
+#define F_SCL 400000UL // SCL frequency
+#define Prescaler 1
+#define TWBR_val ((((F_CPU / F_SCL) / Prescaler) - 16 ) / 2)
+
+uint8_t i2c_start(uint8_t address)
+{
+    // reset TWI control register
+    TWCR = 0;
+    // transmit START condition
+    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
+    // wait for end of transmission
+    while( !(TWCR & (1<<TWINT)) );
+
+    // check if the start condition was successfully transmitted
+    if((TWSR & 0xF8) != TW_START){ return 1; }
+
+    // load slave address into data register
+    TWDR = address;
+    // start transmission of address
+    TWCR = (1<<TWINT) | (1<<TWEN);
+    // wait for end of transmission
+    while( !(TWCR & (1<<TWINT)) );
+
+    // check if the device has acknowledged the READ / WRITE mode
+    uint8_t twst = TW_STATUS & 0xF8;
+    if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
+
+    return 0;
+}
+
+uint8_t i2c_write(uint8_t data)
+{
+    // load data into data register
+    TWDR = data;
+    // start transmission of data
+    TWCR = (1 << TWINT) | (1 << TWEN);
+    // wait for end of transmission
+    while (!(TWCR & (1 << TWINT)))
+        ;
+
+    if ((TWSR & 0xF8) != TW_MT_DATA_ACK) {
+        return 1;
+    }
+    return 0;
+}
+
+uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length)
+{
+    TWBR = (uint8_t)TWBR_val;
+    if (i2c_start(address | I2C_WRITE))
+        return 1;
+    for (uint16_t i = 0; i < length; i++) {
+        if (i2c_write(data[i]))
+            return 1;
+    }
+    // transmit STOP condition
+    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
+    return 0;
+}
+
+void setFrame(uint8_t device, uint8_t frame)
+{
+    static uint8_t current_frame = -1;
+    if(current_frame != frame){
+        uint8_t payload[] = {
+            ISSI_ADDR_DEFAULT | device << 1,
+            ISSI_COMMANDREGISTER,
+            frame
+        };
+        TWITransmitData(payload, sizeof(payload), 0, 1);
+    }
+    // static uint8_t current_frame = 0xFF;
+    // if(current_frame == frame){
+    //     // return;
+    // }
+    // uint8_t payload[2] = { ISSI_COMMANDREGISTER, frame };
+    // i2c_transmit(ISSI_ADDR_DEFAULT | device << 1, payload, 2);
+    // current_frame = frame;
+}
+
+void writeRegister8(uint8_t device, uint8_t frame, uint8_t reg, uint8_t data)
+{
+    // Set the frame
+    setFrame(device, frame);
+
+    // Write to the register
+    uint8_t payload[] = {
+        ISSI_ADDR_DEFAULT | device << 1,
+        reg,
+        data
+    };
+    TWITransmitData(payload, sizeof(payload), 0, 1);
+}
+
+// void activateLED(uint8_t matrix, uint8_t cx, uint8_t cy, uint8_t pwm)
+// {
+//     xprintf("activeLED: %02X %02X %02X %02X\n", matrix, cy, cx, pwm);
+//     uint8_t x = cx - 1;  // funciton takes 1 based counts, but we need 0...
+//     uint8_t y = cy - 1;  // creating them once for less confusion
+//     if(pwm == 0){
+//         cbi(control[matrix][y], x);
+//     }else{
+//         sbi(control[matrix][y], x);
+//     }
+//     uint8_t device = (matrix & 0x06) >> 1;
+//     uint8_t control_reg = (y << 1) | (matrix & 0x01);
+//     uint8_t pwm_reg = 0;
+//     switch(matrix & 0x01){
+//         case 0:
+//             pwm_reg = 0x24;
+//             break;
+//         case 1:
+//             pwm_reg = 0x2C;
+//             break;
+//     }
+//     pwm_reg += (y << 4) + x;
+//     xprintf("  device: %02X\n", device);
+//     xprintf("  control: %02X %02X\n", control_reg, control[matrix][y]);
+//     xprintf("  pwm:     %02X %02X\n", pwm_reg, pwm);
+//     writeRegister8(device, 0, control_reg, control[matrix][y]);
+//     writeRegister8(device, 0, control_reg + 0x12, control[matrix][y]);
+//     writeRegister8(device, 0, pwm_reg, pwm);
+// }
+
+void activateLED(uint8_t matrix, uint8_t cx, uint8_t cy, uint8_t pwm)
+{
+    uint8_t device_addr = (matrix & 0x06) >> 1;
+    ISSIDeviceStruct *device = issi_devices[device_addr];
+    if(device == 0){
+        return;
+    }
+    // xprintf("activeLED: %02X %02X %02X %02X\n", matrix, cy, cx, pwm);
+    uint8_t x = cx - 1;  // funciton takes 1 based counts, but we need 0...
+    uint8_t y = cy - 1;  // creating them once for less confusion
+    uint8_t control_reg = (y << 1) | (matrix & 0x01);
+    if(pwm == 0){
+        cbi(device->led_ctrl[control_reg], x);
+        cbi(device->led_blink_ctrl[control_reg], x);
+     }else{
+        sbi(device->led_ctrl[control_reg], x);
+        sbi(device->led_blink_ctrl[control_reg], x);
+    }
+    uint8_t pwm_reg = 0;
+    switch(matrix & 0x01){
+        case 0:
+            pwm_reg = 0x00;
+            break;
+        case 1:
+            pwm_reg = 0x08;
+            break;
+    }
+    pwm_reg += (y << 4) + x;
+    // xprintf("  device_addr: %02X\n", device_addr);
+    // xprintf("  control: %02X %02X\n", control_reg, control[matrix][y]);
+    // xprintf("  pwm:     %02X %02X\n", pwm_reg, pwm);
+    // writeRegister8(device_addr, 0, control_reg, control[matrix][y]);
+    device->led_pwm[pwm_reg] = pwm;
+    device->led_dirty = 1;
+
+    // writeRegister8(device_addr, 0, control_reg + 0x12, control[matrix][y]);
+    // writeRegister8(device_addr, 0, pwm_reg, pwm);
+}
+
+void update_issi(uint8_t device_addr, uint8_t blocking)
+{
+    // This seems to take about 6ms
+    ISSIDeviceStruct *device = issi_devices[device_addr];
+    if(device != 0){
+        if(device->fn_dirty){
+            device->fn_dirty = 0;
+            setFrame(device_addr, ISSI_BANK_FUNCTIONREG);
+            TWITransmitData(&device->fn_device_addr, sizeof(device->fn_registers) + 2, 0, 1);
+        }
+        if(device->led_dirty){
+            device->led_dirty = 0;
+            setFrame(device_addr, 0);
+            TWITransmitData(&device->led_device_addr, 0xB6, 0, blocking);
+        }
+    }
+}
+
+void issi_init(void)
+{
+    // Set LED_EN/SDB high to enable the chip
+    xprintf("Enabing SDB on pin: %d\n", LED_EN_PIN);
+    _SFR_IO8((LED_EN_PIN >> 4) + 1) &= ~_BV(LED_EN_PIN & 0xF); // IN
+    _SFR_IO8((LED_EN_PIN >> 4) + 2) |=  _BV(LED_EN_PIN & 0xF); // HI
+    TWIInit();
+    for(uint8_t device_addr = 0; device_addr < 4; device_addr++){
+        xprintf("ISSI Init device: %d\n", device_addr);
+        // If this device has been previously allocated, free it
+        if(issi_devices[device_addr] != 0){
+            free(issi_devices[device_addr]);
+        }
+        // Try to shutdown the device, if this fails skip this device
+        writeRegister8(device_addr, ISSI_BANK_FUNCTIONREG, ISSI_REG_SHUTDOWN, 0x00);
+        while (!isTWIReady()){_delay_us(1);}
+        if(TWIInfo.errorCode != 0xFF){
+            xprintf("ISSI init failed %d %02X %02X\n", device_addr, TWIInfo.mode, TWIInfo.errorCode);
+            continue;
+        }
+        // Allocate the device structure - calloc zeros it for us
+        ISSIDeviceStruct *device = (ISSIDeviceStruct *)calloc(sizeof(ISSIDeviceStruct) * 2, 1);
+        issi_devices[device_addr] = device;
+        device->fn_device_addr = ISSI_ADDR_DEFAULT | device_addr << 1;
+        device->fn_register_addr = 0;
+        device->led_device_addr = ISSI_ADDR_DEFAULT | device_addr << 1;
+        device->led_register_addr = 0;
+        // set dirty bits so that all of the buffered data is written out
+        device->fn_dirty = 1;
+        device->led_dirty = 1;
+        update_issi(device_addr, 1);
+        // Set the function register to picture mode
+        // device->fn_reg[ISSI_REG_CONFIG] = ISSI_REG_CONFIG_PICTUREMODE;
+        writeRegister8(device_addr, ISSI_BANK_FUNCTIONREG, ISSI_REG_SHUTDOWN, 0x01);
+    }
+
+    // Shutdown and set all registers to 0
+    // writeRegister8(device_addr, ISSI_BANK_FUNCTIONREG, ISSI_REG_SHUTDOWN, 0x00);
+    // for(uint8_t bank = 0; bank <= 7; bank++){
+    //     for (uint8_t reg = 0x00; reg <= 0xB3; reg++) {
+    //         writeRegister8(device_addr, bank, reg, 0x00);
+    //     }
+    // }
+    // for (uint8_t reg = 0; reg <= 0x0C; reg++) {
+    //     writeRegister8(device_addr, ISSI_BANK_FUNCTIONREG, reg, 0x00);
+    // }
+    // writeRegister8(device_addr, ISSI_BANK_FUNCTIONREG, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE);
+    // writeRegister8(device_addr, ISSI_BANK_FUNCTIONREG, ISSI_REG_SHUTDOWN, 0x01);
+    // picture mode
+    // writeRegister8(ISSI_BANK_FUNCTIONREG, 0x01, 0x01);
+
+    //Enable blink
+    // writeRegister8(ISSI_BANK_FUNCTIONREG, 0x05, 0x48B);
+
+    //Enable Breath
+
+}
+
+#endif

+ 40 - 0
keyboards/meira/issi.h

@@ -0,0 +1,40 @@
+#ifdef ISSI_ENABLE
+#ifndef ISSI_H
+#define ISSI_H
+
+typedef struct ISSIDeviceStruct{
+    uint8_t fn_dirty;       // function registers need to be resent
+    uint8_t fn_device_addr;
+    uint8_t fn_register_addr;
+    uint8_t fn_registers[13];
+    uint8_t led_dirty;      // LED data has changed and needs to be resent
+    uint8_t led_device_addr;
+    uint8_t led_register_addr;
+    uint8_t led_ctrl[18];
+    uint8_t led_blink_ctrl[18];
+    uint8_t led_pwm[144];
+}ISSIDeviceStruct;
+
+extern ISSIDeviceStruct *issi_devices[];
+
+// Low level commands- 'device' is the 2-bit i2c id.
+void issi_init(void);
+void set_shutdown(uint8_t device, uint8_t shutdown);
+void writeRegister8(uint8_t device, uint8_t frame, uint8_t reg, uint8_t data);
+
+// Higher level, no device is given, but it is calculated from 'matrix'
+// Each device has 2 blocks, max of 4 devices:
+//  Device  |   Block   =   Matrix
+//    0           A           0
+//    0           B           1
+//    1           A           2
+//    1           B           3
+//    2           A           4
+//    2           B           5
+//    3           A           6
+//    3           B           7
+void activateLED(uint8_t matrix, uint8_t cx, uint8_t cy, uint8_t pwm);
+void update_issi(uint8_t device_addr, uint8_t blocking);
+
+#endif
+#endif

+ 24 - 0
keyboards/meira/keymaps/default/config.h

@@ -0,0 +1,24 @@
+/* Copyright 2017 REPLACE_WITH_YOUR_NAME
+ *
+ * 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_USER_H
+#define CONFIG_USER_H
+
+#include "../../config.h"
+
+// place overrides here
+
+#endif

+ 320 - 0
keyboards/meira/keymaps/default/keymap.c

@@ -0,0 +1,320 @@
+/* Copyright 2017 Cole Markham
+ *
+ * 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 "meira.h"
+#include "issi.h"
+#include "lighting.h"
+
+#ifdef RGBLIGHT_ENABLE
+//Following line allows macro to read current RGB settings
+extern rgblight_config_t rgblight_config;
+#endif
+
+#define _QWERTY 0
+#define _COLEMAK 1
+#define _DVORAK 2
+#define _LOWER 3
+#define _RAISE 4
+#define _ADJUST 16
+
+enum custom_keycodes {
+  QWERTY = SAFE_RANGE,
+  COLEMAK,
+  DVORAK,
+  LOWER,
+  RAISE,
+  ADJUST,
+};
+
+// define variables for reactive RGB
+bool TOG_STATUS = false;
+int RGB_current_mode;
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+        /* Qwerty
+         * ,-----------------------------------------------------------------------------------.
+         * | Esc  |   Q  |   W  |   E  |   R  |   T  |   Y  |   U  |   I  |   O  |   P  | Bksp |
+         * |------+------+------+------+------+-------------+------+------+------+------+------|
+         * | Tab  |   A  |   S  |   D  |   F  |   G  |   H  |   J  |   K  |   L  |   ;  |  '   |
+         * |------+------+------+------+------+------|------+------+------+------+------+------|
+         * | Shift|   Z  |   X  |   C  |   V  |   B  |   N  |   M  |   ,  |   .  |   /  |Enter |
+         * |------+------+------+------+------+------+------+------+------+------+------+------|
+         * |Adjust| Ctrl | Ctrl  | Alt  |Lower | Cmd  |Space |Raise | Left | Down |  Up  |Right |
+         * `-----------------------------------------------------------------------------------'
+         */
+        [_QWERTY] = KEYMAP( \
+                KC_ESC,  KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,    KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,    KC_BSPC, \
+                KC_TAB,  KC_A,    KC_S,    KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT, \
+                KC_LSFT, KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH,  KC_ENT, \
+                ADJUST,  KC_LCTL, KC_LALT, KC_LALT, LOWER,   KC_LGUI,  KC_SPC,  RAISE,   KC_LEFT, KC_DOWN, KC_UP,   KC_RGHT \
+        ),
+
+        /* Colemak
+         * ,-----------------------------------------------------------------------------------.
+         * | Tab  |   Q  |   W  |   F  |   P  |   G  |   J  |   L  |   U  |   Y  |   ;  | Bksp |
+         * |------+------+------+------+------+-------------+------+------+------+------+------|
+         * | Esc  |   A  |   R  |   S  |   T  |   D  |   H  |   N  |   E  |   I  |   O  |  "   |
+         * |------+------+------+------+------+------|------+------+------+------+------+------|
+         * | Shift|   Z  |   X  |   C  |   V  |   B  |   K  |   M  |   ,  |   .  |   /  |Enter |
+         * |------+------+------+------+------+------+------+------+------+------+------+------|
+         * |Adjust| Ctrl | Alt  | GUI  |Lower |Space |Space |Raise | Left | Down |  Up  |Right |
+         * `-----------------------------------------------------------------------------------'
+         */
+        [_COLEMAK] = KEYMAP( \
+                KC_TAB,  KC_Q,    KC_W,    KC_F,    KC_P,    KC_G,    KC_J,    KC_L,    KC_U,    KC_Y,    KC_SCLN, KC_BSPC, \
+                KC_ESC,  KC_A,    KC_R,    KC_S,    KC_T,    KC_D,    KC_H,    KC_N,    KC_E,    KC_I,    KC_O,    KC_QUOT, \
+                KC_LSFT, KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_K,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_ENT , \
+                ADJUST,  KC_LCTL, KC_LALT, KC_LGUI, LOWER,   KC_SPC,  KC_SPC,  RAISE,   KC_LEFT, KC_DOWN, KC_UP,   KC_RGHT \
+        ),
+
+        /* Dvorak
+         * ,-----------------------------------------------------------------------------------.
+         * | Tab  |   "  |   ,  |   .  |   P  |   Y  |   F  |   G  |   C  |   R  |   L  | Bksp |
+         * |------+------+------+------+------+-------------+------+------+------+------+------|
+         * | Esc  |   A  |   O  |   E  |   U  |   I  |   D  |   H  |   T  |   N  |   S  |  /   |
+         * |------+------+------+------+------+------|------+------+------+------+------+------|
+         * | Shift|   ;  |   Q  |   J  |   K  |   X  |   B  |   M  |   W  |   V  |   Z  |Enter |
+         * |------+------+------+------+------+------+------+------+------+------+------+------|
+         * |Adjust| Ctrl | Alt  | GUI  |Lower |Space |Space |Raise | Left | Down |  Up  |Right |
+         * `-----------------------------------------------------------------------------------'
+         */
+        [_DVORAK] = KEYMAP( \
+                KC_TAB,  KC_QUOT, KC_COMM, KC_DOT,  KC_P,    KC_Y,    KC_F,    KC_G,    KC_C,    KC_R,    KC_L,    KC_BSPC, \
+                KC_ESC,  KC_A,    KC_O,    KC_E,    KC_U,    KC_I,    KC_D,    KC_H,    KC_T,    KC_N,    KC_S,    KC_SLSH, \
+                KC_LSFT, KC_SCLN, KC_Q,    KC_J,    KC_K,    KC_X,    KC_B,    KC_M,    KC_W,    KC_V,    KC_Z,    KC_ENT , \
+                ADJUST,  KC_LCTL, KC_LALT, KC_LGUI, LOWER,   KC_SPC,  KC_SPC,  RAISE,   KC_LEFT, KC_DOWN, KC_UP,   KC_RGHT \
+        ),
+
+        /* Lower
+         * ,-----------------------------------------------------------------------------------.
+         * |      |   !  |   @  |   #  |   $  |   %  |   ^  |   &  |   *  |   (  |   )  | Bksp |
+         * |------+------+------+------+------+-------------+------+------+------+------+------|
+         * |   ~  |  F1  |  F2  |  F3  |  F4  |  F5  |  F6  |   _  |   +  |     |    \  |  |   |
+         * |------+------+------+------+------+------|------+------+------+------+------+------|
+         * |      |  F7  |  F8  |  F9  |  F10 |  F11 |  F12 |ISO ~ |ISO | |      |      |Enter |
+         * |------+------+------+------+------+------+------+------+------+------+------+------|
+         * |      |      |      |      |      |             |      | Next | Vol- | Vol+ | Play |
+         * `-----------------------------------------------------------------------------------'
+         */
+        [_LOWER] = KEYMAP( \
+                _______, KC_EXLM, KC_AT,   KC_HASH, KC_DLR,  KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_DEL, \
+                KC_TILD,  KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE, \
+                _______, KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12,S(KC_NUHS),S(KC_NUBS),_______, _______, KC_QUOT, \
+                _______, _______, _______, _______, _______, _______, _______, _______, KC_HOME, KC_PGDN, KC_PGUP, KC_END \
+        ),
+
+        /* Raise
+         * ,-----------------------------------------------------------------------------------.
+         * |      |   1  |   2  |   3  |   4  |   5  |   6  |   7  |   8  |   9  |   0  | Bksp |
+         * |------+------+------+------+------+-------------+------+------+------+------+------|
+         * |   `  |  F1  |  F2  |  F3  |  F4  |  F5  |  F6  |   -  |   =  |   [  |   ]  |  \   |
+         * |------+------+------+------+------+------|------+------+------+------+------+------|
+         * |      |  F7  |  F8  |  F9  |  F10 |  F11 |  F12 |ISO # |ISO / |      |      |Enter |
+         * |------+------+------+------+------+------+------+------+------+------+------+------|
+         * |      |      |      |      |      |             |      | Home | PgUp | PgDn | End  |
+         * `-----------------------------------------------------------------------------------'
+         */
+        [_RAISE] = KEYMAP( \
+                _______,  KC_1,    KC_2,    KC_3,    KC_4,    KC_5,    KC_6,    KC_7,    KC_8,    KC_9,    KC_0,    KC_DEL, \
+                KC_GRV,  KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_MINS, KC_EQL,  KC_LBRC, KC_RBRC, KC_BSLS, \
+                _______, KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12,  KC_NUHS, KC_NUBS, _______, _______, _______, \
+                _______, _______, _______, _______, _______, _______, _______, _______, KC_HOME, KC_PGDN, KC_PGUP, KC_END \
+        ),
+
+        /* Adjust (Lower + Raise)
+         * ,-----------------------------------------------------------------------------------.
+         * |      | Reset|      |      |      |      |      |      |      |      |      |  Del |
+         * |------+------+------+------+------+-------------+------+------+------+------+------|
+         * |      |      |      |Aud on|Audoff|AGnorm|AGswap|Qwerty|Colemk|Dvorak|      |      |
+         * |------+------+------+------+------+------|------+------+------+------+------+------|
+         * |      |      |      |      |      |      |      |      |      |      |      |      |
+         * |------+------+------+------+------+------+------+------+------+------+------+------|
+         * |      |      |      |      |      |             |      |      |      |      |      |
+         * `-----------------------------------------------------------------------------------'
+         */
+        [_ADJUST] =  KEYMAP( \
+                BL_TOGG, RESET,   _______, KC_MRWD, KC_MPLY, KC_MFFD, KC_PSCR, _______, KC_MUTE, KC_VOLD, KC_VOLU, KC_DEL, \
+                BL_STEP, RGB_MOD, _______, AU_ON,   AU_OFF,  AG_NORM, AG_SWAP, QWERTY,  COLEMAK, DVORAK,  _______, _______, \
+                _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
+                _______, KC_PSCR, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ \
+        )
+};
+
+const uint16_t PROGMEM fn_actions[] = {
+
+};
+
+// Setting ADJUST layer RGB back to default
+void update_tri_layer_RGB(uint8_t layer1, uint8_t layer2, uint8_t layer3) {
+  if (IS_LAYER_ON(layer1) && IS_LAYER_ON(layer2)) {
+#ifdef RGBLIGHT_ENABLE
+    rgblight_mode(RGB_current_mode);
+#endif
+    layer_on(layer3);
+  } else {
+    layer_off(layer3);
+  }
+}
+
+const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
+{
+  // MACRODOWN only works in this function
+      switch(id) {
+        case 0:
+          if (record->event.pressed) {
+            register_code(KC_RSFT);
+          } else {
+            unregister_code(KC_RSFT);
+          }
+        break;
+      }
+    return MACRO_NONE;
+};
+
+
+void matrix_init_user(void) {
+
+}
+
+void matrix_scan_user(void) {
+
+}
+
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+  switch (keycode) {
+    case QWERTY:
+      if (record->event.pressed) {
+        #ifdef AUDIO_ENABLE
+          PLAY_NOTE_ARRAY(tone_qwerty, false, 0);
+        #endif
+//        persistent_default_layer_set(1UL<<_QWERTY);
+      }
+      return false;
+      break;
+    case COLEMAK:
+      if (record->event.pressed) {
+        #ifdef AUDIO_ENABLE
+          PLAY_NOTE_ARRAY(tone_colemak, false, 0);
+        #endif
+//        persistent_default_layer_set(1UL<<_COLEMAK);
+      }
+      return false;
+      break;
+    case DVORAK:
+      if (record->event.pressed) {
+        #ifdef AUDIO_ENABLE
+          PLAY_NOTE_ARRAY(tone_dvorak, false, 0);
+        #endif
+//        persistent_default_layer_set(1UL<<_DVORAK);
+      }
+      return false;
+      break;
+    case LOWER:
+        if (record->event.pressed) {
+            //not sure how to have keyboard check mode and set it to a variable, so my work around
+            //uses another variable that would be set to true after the first time a reactive key is pressed.
+            if (TOG_STATUS) { //TOG_STATUS checks is another reactive key currently pressed, only changes RGB mode if returns false
+            } else {
+                TOG_STATUS = !TOG_STATUS;
+#ifdef RGBLIGHT_ENABLE
+                rgblight_mode(16);
+#endif
+            }
+            layer_on(_LOWER);
+            update_tri_layer_RGB(_LOWER, _RAISE, _ADJUST);
+        } else {
+#ifdef RGBLIGHT_ENABLE
+            rgblight_mode(RGB_current_mode);   // revert RGB to initial mode prior to RGB mode change
+#endif
+            TOG_STATUS = false;
+            layer_off(_LOWER);
+            update_tri_layer_RGB(_LOWER, _RAISE, _ADJUST);
+        }
+        return false;
+        break;
+    case RAISE:
+        if (record->event.pressed) {
+            //not sure how to have keyboard check mode and set it to a variable, so my work around
+            //uses another variable that would be set to true after the first time a reactive key is pressed.
+            if (TOG_STATUS) { //TOG_STATUS checks is another reactive key currently pressed, only changes RGB mode if returns false
+            } else {
+                TOG_STATUS = !TOG_STATUS;
+#ifdef RGBLIGHT_ENABLE
+                rgblight_mode(15);
+#endif
+            }
+            layer_on(_RAISE);
+            update_tri_layer_RGB(_LOWER, _RAISE, _ADJUST);
+        } else {
+#ifdef RGBLIGHT_ENABLE
+            rgblight_mode(RGB_current_mode);  // revert RGB to initial mode prior to RGB mode change
+#endif
+            layer_off(_RAISE);
+            TOG_STATUS = false;
+            update_tri_layer_RGB(_LOWER, _RAISE, _ADJUST);
+        }
+        return false;
+        break;
+    case ADJUST:
+        // FIXME add RGB feedback
+        if (record->event.pressed) {
+            layer_on(_ADJUST);
+        } else {
+            layer_off(_ADJUST);
+        }
+        return false;
+        break;
+    case BL_TOGG:
+#ifdef ISSI_ENABLE
+        if (record->event.pressed) {
+            print("Enabling backlight\n");
+            issi_init();
+        }
+#endif
+        return false;
+        break;
+    case BL_STEP:
+        if (record->event.pressed) {
+            print("Stepping backlight\n");
+#ifdef BACKLIGHT_ENABLE
+            print("Really stepping backlight\n");
+            backlight_step();
+#endif
+
+        }
+        return false;
+        break;
+        //led operations - RGB mode change now updates the RGB_current_mode to allow the right RGB mode to be set after reactive keys are released
+#ifdef RGBLIGHT_ENABLE
+    case RGB_MOD:
+        if (record->event.pressed) {
+            rgblight_mode(RGB_current_mode);
+            rgblight_step();
+            RGB_current_mode = rgblight_config.mode;
+        }
+        return false;
+        break;
+#endif
+//    case BL_INC:
+//    		meira_inc_backlight_level();
+//    	      return false;
+//    		break;
+  }
+  return true;
+}
+
+void led_set_user(uint8_t usb_led) {
+
+}

+ 1 - 0
keyboards/meira/keymaps/default/readme.md

@@ -0,0 +1 @@
+# The default keymap for meira

+ 95 - 0
keyboards/meira/lighting.c

@@ -0,0 +1,95 @@
+#ifdef ISSI_ENABLE
+
+
+#include <avr/sfr_defs.h>
+#include <avr/timer_avr.h>
+#include <avr/wdt.h>
+#include "meira.h"
+#include "issi.h"
+#include "TWIlib.h"
+#include "lighting.h"
+#include "debug.h"
+#include "audio/audio.h"
+
+
+const uint8_t backlight_pwm_map[BACKLIGHT_LEVELS] = BACKLIGHT_PWM_MAP;
+
+    const uint8_t switch_matrices[] = {0, 1};
+
+    // Maps switch LEDs from Row/Col to ISSI matrix.
+    // Value breakdown:
+    //     Bit     | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+    //             |   | ISSI Col  |    ISSI Row   |
+    //             /   |
+    //             Device
+//    const uint8_t switch_leds[MATRIX_ROWS][MATRIX_COLS] =
+//    KEYMAP(
+//      0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0xA9, 0xA8, 0xA7, 0xA6, 0xA5,
+//      0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0xB9, 0xB8, 0xB7, 0xB6, 0xB5,
+//      0x49, 0x48, 0x47, 0x45, 0x44, 0x43, 0x42, 0x41, 0xC9, 0xC8, 0xC7, 0xC6,
+//      0x59, 0x58, 0x57, 0x56,       0x55,       0x51, 0xD6, 0xE5, 0xE4, 0xE3, 0xE2);
+
+void backlight_set(uint8_t level){
+#ifdef BACKLIGHT_ENABLE
+    uint8_t pwm_value = 0;
+    if(level >= BACKLIGHT_LEVELS){
+        level = BACKLIGHT_LEVELS;
+    }
+    if(level > 0){
+        pwm_value = backlight_pwm_map[level-1];
+    }
+    xprintf("BACKLIGHT_LEVELS: %d\n", BACKLIGHT_LEVELS);
+    xprintf("backlight_set level: %d pwm: %d\n", level, pwm_value);
+    for(int x = 1; x <= 9; x++){
+        for(int y = 1; y <= 9; y++){
+            activateLED(switch_matrices[0], x, y, pwm_value);
+            activateLED(switch_matrices[1], x, y, pwm_value);
+        }
+    }
+#endif
+}
+
+void set_backlight_by_keymap(uint8_t col, uint8_t row){
+//    dprintf("LED: %02X, %d %d %d\n", lookup_value, matrix, led_col, led_row);
+//    activateLED(matrix, led_col, led_row, 255);
+}
+
+void force_issi_refresh(){
+    issi_devices[0]->led_dirty = true;
+    update_issi(0, true);
+    issi_devices[3]->led_dirty = true;
+    update_issi(3, true);
+}
+
+void led_test(){
+#ifdef WATCHDOG_ENABLE
+    // This test take a long time to run, disable the WTD until its complete
+    wdt_disable();
+#endif
+    backlight_set(0);
+    force_issi_refresh();
+//    for(uint8_t x = 0; x < sizeof(rgb_sequence); x++){
+//        set_rgb(rgb_sequence[x], 255, 0, 0);
+//        force_issi_refresh();
+//        _delay_ms(250);
+//        set_rgb(rgb_sequence[x], 0, 255, 0);
+//        force_issi_refresh();
+//        _delay_ms(250);
+//        set_rgb(rgb_sequence[x], 0, 0, 255);
+//        force_issi_refresh();
+//        _delay_ms(250);
+//        set_rgb(rgb_sequence[x], 0, 0, 0);
+//        force_issi_refresh();
+//    }
+#ifdef WATCHDOG_ENABLE
+    wdt_enable(WDTO_250MS);
+#endif
+}
+
+void backlight_init_ports(void){
+    xprintf("backlight_init_ports\n");
+    issi_init();
+}
+
+#endif
+

+ 9 - 0
keyboards/meira/lighting.h

@@ -0,0 +1,9 @@
+#ifndef LIGHTING_H
+#define LIGHTING_H
+
+void led_test(void);
+void force_issi_refresh(void);
+void set_backlight(uint8_t level);
+void set_backlight_by_keymap(uint8_t col, uint8_t row);
+
+#endif

+ 314 - 0
keyboards/meira/matrix.c

@@ -0,0 +1,314 @@
+/*
+Copyright 2012 Jun Wako <wakojun@gmail.com>
+Copyright 2017 Cole Markham <cole@ccmcomputing.net>
+
+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>
+#if defined(__AVR__)
+#include <avr/io.h>
+#endif
+#include "meira.h"
+#include "wait.h"
+#include "print.h"
+#include "debug.h"
+#include "util.h"
+#include "matrix.h"
+#include "config.h"
+#include "timer.h"
+
+#ifndef DEBOUNCING_DELAY
+#   define DEBOUNCING_DELAY 5
+#endif
+
+#if (DEBOUNCING_DELAY > 0)
+    static uint16_t debouncing_time;
+    static bool debouncing = false;
+#endif
+
+#if (MATRIX_COLS <= 8)
+#    define print_matrix_header()  print("\nr/c 01234567\n")
+#    define print_matrix_row(row)  print_bin_reverse8(matrix_get_row(row))
+#    define matrix_bitpop(i)       bitpop(matrix[i])
+#    define ROW_SHIFTER ((uint8_t)1)
+#elif (MATRIX_COLS <= 16)
+#    define print_matrix_header()  print("\nr/c 0123456789ABCDEF\n")
+#    define print_matrix_row(row)  print_bin_reverse16(matrix_get_row(row))
+#    define matrix_bitpop(i)       bitpop16(matrix[i])
+#    define ROW_SHIFTER ((uint16_t)1)
+#elif (MATRIX_COLS <= 32)
+#    define print_matrix_header()  print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n")
+#    define print_matrix_row(row)  print_bin_reverse32(matrix_get_row(row))
+#    define matrix_bitpop(i)       bitpop32(matrix[i])
+#    define ROW_SHIFTER  ((uint32_t)1)
+#endif
+
+static matrix_row_t matrix_debouncing[MATRIX_ROWS];
+
+static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
+static const uint8_t col_pins[4] = MATRIX_COL_PINS;
+//static const uint8_t lrow_pins[MATRIX_ROWS] = LED_ROW_PINS;
+//static const uint8_t lcol_pins[4] = LED_COL_PINS;
+
+/* matrix state(1:on, 0:off) */
+static matrix_row_t matrix[MATRIX_ROWS];
+static matrix_row_t matrix_debouncing[MATRIX_ROWS];
+static void init_rows(void);
+//static void init_lcols(void);
+static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
+static void unselect_cols(void);
+static void select_col(uint8_t col);
+
+__attribute__ ((weak))
+void matrix_init_quantum(void) {
+    matrix_init_kb();
+}
+
+__attribute__ ((weak))
+void matrix_scan_quantum(void) {
+    matrix_scan_kb();
+}
+
+__attribute__ ((weak))
+void matrix_init_kb(void) {
+    matrix_init_user();
+}
+
+__attribute__ ((weak))
+void matrix_scan_kb(void) {
+    matrix_scan_user();
+}
+
+__attribute__ ((weak))
+void matrix_init_user(void) {
+}
+
+__attribute__ ((weak))
+void matrix_scan_user(void) {
+}
+
+inline
+uint8_t matrix_rows(void)
+{
+    return MATRIX_ROWS;
+}
+
+inline
+uint8_t matrix_cols(void)
+{
+    return MATRIX_COLS;
+}
+
+void matrix_init(void)
+{
+    debug_enable = true;
+    debug_matrix = true;
+    debug_mouse = true;
+    // initialize row and col
+    unselect_cols();
+    init_rows();
+//    init_lcols();
+
+//    TX_RX_LED_INIT;
+
+    // initialize matrix state: all keys off
+    for (uint8_t i=0; i < MATRIX_ROWS; i++) {
+        matrix[i] = 0;
+        matrix_debouncing[i] = 0;
+    }
+
+    matrix_init_quantum();
+
+}
+
+uint8_t _matrix_scan(void)
+{
+    // Set col, read rows
+    for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
+#       if (DEBOUNCING_DELAY > 0)
+            bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col);
+            if (matrix_changed) {
+                debouncing = true;
+                debouncing_time = timer_read();
+            }
+#       else
+             read_rows_on_col(matrix, current_col);
+#       endif
+
+    }
+
+#   if (DEBOUNCING_DELAY > 0)
+        if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
+            for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
+                matrix[i] = matrix_debouncing[i];
+            }
+            debouncing = false;
+        }
+#   endif
+
+	return 1;
+}
+
+uint8_t matrix_scan(void)
+{
+	uint8_t ret = _matrix_scan();
+	matrix_scan_quantum();
+//	// HACK backlighting
+//	for (uint8_t t = 0; t < meira_get_backlight_level(); t++) {
+//		for (uint8_t x = 0; x < 13; x++) {
+//			for (uint8_t y = 0; y < 4; y++) {
+//				uint8_t pin = lcol_pins[y];
+//				if ((x >> y) & 1) {
+//					_SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
+//				} else {
+//					_SFR_IO8((pin >> 4) + 2) &=  ~_BV(pin & 0xF); // LO
+//				}
+//			}
+//		}
+//	}
+	return ret;
+}
+
+bool matrix_is_modified(void)
+{
+    if (debouncing) return false;
+    return true;
+}
+
+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 0123456789ABCDEF\n");
+    for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+        phex(row); print(": ");
+        pbin_reverse16(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 += bitpop16(matrix[i]);
+    }
+    return count;
+}
+
+
+static void init_rows(void)
+{
+    for(uint8_t x = 0; x < MATRIX_ROWS; x++) {
+        uint8_t pin = row_pins[x];
+        _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
+        _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
+//        // HACK backlighting
+//        uint8_t lpin = lrow_pins[x];
+//        _SFR_IO8((lpin >> 4) + 1) |= _BV(lpin & 0xF); // OUT
+//        _SFR_IO8((lpin >> 4) + 2) |=  _BV(lpin & 0xF); // HI
+    }
+}
+
+//static void init_lcols(void)
+//{
+//	for (uint8_t x = 0; x < 4; x++) {
+//		uint8_t pin = lcol_pins[x];
+//		_SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT
+//		_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HIGH
+//	}
+//}
+
+static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
+{
+    bool matrix_changed = false;
+
+    // Select col and wait for col selection to stabilize
+    select_col(current_col);
+    wait_us(30);
+
+    // For each row...
+    for(uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++)
+    {
+
+        // Store last value of row prior to reading
+        matrix_row_t last_row_value = current_matrix[row_index];
+
+        // Check row pin state
+        if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)) == 0)
+        {
+            // Pin LO, set col bit
+            current_matrix[row_index] |= (ROW_SHIFTER << current_col);
+        }
+        else
+        {
+            // Pin HI, clear col bit
+            current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
+        }
+
+        // Determine if the matrix changed state
+        if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
+        {
+            matrix_changed = true;
+        }
+    }
+
+    // Unselect col
+    unselect_cols();
+
+    return matrix_changed;
+}
+
+static void select_col(uint8_t col)
+{
+#ifdef FLIPPED_BOARD
+	col = MATRIX_COLS - col - 1;
+#endif
+    for(uint8_t x = 0; x < 4; x++) {
+		uint8_t pin = col_pins[x];
+        _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT
+		if (((col >> x) & 0x1) == 1){
+			_SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HIGH
+		} else {
+			_SFR_IO8((pin >> 4) + 2) &=  ~_BV(pin & 0xF); // LOW
+		}
+	}
+}
+
+static void unselect_cols(void)
+{
+	// FIXME This really needs to use the global enable on the decoder, because currently this sets the value to col1
+    for(uint8_t x = 0; x < 4; x++) {
+        uint8_t pin = col_pins[x];
+        _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT
+        _SFR_IO8((pin >> 4) + 2) &=  ~_BV(pin & 0xF); // LOW
+    }
+}
+
+

+ 145 - 0
keyboards/meira/meira.c

@@ -0,0 +1,145 @@
+/* Copyright 2017 REPLACE_WITH_YOUR_NAME
+ *
+ * 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 "meira.h"
+#include "issi.h"
+#include "TWIlib.h"
+#include "lighting.h"
+#include "quantum.h"
+#define BACKLIGHT_BREATHING
+
+#ifdef AUDIO_ENABLE
+    float tone_startup[][2] = SONG(STARTUP_SOUND);
+    float tone_goodbye[][2] = SONG(GOODBYE_SOUND);
+#endif
+
+
+void shutdown_user(void) {
+    #ifdef AUDIO_ENABLE
+        PLAY_NOTE_ARRAY(tone_goodbye, false, 0);
+    _delay_ms(150);
+    stop_all_notes();
+    #endif
+}
+
+
+void matrix_init_kb(void)
+{
+    debug_enable=true;
+    print("meira matrix_init_kb\n");
+#ifdef AUDIO_ENABLE
+    _delay_ms(20); // gets rid of tick
+    PLAY_NOTE_ARRAY(tone_startup, false, 0);
+#endif
+
+
+#ifdef ISSI_ENABLE
+    issi_init();
+#endif
+    backlight_set(5);
+#ifdef WATCHDOG_ENABLE
+    // This is done after turning the layer LED red, if we're caught in a loop
+    // we should get a flashing red light
+    wdt_enable(WDTO_500MS);
+#endif
+
+
+    // put your keyboard start-up code here
+    // runs once when the firmware starts up
+    matrix_init_user();
+}
+
+void matrix_scan_kb(void)
+{
+#ifdef WATCHDOG_ENABLE
+    wdt_reset();
+#endif
+#ifdef ISSI_ENABLE
+    // switch/underglow lighting update
+    static uint32_t issi_device = 0;
+    static uint32_t twi_last_ready = 0;
+    if(twi_last_ready > 1000){
+        // Its been way too long since the last ISSI update, reset the I2C bus and start again
+        xprintf("TWI failed to recover, TWI re-init\n");
+        twi_last_ready = 0;
+        TWIInit();
+        force_issi_refresh();
+    }
+    if(isTWIReady()){
+        twi_last_ready = 0;
+        // If the i2c bus is available, kick off the issi update, alternate between devices
+        update_issi(issi_device, issi_device);
+        if(issi_device){
+            issi_device = 0;
+        }else{
+            issi_device = 3;
+        }
+    }else{
+        twi_last_ready++;
+    }
+#endif
+    matrix_scan_user();
+}
+
+bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
+    // Test code that turns on the switch led for the key that is pressed
+    // set_backlight_by_keymap(record->event.key.col, record->event.key.row);
+    if (keycode == RESET) {
+        reset_keyboard_kb();
+    } else {
+    }
+	return process_record_user(keycode, record);
+}
+
+void led_set_kb(uint8_t usb_led) {
+	// put your keyboard LED indicator (ex: Caps Lock LED) toggling code here
+	led_set_user(usb_led);
+}
+
+//void action_function(keyrecord_t *event, uint8_t id, uint8_t opt)
+//{
+//#ifdef AUDIO_ENABLE
+//    int8_t sign = 1;
+//#endif
+//    if(id == LFK_ESC_TILDE){
+//        // Send ~ on shift-esc
+//        void (*method)(uint8_t) = (event->event.pressed) ? &add_key : &del_key;
+//        uint8_t shifted = get_mods() & (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT));
+//        method(shifted ? KC_GRAVE : KC_ESCAPE);
+//        send_keyboard_report();
+//    }else if(event->event.pressed){
+//        switch(id){
+//            case LFK_CLEAR:
+//                // Go back to default layer
+//                layer_clear();
+//                break;
+//#ifdef ISSI_ENABLE
+//            case LFK_LED_TEST:
+//                led_test();
+//                break;
+//#endif
+//        }
+//    }
+//}
+
+void reset_keyboard_kb(){
+#ifdef WATCHDOG_ENABLE
+    MCUSR = 0;
+    wdt_disable();
+    wdt_reset();
+#endif
+    xprintf("programming!\n");
+    reset_keyboard();
+}

+ 48 - 0
keyboards/meira/meira.h

@@ -0,0 +1,48 @@
+/* Copyright 2017 Cole Markham
+ *
+ * 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 MEIRA_H
+#define MEIRA_H
+
+
+#ifdef SUBPROJECT_featherble
+    #include "featherble.h"
+#endif
+#ifdef SUBPROJECT_promicro
+    #include "promicro.h"
+#endif
+
+#include "quantum.h"
+
+void reset_keyboard_kb(void);
+
+// This a shortcut to help you visually see your layout.
+// The following is an example using the Planck MIT layout
+// The first section contains all of the arguments
+// The second converts the arguments into a two-dimensional array
+#define KEYMAP( \
+   k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0a, k0b, \
+	k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1a, k1b, \
+	k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k2a, k2b, \
+	k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k3a, k3b \
+) \
+{ \
+	{ k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0a, k0b }, \
+	{ k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1a, k1b }, \
+	{ k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k2a, k2b }, \
+	{ k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k3a, k3b } \
+}
+
+#endif

+ 168 - 0
keyboards/meira/promicro/config.h

@@ -0,0 +1,168 @@
+/*
+Copyright 2017 REPLACE_WITH_YOUR_NAME
+
+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 PROMICROCONFIG_H
+#define PROMICROCONFIG_H
+
+#include "config_common.h"
+
+
+/*
+ * Keyboard Matrix Assignments
+ *
+ * Change this to how you wired your keyboard
+ * COLS: AVR pins used for columns, left to right
+ * ROWS: AVR pins used for rows, top to bottom
+ * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode)
+ *                  ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
+ *
+*/
+#define MATRIX_ROW_PINS { F7, F6, F5, F4 }
+// Column pins to demux in LSB order
+#define MATRIX_COL_PINS { B1, B3, B2, B6 }
+#define LED_EN_PIN D2
+#define UNUSED_PINS
+
+#define CATERINA_BOOTLOADER
+
+/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
+#define DEBOUNCING_DELAY 5
+
+/* define if matrix has ghost (lacks anti-ghosting diodes) */
+//#define MATRIX_HAS_GHOST
+
+/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
+//#define LOCKING_SUPPORT_ENABLE
+/* Locking resynchronize hack */
+//#define LOCKING_RESYNC_ENABLE
+
+/*
+ * Force NKRO
+ *
+ * Force NKRO (nKey Rollover) to be enabled by default, regardless of the saved
+ * state in the bootmagic EEPROM settings. (Note that NKRO must be enabled in the
+ * makefile for this to work.)
+ *
+ * If forced on, NKRO can be disabled via magic key (default = LShift+RShift+N)
+ * until the next keyboard reset.
+ *
+ * NKRO may prevent your keystrokes from being detected in the BIOS, but it is
+ * fully operational during normal computer usage.
+ *
+ * For a less heavy-handed approach, enable NKRO via magic key (LShift+RShift+N)
+ * or via bootmagic (hold SPACE+N while plugging in the keyboard). Once set by
+ * bootmagic, NKRO mode will always be enabled until it is toggled again during a
+ * power-up.
+ *
+ */
+//#define FORCE_NKRO
+
+/*
+ * Magic Key Options
+ *
+ * Magic keys are hotkey commands that allow control over firmware functions of
+ * the keyboard. They are best used in combination with the HID Listen program,
+ * found here: https://www.pjrc.com/teensy/hid_listen.html
+ *
+ * The options below allow the magic key functionality to be changed. This is
+ * useful if your keyboard/keypad is missing keys and you want magic key support.
+ *
+ */
+
+/* key combination for magic key command */
+#define IS_COMMAND() ( \
+    keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
+)
+
+/* control how magic key switches layers */
+//#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS  true
+//#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS  true
+//#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM false
+
+/* override magic key keymap */
+//#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
+//#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
+//#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
+//#define MAGIC_KEY_HELP1          H
+//#define MAGIC_KEY_HELP2          SLASH
+//#define MAGIC_KEY_DEBUG          D
+//#define MAGIC_KEY_DEBUG_MATRIX   X
+//#define MAGIC_KEY_DEBUG_KBD      K
+//#define MAGIC_KEY_DEBUG_MOUSE    M
+//#define MAGIC_KEY_VERSION        V
+//#define MAGIC_KEY_STATUS         S
+//#define MAGIC_KEY_CONSOLE        C
+//#define MAGIC_KEY_LAYER0_ALT1    ESC
+//#define MAGIC_KEY_LAYER0_ALT2    GRAVE
+//#define MAGIC_KEY_LAYER0         0
+//#define MAGIC_KEY_LAYER1         1
+//#define MAGIC_KEY_LAYER2         2
+//#define MAGIC_KEY_LAYER3         3
+//#define MAGIC_KEY_LAYER4         4
+//#define MAGIC_KEY_LAYER5         5
+//#define MAGIC_KEY_LAYER6         6
+//#define MAGIC_KEY_LAYER7         7
+//#define MAGIC_KEY_LAYER8         8
+//#define MAGIC_KEY_LAYER9         9
+//#define MAGIC_KEY_BOOTLOADER     PAUSE
+//#define MAGIC_KEY_LOCK           CAPS
+//#define MAGIC_KEY_EEPROM         E
+//#define MAGIC_KEY_NKRO           N
+//#define MAGIC_KEY_SLEEP_LED      Z
+
+/*
+ * 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
+
+/*
+ * MIDI options
+ */
+
+/* Prevent use of disabled MIDI features in the keymap */
+//#define MIDI_ENABLE_STRICT 1
+
+/* enable basic MIDI features:
+   - MIDI notes can be sent when in Music mode is on
+*/
+//#define MIDI_BASIC
+
+/* enable advanced MIDI features:
+   - MIDI notes can be added to the keymap
+   - Octave shift and transpose
+   - Virtual sustain, portamento, and modulation wheel
+   - etc.
+*/
+//#define MIDI_ADVANCED
+
+/* override number of MIDI tone keycodes (each octave adds 12 keycodes and allocates 12 bytes) */
+//#define MIDI_TONE_KEYCODE_OCTAVES 1
+
+#endif

+ 2 - 0
keyboards/meira/promicro/promicro.c

@@ -0,0 +1,2 @@
+#include "meira.h"
+

+ 10 - 0
keyboards/meira/promicro/promicro.h

@@ -0,0 +1,10 @@
+#ifndef FEATHERBLE_H
+#define FEATHERBLE_H
+
+#include "../meira.h"
+
+#include "quantum.h"
+
+#include "pro_micro.h"
+
+#endif

+ 2 - 0
keyboards/meira/promicro/rules.mk

@@ -0,0 +1,2 @@
+BLUETOOTH_ENABLE = no
+BACKLIGHT_ENABLE = yes

+ 28 - 0
keyboards/meira/readme.md

@@ -0,0 +1,28 @@
+meira keyboard firmware
+======================
+
+## Quantum MK Firmware
+
+For the full Quantum feature list, see [the parent readme](/).
+
+## Building
+
+Download or clone the whole firmware and navigate to the keyboards/meira folder. Once your dev env is setup, you'll be able to type `make` to generate your .hex - you can then use the Teensy Loader to program your .hex file. 
+
+Depending on which keymap you would like to use, you will have to compile slightly differently.
+
+### Default
+
+To build with the default keymap, simply run `make default`.
+
+### Other Keymaps
+
+Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create a folder with the name of your keymap in the keymaps folder, and see keymap documentation (you can find in top readme.md) and existant keymap files.
+
+To build the firmware binary hex file with a keymap just do `make` with a keymap like this:
+
+```
+$ make [default|jack|<name>]
+```
+
+Keymaps follow the format **__\<name\>.c__** and are stored in the `keymaps` folder.

+ 84 - 0
keyboards/meira/rules.mk

@@ -0,0 +1,84 @@
+SRC += matrix.c TWIlib.c issi.c lighting.c
+
+# MCU name
+#MCU = at90usb1286
+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=512
+
+
+# Build Options
+#   change yes to no to disable
+#
+BOOTMAGIC_ENABLE ?= no      # 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
+# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
+SLEEP_LED_ENABLE ?= no       # Breathing sleep LED during USB suspend
+# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
+NKRO_ENABLE ?= no            # USB Nkey Rollover
+BACKLIGHT_ENABLE = yes       # Enable keyboard backlight functionality on B7 by default
+MIDI_ENABLE ?= no            # MIDI support (+2400 to 4200, depending on config)
+UNICODE_ENABLE ?= no         # Unicode
+BLUETOOTH_ENABLE ?= no       # Enable Bluetooth with the Adafruit EZ-Key HID
+AUDIO_ENABLE ?= no           # Audio output on port C6
+RGBLIGHT_ENABLE ?= no       # Enable WS2812 RGB underlight.  Do not enable this with audio at the same time.
+FAUXCLICKY_ENABLE ?= no      # Use buzzer to emulate clicky switches
+
+ISSI_ENABLE = yes			# If the I2C pullup resistors aren't install this must be disabled
+#WATCHDOG_ENABLE = yes		# Resets keyboard if matrix_scan isn't run every 250ms
+
+CUSTOM_MATRIX = yes
+
+ifeq ($(strip $(ISSI_ENABLE)), yes)
+    TMK_COMMON_DEFS += -DISSI_ENABLE
+endif
+
+ifeq ($(strip $(WATCHDOG_ENABLE)), yes)
+    TMK_COMMON_DEFS += -DWATCHDOG_ENABLE
+endif