~ruther/qmk_firmware

a9a46adba0e005f6fecfb5ed47fe8a5eec4b06f4 — Cole Markham 7 years ago c51dfef
Add support for Meira
A keyboards/meira/TWIlib.c => keyboards/meira/TWIlib.c +287 -0
@@ 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;
	}

}

A keyboards/meira/TWIlib.h => keyboards/meira/TWIlib.h +81 -0
@@ 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_
\ No newline at end of file

A keyboards/meira/config.h => keyboards/meira/config.h +53 -0
@@ 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

A keyboards/meira/featherble/config.h => keyboards/meira/featherble/config.h +175 -0
@@ 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

A keyboards/meira/featherble/featherble.c => keyboards/meira/featherble/featherble.c +1 -0
@@ 0,0 1,1 @@
#include "meira.h"

A keyboards/meira/featherble/featherble.h => keyboards/meira/featherble/featherble.h +9 -0
@@ 0,0 1,9 @@
#ifndef FEATHERBLE_H
#define FEATHERBLE_H

#include "../meira.h"

#include "quantum.h"


#endif

A keyboards/meira/featherble/rules.mk => keyboards/meira/featherble/rules.mk +4 -0
@@ 0,0 1,4 @@
BLUETOOTH_ENABLE = yes
BACKLIGHT_ENABLE = yes
F_CPU = 8000000


A keyboards/meira/issi.c => keyboards/meira/issi.c +286 -0
@@ 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

A keyboards/meira/issi.h => keyboards/meira/issi.h +40 -0
@@ 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
\ No newline at end of file

A keyboards/meira/keymaps/default/config.h => keyboards/meira/keymaps/default/config.h +24 -0
@@ 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

A keyboards/meira/keymaps/default/keymap.c => keyboards/meira/keymaps/default/keymap.c +320 -0
@@ 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) {

}

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

A keyboards/meira/lighting.c => keyboards/meira/lighting.c +95 -0
@@ 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


A keyboards/meira/lighting.h => keyboards/meira/lighting.h +9 -0
@@ 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

A keyboards/meira/matrix.c => keyboards/meira/matrix.c +314 -0
@@ 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
    }
}



A keyboards/meira/meira.c => keyboards/meira/meira.c +145 -0
@@ 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();
}

A keyboards/meira/meira.h => keyboards/meira/meira.h +48 -0
@@ 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

A keyboards/meira/promicro/config.h => keyboards/meira/promicro/config.h +168 -0
@@ 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

A keyboards/meira/promicro/promicro.c => keyboards/meira/promicro/promicro.c +2 -0
@@ 0,0 1,2 @@
#include "meira.h"


A keyboards/meira/promicro/promicro.h => keyboards/meira/promicro/promicro.h +10 -0
@@ 0,0 1,10 @@
#ifndef FEATHERBLE_H
#define FEATHERBLE_H

#include "../meira.h"

#include "quantum.h"

#include "pro_micro.h"

#endif

A keyboards/meira/promicro/rules.mk => keyboards/meira/promicro/rules.mk +2 -0
@@ 0,0 1,2 @@
BLUETOOTH_ENABLE = no
BACKLIGHT_ENABLE = yes

A keyboards/meira/readme.md => keyboards/meira/readme.md +28 -0
@@ 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.

A keyboards/meira/rules.mk => keyboards/meira/rules.mk +84 -0
@@ 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