forked from mfulz_github/qmk_firmware
		
	Remove legacy AVR ssd1306 driver (#17864)
This commit is contained in:
		
							parent
							
								
									f7aaed1b57
								
							
						
					
					
						commit
						98d5c77521
					
				@ -1,159 +0,0 @@
 | 
				
			|||||||
#include <util/twi.h>
 | 
					 | 
				
			||||||
#include <avr/io.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <avr/interrupt.h>
 | 
					 | 
				
			||||||
#include <util/twi.h>
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					 | 
				
			||||||
#include "i2c.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Limits the amount of we wait for any one i2c transaction.
 | 
					 | 
				
			||||||
// Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is
 | 
					 | 
				
			||||||
// 9 bits, a single transaction will take around 90μs to complete.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// (F_CPU/SCL_CLOCK)  =>  # of μC cycles to transfer a bit
 | 
					 | 
				
			||||||
// poll loop takes at least 8 clock cycles to execute
 | 
					 | 
				
			||||||
#define I2C_LOOP_TIMEOUT (9+1)*(F_CPU/SCL_CLOCK)/8
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define BUFFER_POS_INC() (slave_buffer_pos = (slave_buffer_pos+1)%SLAVE_BUFFER_SIZE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static volatile uint8_t slave_buffer_pos;
 | 
					 | 
				
			||||||
static volatile bool slave_has_register_set = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Wait for an i2c operation to finish
 | 
					 | 
				
			||||||
inline static
 | 
					 | 
				
			||||||
void i2c_delay(void) {
 | 
					 | 
				
			||||||
  uint16_t lim = 0;
 | 
					 | 
				
			||||||
  while(!(TWCR & (1<<TWINT)) && lim < I2C_LOOP_TIMEOUT)
 | 
					 | 
				
			||||||
    lim++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // easier way, but will wait slightly longer
 | 
					 | 
				
			||||||
  // _delay_us(100);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Setup twi to run at 100kHz
 | 
					 | 
				
			||||||
void i2c_master_init(void) {
 | 
					 | 
				
			||||||
  // no prescaler
 | 
					 | 
				
			||||||
  TWSR = 0;
 | 
					 | 
				
			||||||
  // Set TWI clock frequency to SCL_CLOCK. Need TWBR>10.
 | 
					 | 
				
			||||||
  // Check datasheets for more info.
 | 
					 | 
				
			||||||
  TWBR = ((F_CPU/SCL_CLOCK)-16)/2;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Start a transaction with the given i2c slave address. The direction of the
 | 
					 | 
				
			||||||
// transfer is set with I2C_READ and I2C_WRITE.
 | 
					 | 
				
			||||||
// returns: 0 => success
 | 
					 | 
				
			||||||
//          1 => error
 | 
					 | 
				
			||||||
uint8_t i2c_master_start(uint8_t address) {
 | 
					 | 
				
			||||||
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  i2c_delay();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // check that we started successfully
 | 
					 | 
				
			||||||
  if ( (TW_STATUS != TW_START) && (TW_STATUS != TW_REP_START))
 | 
					 | 
				
			||||||
    return 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  TWDR = address;
 | 
					 | 
				
			||||||
  TWCR = (1<<TWINT) | (1<<TWEN);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  i2c_delay();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) )
 | 
					 | 
				
			||||||
    return 1; // slave did not acknowledge
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
    return 0; // success
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Finish the i2c transaction.
 | 
					 | 
				
			||||||
void i2c_master_stop(void) {
 | 
					 | 
				
			||||||
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  uint16_t lim = 0;
 | 
					 | 
				
			||||||
  while(!(TWCR & (1<<TWSTO)) && lim < I2C_LOOP_TIMEOUT)
 | 
					 | 
				
			||||||
    lim++;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Write one byte to the i2c slave.
 | 
					 | 
				
			||||||
// returns 0 => slave ACK
 | 
					 | 
				
			||||||
//         1 => slave NACK
 | 
					 | 
				
			||||||
uint8_t i2c_master_write(uint8_t data) {
 | 
					 | 
				
			||||||
  TWDR = data;
 | 
					 | 
				
			||||||
  TWCR = (1<<TWINT) | (1<<TWEN);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  i2c_delay();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // check if the slave acknowledged us
 | 
					 | 
				
			||||||
  return (TW_STATUS == TW_MT_DATA_ACK) ? 0 : 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Read one byte from the i2c slave. If ack=1 the slave is acknowledged,
 | 
					 | 
				
			||||||
// if ack=0 the acknowledge bit is not set.
 | 
					 | 
				
			||||||
// returns: byte read from i2c device
 | 
					 | 
				
			||||||
uint8_t i2c_master_read(int ack) {
 | 
					 | 
				
			||||||
  TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  i2c_delay();
 | 
					 | 
				
			||||||
  return TWDR;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void i2c_reset_state(void) {
 | 
					 | 
				
			||||||
  TWCR = 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void i2c_slave_init(uint8_t address) {
 | 
					 | 
				
			||||||
  TWAR = address << 0; // slave i2c address
 | 
					 | 
				
			||||||
  // TWEN  - twi enable
 | 
					 | 
				
			||||||
  // TWEA  - enable address acknowledgement
 | 
					 | 
				
			||||||
  // TWINT - twi interrupt flag
 | 
					 | 
				
			||||||
  // TWIE  - enable the twi interrupt
 | 
					 | 
				
			||||||
  TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ISR(TWI_vect);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ISR(TWI_vect) {
 | 
					 | 
				
			||||||
  uint8_t ack = 1;
 | 
					 | 
				
			||||||
  switch(TW_STATUS) {
 | 
					 | 
				
			||||||
    case TW_SR_SLA_ACK:
 | 
					 | 
				
			||||||
      // this device has been addressed as a slave receiver
 | 
					 | 
				
			||||||
      slave_has_register_set = false;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case TW_SR_DATA_ACK:
 | 
					 | 
				
			||||||
      // this device has received data as a slave receiver
 | 
					 | 
				
			||||||
      // The first byte that we receive in this transaction sets the location
 | 
					 | 
				
			||||||
      // of the read/write location of the slaves memory that it exposes over
 | 
					 | 
				
			||||||
      // i2c.  After that, bytes will be written at slave_buffer_pos, incrementing
 | 
					 | 
				
			||||||
      // slave_buffer_pos after each write.
 | 
					 | 
				
			||||||
      if(!slave_has_register_set) {
 | 
					 | 
				
			||||||
        slave_buffer_pos = TWDR;
 | 
					 | 
				
			||||||
        // don't acknowledge the master if this memory loctaion is out of bounds
 | 
					 | 
				
			||||||
        if ( slave_buffer_pos >= SLAVE_BUFFER_SIZE ) {
 | 
					 | 
				
			||||||
          ack = 0;
 | 
					 | 
				
			||||||
          slave_buffer_pos = 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        slave_has_register_set = true;
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        i2c_slave_buffer[slave_buffer_pos] = TWDR;
 | 
					 | 
				
			||||||
        BUFFER_POS_INC();
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case TW_ST_SLA_ACK:
 | 
					 | 
				
			||||||
    case TW_ST_DATA_ACK:
 | 
					 | 
				
			||||||
      // master has addressed this device as a slave transmitter and is
 | 
					 | 
				
			||||||
      // requesting data.
 | 
					 | 
				
			||||||
      TWDR = i2c_slave_buffer[slave_buffer_pos];
 | 
					 | 
				
			||||||
      BUFFER_POS_INC();
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case TW_BUS_ERROR: // something went wrong, reset twi state
 | 
					 | 
				
			||||||
      TWCR = 0;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // Reset everything, so we are ready for the next TWI interrupt
 | 
					 | 
				
			||||||
  TWCR |= (1<<TWIE) | (1<<TWINT) | (ack<<TWEA) | (1<<TWEN);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,28 +0,0 @@
 | 
				
			|||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef F_CPU
 | 
					 | 
				
			||||||
#define F_CPU 16000000UL
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define I2C_READ 1
 | 
					 | 
				
			||||||
#define I2C_WRITE 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define I2C_ACK 1
 | 
					 | 
				
			||||||
#define I2C_NACK 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define SLAVE_BUFFER_SIZE 0x10
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// i2c SCL clock frequency
 | 
					 | 
				
			||||||
#define SCL_CLOCK  400000L
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void i2c_master_init(void);
 | 
					 | 
				
			||||||
uint8_t i2c_master_start(uint8_t address);
 | 
					 | 
				
			||||||
void i2c_master_stop(void);
 | 
					 | 
				
			||||||
uint8_t i2c_master_write(uint8_t data);
 | 
					 | 
				
			||||||
uint8_t i2c_master_read(int);
 | 
					 | 
				
			||||||
void i2c_reset_state(void);
 | 
					 | 
				
			||||||
void i2c_slave_init(uint8_t address);
 | 
					 | 
				
			||||||
@ -1,58 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
This is the c configuration file for the keymap
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Copyright 2012 Jun Wako <wakojun@gmail.com>
 | 
					 | 
				
			||||||
Copyright 2015 Jack Humbert
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This program is free software: you can redistribute it and/or modify
 | 
					 | 
				
			||||||
it under the terms of the GNU General Public License as published by
 | 
					 | 
				
			||||||
the Free Software Foundation, either version 2 of the License, or
 | 
					 | 
				
			||||||
(at your option) any later version.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This program is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
GNU General Public License for more details.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
You should have received a copy of the GNU General Public License
 | 
					 | 
				
			||||||
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef CONFIG_USER_H
 | 
					 | 
				
			||||||
#define CONFIG_USER_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "../../config.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Use I2C or Serial, not both */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define USE_I2C
 | 
					 | 
				
			||||||
//#define USE_SERIAL
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Select hand configuration */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define MASTER_LEFT
 | 
					 | 
				
			||||||
// #define MASTER_RIGHT
 | 
					 | 
				
			||||||
// #define EE_HANDS
 | 
					 | 
				
			||||||
#define FLIP_HALF
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define SSD1306OLED
 | 
					 | 
				
			||||||
//#define OLED_ROTATE180
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define TAPPING_FORCE_HOLD
 | 
					 | 
				
			||||||
#define TAPPING_TERM 100
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef SUBPROJECT_rev1
 | 
					 | 
				
			||||||
    #include "../../rev1/config.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef SUBPROJECT_rev2
 | 
					 | 
				
			||||||
    #include "../../rev2/config.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#undef RGBLED_NUM
 | 
					 | 
				
			||||||
#define RGBLIGHT_ANIMATIONS
 | 
					 | 
				
			||||||
#define RGBLED_NUM 6
 | 
					 | 
				
			||||||
#define RGBLIGHT_HUE_STEP 10
 | 
					 | 
				
			||||||
#define RGBLIGHT_SAT_STEP 17
 | 
					 | 
				
			||||||
#define RGBLIGHT_VAL_STEP 17
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
@ -1,415 +0,0 @@
 | 
				
			|||||||
#include QMK_KEYBOARD_H
 | 
					 | 
				
			||||||
#include <LUFA/Drivers/Peripheral/TWI.h>
 | 
					 | 
				
			||||||
#ifdef SSD1306OLED
 | 
					 | 
				
			||||||
  #include "ssd1306.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern keymap_config_t keymap_config;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//Following line allows macro to read current RGB settings
 | 
					 | 
				
			||||||
extern rgblight_config_t rgblight_config;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Each layer gets a name for readability, which is then used in the keymap matrix below.
 | 
					 | 
				
			||||||
// The underscores don't mean anything - you can have a layer called STUFF or any other name.
 | 
					 | 
				
			||||||
// Layer names don't all need to be of the same length, obviously, and you can also skip them
 | 
					 | 
				
			||||||
// entirely and just use numbers.
 | 
					 | 
				
			||||||
#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,
 | 
					 | 
				
			||||||
  BACKLIT,
 | 
					 | 
				
			||||||
  RGBLED_TOGGLE,
 | 
					 | 
				
			||||||
  RGBLED_STEP_MODE,
 | 
					 | 
				
			||||||
  RGBLED_INCREASE_HUE,
 | 
					 | 
				
			||||||
  RGBLED_DECREASE_HUE,
 | 
					 | 
				
			||||||
  RGBLED_INCREASE_SAT,
 | 
					 | 
				
			||||||
  RGBLED_DECREASE_SAT,
 | 
					 | 
				
			||||||
  RGBLED_INCREASE_VAL,
 | 
					 | 
				
			||||||
  RGBLED_DECREASE_VAL,
 | 
					 | 
				
			||||||
  M_SAMPLE
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Qwerty
 | 
					 | 
				
			||||||
 * ,-----------------------------------------------------------------------------------.
 | 
					 | 
				
			||||||
 * | Tab  |   Q  |   W  |   E  |   R  |   T  |   Y  |   U  |   I  |   O  |   P  | Bksp |
 | 
					 | 
				
			||||||
 * |------+------+------+------+------+-------------+------+------+------+------+------|
 | 
					 | 
				
			||||||
 * | Esc  |   A  |   S  |   D  |   F  |   G  |   H  |   J  |   K  |   L  |   ;  |  "   |
 | 
					 | 
				
			||||||
 * |------+------+------+------+------+------|------+------+------+------+------+------|
 | 
					 | 
				
			||||||
 * | Shift|   Z  |   X  |   C  |   V  |   B  |   N  |   M  |   ,  |   .  |   /  |Enter |
 | 
					 | 
				
			||||||
 * |------+------+------+------+------+------+------+------+------+------+------+------|
 | 
					 | 
				
			||||||
 * |Adjust| Ctrl | Alt  | GUI  |Lower |Space |Space |Raise | Left | Down |  Up  |Right |
 | 
					 | 
				
			||||||
 * `-----------------------------------------------------------------------------------'
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
[_QWERTY] = LAYOUT( \
 | 
					 | 
				
			||||||
  KC_TAB,  KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,    KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,    KC_BSPC, \
 | 
					 | 
				
			||||||
  KC_ESC,  KC_A,    KC_S,    KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT, \
 | 
					 | 
				
			||||||
  KC_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_LGUI, LOWER,   KC_SPC,  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] = LAYOUT( \
 | 
					 | 
				
			||||||
  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] = LAYOUT( \
 | 
					 | 
				
			||||||
  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 |
 | 
					 | 
				
			||||||
 * |------+------+------+------+------+-------------+------+------+------+------+------|
 | 
					 | 
				
			||||||
 * | Del  |  F1  |  F2  |  F3  |  F4  |  F5  |  F6  |   _  |   +  |     |    \  |  |   |
 | 
					 | 
				
			||||||
 * |------+------+------+------+------+------|------+------+------+------+------+------|
 | 
					 | 
				
			||||||
 * |      |  F7  |  F8  |  F9  |  F10 |  F11 |  F12 |ISO ~ |ISO | |      |      |Enter |
 | 
					 | 
				
			||||||
 * |------+------+------+------+------+------+------+------+------+------+------+------|
 | 
					 | 
				
			||||||
 * |      |      |      |      |      |             |      | Next | Vol- | Vol+ | Play |
 | 
					 | 
				
			||||||
 * `-----------------------------------------------------------------------------------'
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
[_LOWER] = LAYOUT( \
 | 
					 | 
				
			||||||
  KC_TILD, KC_EXLM, KC_AT,   KC_HASH, KC_DLR,  KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC, \
 | 
					 | 
				
			||||||
  KC_DEL,  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_MNXT, KC_VOLD, KC_VOLU, KC_MPLY \
 | 
					 | 
				
			||||||
),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Raise
 | 
					 | 
				
			||||||
 * ,-----------------------------------------------------------------------------------.
 | 
					 | 
				
			||||||
 * |   `  |   1  |   2  |   3  |   4  |   5  |   6  |   7  |   8  |   9  |   0  | Bksp |
 | 
					 | 
				
			||||||
 * |------+------+------+------+------+-------------+------+------+------+------+------|
 | 
					 | 
				
			||||||
 * | Del  |  F1  |  F2  |  F3  |  F4  |  F5  |  F6  |   -  |   =  |   [  |   ]  |  \   |
 | 
					 | 
				
			||||||
 * |------+------+------+------+------+------|------+------+------+------+------+------|
 | 
					 | 
				
			||||||
 * |      |  F7  |  F8  |  F9  |  F10 |  F11 |  F12 |ISO # |ISO / |      |      |Enter |
 | 
					 | 
				
			||||||
 * |------+------+------+------+------+------+------+------+------+------+------+------|
 | 
					 | 
				
			||||||
 * |      |      |      |      |      |             |      | Next | Vol- | Vol+ | Play |
 | 
					 | 
				
			||||||
 * `-----------------------------------------------------------------------------------'
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
[_RAISE] = LAYOUT( \
 | 
					 | 
				
			||||||
  KC_GRV,  KC_1,    KC_2,    KC_3,    KC_4,    KC_5,    KC_6,    KC_7,    KC_8,    KC_9,    KC_0,    KC_BSPC, \
 | 
					 | 
				
			||||||
  KC_DEL,  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_MNXT, KC_VOLD, KC_VOLU, KC_MPLY \
 | 
					 | 
				
			||||||
),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Adjust (Lower + Raise)
 | 
					 | 
				
			||||||
 * ,-----------------------------------------------------------------------------------.
 | 
					 | 
				
			||||||
 * |      | Reset|      |      |      |      |      |      |      |      |      |  Del |
 | 
					 | 
				
			||||||
 * |------+------+------+------+------+-------------+------+------+------+------+------|
 | 
					 | 
				
			||||||
 * |      |      |      |Aud on|Audoff|AGnorm|AGswap|Qwerty|Colemk|Dvorak|      |      |
 | 
					 | 
				
			||||||
 * |------+------+------+------+------+------|------+------+------+------+------+------|
 | 
					 | 
				
			||||||
 * |      |      |      |      |      |      |      |      |      |      |      |      |
 | 
					 | 
				
			||||||
 * |------+------+------+------+------+------+------+------+------+------+------+------|
 | 
					 | 
				
			||||||
 * |      |      |      |      |      |             |      |      |      |      |      |
 | 
					 | 
				
			||||||
 * `-----------------------------------------------------------------------------------'
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
[_ADJUST] =  LAYOUT( \
 | 
					 | 
				
			||||||
  _______, RESET,   _______, M_SAMPLE, _______, _______, _______, _______, _______, _______, _______, KC_DEL, \
 | 
					 | 
				
			||||||
  _______, _______, _______, AU_ON,   AU_OFF,  AG_NORM, AG_SWAP, QWERTY,  COLEMAK, DVORAK,  _______, _______, \
 | 
					 | 
				
			||||||
  _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
 | 
					 | 
				
			||||||
  _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ \
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef AUDIO_ENABLE
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
float tone_startup[][2]    = SONG(STARTUP_SOUND);
 | 
					 | 
				
			||||||
float tone_qwerty[][2]     = SONG(QWERTY_SOUND);
 | 
					 | 
				
			||||||
float tone_dvorak[][2]     = SONG(DVORAK_SOUND);
 | 
					 | 
				
			||||||
float tone_colemak[][2]    = SONG(COLEMAK_SOUND);
 | 
					 | 
				
			||||||
float tone_plover[][2]     = SONG(PLOVER_SOUND);
 | 
					 | 
				
			||||||
float tone_plover_gb[][2]  = SONG(PLOVER_GOODBYE_SOUND);
 | 
					 | 
				
			||||||
float music_scale[][2]     = SONG(MUSIC_SCALE_SOUND);
 | 
					 | 
				
			||||||
float tone_goodbye[][2]    = SONG(GOODBYE_SOUND);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// define variables for reactive RGB
 | 
					 | 
				
			||||||
bool TOG_STATUS = false;
 | 
					 | 
				
			||||||
int RGB_current_mode;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void persistent_default_layer_set(uint16_t default_layer) {
 | 
					 | 
				
			||||||
  eeconfig_update_default_layer(default_layer);
 | 
					 | 
				
			||||||
  default_layer_set(default_layer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 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)) {
 | 
					 | 
				
			||||||
    rgblight_mode(RGB_current_mode);
 | 
					 | 
				
			||||||
    layer_on(layer3);
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    layer_off(layer3);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
 | 
					 | 
				
			||||||
  switch (keycode) {
 | 
					 | 
				
			||||||
    case QWERTY:
 | 
					 | 
				
			||||||
      if (record->event.pressed) {
 | 
					 | 
				
			||||||
        #ifdef AUDIO_ENABLE
 | 
					 | 
				
			||||||
          PLAY_SONG(tone_qwerty);
 | 
					 | 
				
			||||||
        #endif
 | 
					 | 
				
			||||||
        persistent_default_layer_set(1UL<<_QWERTY);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case COLEMAK:
 | 
					 | 
				
			||||||
      if (record->event.pressed) {
 | 
					 | 
				
			||||||
        #ifdef AUDIO_ENABLE
 | 
					 | 
				
			||||||
          PLAY_SONG(tone_colemak);
 | 
					 | 
				
			||||||
        #endif
 | 
					 | 
				
			||||||
        persistent_default_layer_set(1UL<<_COLEMAK);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case DVORAK:
 | 
					 | 
				
			||||||
      if (record->event.pressed) {
 | 
					 | 
				
			||||||
        #ifdef AUDIO_ENABLE
 | 
					 | 
				
			||||||
          PLAY_SONG(tone_dvorak);
 | 
					 | 
				
			||||||
        #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;
 | 
					 | 
				
			||||||
          rgblight_mode(16);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        layer_on(_LOWER);
 | 
					 | 
				
			||||||
        update_tri_layer_RGB(_LOWER, _RAISE, _ADJUST);
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        rgblight_mode(RGB_current_mode);   // revert RGB to initial mode prior to RGB mode change
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
          rgblight_mode(15);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        layer_on(_RAISE);
 | 
					 | 
				
			||||||
        update_tri_layer_RGB(_LOWER, _RAISE, _ADJUST);
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        rgblight_mode(RGB_current_mode);  // revert RGB to initial mode prior to RGB mode change
 | 
					 | 
				
			||||||
        layer_off(_RAISE);
 | 
					 | 
				
			||||||
        TOG_STATUS = false;
 | 
					 | 
				
			||||||
        update_tri_layer_RGB(_LOWER, _RAISE, _ADJUST);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case BACKLIT:
 | 
					 | 
				
			||||||
      if (record->event.pressed) {
 | 
					 | 
				
			||||||
        register_code(KC_RSFT);
 | 
					 | 
				
			||||||
        #ifdef BACKLIGHT_ENABLE
 | 
					 | 
				
			||||||
          backlight_step();
 | 
					 | 
				
			||||||
        #endif
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        unregister_code(KC_RSFT);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      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
 | 
					 | 
				
			||||||
    case RGB_MOD:
 | 
					 | 
				
			||||||
      if (record->event.pressed) {
 | 
					 | 
				
			||||||
        rgblight_mode(RGB_current_mode);
 | 
					 | 
				
			||||||
        rgblight_step();
 | 
					 | 
				
			||||||
        RGB_current_mode = rgblight_config.mode;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case M_SAMPLE:
 | 
					 | 
				
			||||||
      if (record->event.pressed){
 | 
					 | 
				
			||||||
        SEND_STRING("hello world");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void matrix_init_user(void) {
 | 
					 | 
				
			||||||
    #ifdef AUDIO_ENABLE
 | 
					 | 
				
			||||||
        startup_user();
 | 
					 | 
				
			||||||
    #endif
 | 
					 | 
				
			||||||
    RGB_current_mode = rgblight_config.mode;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//SSD1306 OLED init and update loop, make sure to add #define SSD1306OLED in config.h
 | 
					 | 
				
			||||||
#ifdef SSD1306OLED
 | 
					 | 
				
			||||||
void matrix_master_OLED_init (void) {
 | 
					 | 
				
			||||||
    TWI_Init(TWI_BIT_PRESCALE_1, TWI_BITLENGTH_FROM_FREQ(1, 800000));
 | 
					 | 
				
			||||||
    iota_gfx_init();   // turns on the display
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void matrix_scan_user(void) {
 | 
					 | 
				
			||||||
     iota_gfx_task();  // this is what updates the display continuously
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef AUDIO_ENABLE
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void startup_user()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    _delay_ms(20); // gets rid of tick
 | 
					 | 
				
			||||||
    PLAY_SONG(tone_startup);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void shutdown_user()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    PLAY_SONG(tone_goodbye);
 | 
					 | 
				
			||||||
    _delay_ms(150);
 | 
					 | 
				
			||||||
    stop_all_notes();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void music_on_user(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    music_scale_user();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void music_scale_user(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    PLAY_SONG(music_scale);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void matrix_update(struct CharacterMatrix *dest,
 | 
					 | 
				
			||||||
                          const struct CharacterMatrix *source) {
 | 
					 | 
				
			||||||
  if (memcmp(dest->display, source->display, sizeof(dest->display))) {
 | 
					 | 
				
			||||||
    memcpy(dest->display, source->display, sizeof(dest->display));
 | 
					 | 
				
			||||||
    dest->dirty = true;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//assign the right code to your layers for OLED display
 | 
					 | 
				
			||||||
#define L_BASE 0
 | 
					 | 
				
			||||||
#define L_LOWER 8
 | 
					 | 
				
			||||||
#define L_RAISE 16
 | 
					 | 
				
			||||||
#define L_FNLAYER 64
 | 
					 | 
				
			||||||
#define L_NUMLAY 128
 | 
					 | 
				
			||||||
#define L_NLOWER 136
 | 
					 | 
				
			||||||
#define L_NFNLAYER 192
 | 
					 | 
				
			||||||
#define L_MOUSECURSOR 256
 | 
					 | 
				
			||||||
#define L_ADJUST 65560
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void iota_gfx_task_user(void) {
 | 
					 | 
				
			||||||
#if DEBUG_TO_SCREEN
 | 
					 | 
				
			||||||
  if (debug_enable) {
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct CharacterMatrix matrix;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  matrix_clear(&matrix);
 | 
					 | 
				
			||||||
  matrix_write_P(&matrix, PSTR("USB: "));
 | 
					 | 
				
			||||||
#ifdef PROTOCOL_LUFA
 | 
					 | 
				
			||||||
  switch (USB_DeviceState) {
 | 
					 | 
				
			||||||
    case DEVICE_STATE_Unattached:
 | 
					 | 
				
			||||||
      matrix_write_P(&matrix, PSTR("Unattached"));
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case DEVICE_STATE_Suspended:
 | 
					 | 
				
			||||||
      matrix_write_P(&matrix, PSTR("Suspended"));
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case DEVICE_STATE_Configured:
 | 
					 | 
				
			||||||
      matrix_write_P(&matrix, PSTR("Connected"));
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case DEVICE_STATE_Powered:
 | 
					 | 
				
			||||||
      matrix_write_P(&matrix, PSTR("Powered"));
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case DEVICE_STATE_Default:
 | 
					 | 
				
			||||||
      matrix_write_P(&matrix, PSTR("Default"));
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case DEVICE_STATE_Addressed:
 | 
					 | 
				
			||||||
      matrix_write_P(&matrix, PSTR("Addressed"));
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      matrix_write_P(&matrix, PSTR("Invalid"));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Define layers here, Have not worked out how to have text displayed for each layer. Copy down the number you see and add a case for it below
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  char buf[40];
 | 
					 | 
				
			||||||
  snprintf(buf,sizeof(buf), "Undef-%ld", layer_state);
 | 
					 | 
				
			||||||
  matrix_write_P(&matrix, PSTR("\n\nLayer: "));
 | 
					 | 
				
			||||||
    switch (layer_state) {
 | 
					 | 
				
			||||||
        case L_BASE:
 | 
					 | 
				
			||||||
           matrix_write_P(&matrix, PSTR("Default"));
 | 
					 | 
				
			||||||
           break;
 | 
					 | 
				
			||||||
        case L_RAISE:
 | 
					 | 
				
			||||||
           matrix_write_P(&matrix, PSTR("Raise"));
 | 
					 | 
				
			||||||
           break;
 | 
					 | 
				
			||||||
        case L_LOWER:
 | 
					 | 
				
			||||||
           matrix_write_P(&matrix, PSTR("Lower"));
 | 
					 | 
				
			||||||
           break;
 | 
					 | 
				
			||||||
        case L_ADJUST:
 | 
					 | 
				
			||||||
           matrix_write_P(&matrix, PSTR("ADJUST"));
 | 
					 | 
				
			||||||
           break;
 | 
					 | 
				
			||||||
        default:
 | 
					 | 
				
			||||||
           matrix_write(&matrix, buf);
 | 
					 | 
				
			||||||
 }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Host Keyboard LED Status
 | 
					 | 
				
			||||||
  char led[40];
 | 
					 | 
				
			||||||
    snprintf(led, sizeof(led), "\n%s  %s  %s",
 | 
					 | 
				
			||||||
            (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) ? "NUMLOCK" : "       ",
 | 
					 | 
				
			||||||
            (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) ? "CAPS" : "    ",
 | 
					 | 
				
			||||||
            (host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK)) ? "SCLK" : "    ");
 | 
					 | 
				
			||||||
  matrix_write(&matrix, led);
 | 
					 | 
				
			||||||
  matrix_update(&display, &matrix);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,25 +0,0 @@
 | 
				
			|||||||
SSD1306 OLED Display via I2C
 | 
					 | 
				
			||||||
======
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Features
 | 
					 | 
				
			||||||
--------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Some features supported by the firmware:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
* I2C connection between the two halves is required as the OLED display will use this connection as well. Note this
 | 
					 | 
				
			||||||
  requires pull-up resistors on the data and clock lines.
 | 
					 | 
				
			||||||
* OLED display will connect from either side
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Wiring
 | 
					 | 
				
			||||||
------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Work in progress...
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
OLED Configuration
 | 
					 | 
				
			||||||
-------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Work in progress...
 | 
					 | 
				
			||||||
@ -1,22 +0,0 @@
 | 
				
			|||||||
SRC += ssd1306.c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Build Options
 | 
					 | 
				
			||||||
#   change to "no" to disable the options, or define them in the Makefile in
 | 
					 | 
				
			||||||
#   the appropriate keymap folder that will get included automatically
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
BOOTMAGIC_ENABLE = no       # Enable Bootmagic Lite
 | 
					 | 
				
			||||||
MOUSEKEY_ENABLE = no        # Mouse keys
 | 
					 | 
				
			||||||
EXTRAKEY_ENABLE = yes       # Audio control and System control
 | 
					 | 
				
			||||||
CONSOLE_ENABLE = no         # Console for debug
 | 
					 | 
				
			||||||
COMMAND_ENABLE = no         # Commands for debug and configuration
 | 
					 | 
				
			||||||
NKRO_ENABLE = yes           # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
 | 
					 | 
				
			||||||
BACKLIGHT_ENABLE = no       # Enable keyboard backlight functionality
 | 
					 | 
				
			||||||
MIDI_ENABLE = no            # MIDI controls
 | 
					 | 
				
			||||||
AUDIO_ENABLE = no           # Audio output on port C6
 | 
					 | 
				
			||||||
UNICODE_ENABLE = no         # Unicode
 | 
					 | 
				
			||||||
BLUETOOTH_ENABLE = no       # Enable Bluetooth with the Adafruit EZ-Key HID
 | 
					 | 
				
			||||||
RGBLIGHT_ENABLE = yes       # Enable WS2812 RGB underlight.
 | 
					 | 
				
			||||||
SWAP_HANDS_ENABLE = no      # Enable one-hand typing
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
 | 
					 | 
				
			||||||
SLEEP_LED_ENABLE = no    # Breathing sleep LED during USB suspend
 | 
					 | 
				
			||||||
@ -1,329 +0,0 @@
 | 
				
			|||||||
#ifdef SSD1306OLED
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#    include "ssd1306.h"
 | 
					 | 
				
			||||||
#    include "i2c.h"
 | 
					 | 
				
			||||||
#    include <string.h>
 | 
					 | 
				
			||||||
#    include "print.h"
 | 
					 | 
				
			||||||
#    include "glcdfont.c"
 | 
					 | 
				
			||||||
#    ifdef PROTOCOL_LUFA
 | 
					 | 
				
			||||||
#        include "lufa.h"
 | 
					 | 
				
			||||||
#    endif
 | 
					 | 
				
			||||||
#    include "sendchar.h"
 | 
					 | 
				
			||||||
#    include "timer.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct CharacterMatrix display;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Set this to 1 to help diagnose early startup problems
 | 
					 | 
				
			||||||
// when testing power-on with ble.  Turn it off otherwise,
 | 
					 | 
				
			||||||
// as the latency of printing most of the debug info messes
 | 
					 | 
				
			||||||
// with the matrix scan, causing keys to drop.
 | 
					 | 
				
			||||||
#    define DEBUG_TO_SCREEN 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// static uint16_t last_battery_update;
 | 
					 | 
				
			||||||
// static uint32_t vbat;
 | 
					 | 
				
			||||||
//#define BatteryUpdateInterval 10000 /* milliseconds */
 | 
					 | 
				
			||||||
#    define ScreenOffInterval 300000 /* milliseconds */
 | 
					 | 
				
			||||||
#    if DEBUG_TO_SCREEN
 | 
					 | 
				
			||||||
static uint8_t displaying;
 | 
					 | 
				
			||||||
#    endif
 | 
					 | 
				
			||||||
static uint16_t last_flush;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Write command sequence.
 | 
					 | 
				
			||||||
// Returns true on success.
 | 
					 | 
				
			||||||
static inline bool _send_cmd1(uint8_t cmd) {
 | 
					 | 
				
			||||||
    bool res = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (i2c_start_write(SSD1306_ADDRESS)) {
 | 
					 | 
				
			||||||
        xprintf("failed to start write to %d\n", SSD1306_ADDRESS);
 | 
					 | 
				
			||||||
        goto done;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (i2c_master_write(0x0 /* command byte follows */)) {
 | 
					 | 
				
			||||||
        print("failed to write control byte\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        goto done;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (i2c_master_write(cmd)) {
 | 
					 | 
				
			||||||
        xprintf("failed to write command %d\n", cmd);
 | 
					 | 
				
			||||||
        goto done;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    res = true;
 | 
					 | 
				
			||||||
done:
 | 
					 | 
				
			||||||
    i2c_master_stop();
 | 
					 | 
				
			||||||
    return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Write 2-byte command sequence.
 | 
					 | 
				
			||||||
// Returns true on success
 | 
					 | 
				
			||||||
static inline bool _send_cmd2(uint8_t cmd, uint8_t opr) {
 | 
					 | 
				
			||||||
    if (!_send_cmd1(cmd)) {
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return _send_cmd1(opr);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Write 3-byte command sequence.
 | 
					 | 
				
			||||||
// Returns true on success
 | 
					 | 
				
			||||||
static inline bool _send_cmd3(uint8_t cmd, uint8_t opr1, uint8_t opr2) {
 | 
					 | 
				
			||||||
    if (!_send_cmd1(cmd)) {
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!_send_cmd1(opr1)) {
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return _send_cmd1(opr2);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#    define send_cmd1(c)      \
 | 
					 | 
				
			||||||
        if (!_send_cmd1(c)) { \
 | 
					 | 
				
			||||||
            goto done;        \
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
#    define send_cmd2(c, o)      \
 | 
					 | 
				
			||||||
        if (!_send_cmd2(c, o)) { \
 | 
					 | 
				
			||||||
            goto done;           \
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
#    define send_cmd3(c, o1, o2)      \
 | 
					 | 
				
			||||||
        if (!_send_cmd3(c, o1, o2)) { \
 | 
					 | 
				
			||||||
            goto done;                \
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void clear_display(void) {
 | 
					 | 
				
			||||||
    matrix_clear(&display);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Clear all of the display bits (there can be random noise
 | 
					 | 
				
			||||||
    // in the RAM on startup)
 | 
					 | 
				
			||||||
    send_cmd3(PageAddr, 0, (DisplayHeight / 8) - 1);
 | 
					 | 
				
			||||||
    send_cmd3(ColumnAddr, 0, DisplayWidth - 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (i2c_start_write(SSD1306_ADDRESS)) {
 | 
					 | 
				
			||||||
        goto done;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (i2c_master_write(0x40)) {
 | 
					 | 
				
			||||||
        // Data mode
 | 
					 | 
				
			||||||
        goto done;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for (uint8_t row = 0; row < MatrixRows; ++row) {
 | 
					 | 
				
			||||||
        for (uint8_t col = 0; col < DisplayWidth; ++col) {
 | 
					 | 
				
			||||||
            i2c_master_write(0);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    display.dirty = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
done:
 | 
					 | 
				
			||||||
    i2c_master_stop();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#    if DEBUG_TO_SCREEN
 | 
					 | 
				
			||||||
#        undef sendchar
 | 
					 | 
				
			||||||
static int8_t capture_sendchar(uint8_t c) {
 | 
					 | 
				
			||||||
    sendchar(c);
 | 
					 | 
				
			||||||
    iota_gfx_write_char(c);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!displaying) {
 | 
					 | 
				
			||||||
        iota_gfx_flush();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#    endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool iota_gfx_init(void) {
 | 
					 | 
				
			||||||
    bool success = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    send_cmd1(DisplayOff);
 | 
					 | 
				
			||||||
    send_cmd2(SetDisplayClockDiv, 0x80);
 | 
					 | 
				
			||||||
    send_cmd2(SetMultiPlex, DisplayHeight - 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    send_cmd2(SetDisplayOffset, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    send_cmd1(SetStartLine | 0x0);
 | 
					 | 
				
			||||||
    send_cmd2(SetChargePump, 0x14 /* Enable */);
 | 
					 | 
				
			||||||
    send_cmd2(SetMemoryMode, 0 /* horizontal addressing */);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#    ifdef OLED_ROTATE180
 | 
					 | 
				
			||||||
    // the following Flip the display orientation 180 degrees
 | 
					 | 
				
			||||||
    send_cmd1(SegRemap);
 | 
					 | 
				
			||||||
    send_cmd1(ComScanInc);
 | 
					 | 
				
			||||||
#    endif
 | 
					 | 
				
			||||||
#    ifndef OLED_ROTATE180
 | 
					 | 
				
			||||||
    // Flips the display orientation 0 degrees
 | 
					 | 
				
			||||||
    send_cmd1(SegRemap | 0x1);
 | 
					 | 
				
			||||||
    send_cmd1(ComScanDec);
 | 
					 | 
				
			||||||
#    endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    send_cmd2(SetComPins, 0x2);
 | 
					 | 
				
			||||||
    send_cmd2(SetContrast, 0x8f);
 | 
					 | 
				
			||||||
    send_cmd2(SetPreCharge, 0xf1);
 | 
					 | 
				
			||||||
    send_cmd2(SetVComDetect, 0x40);
 | 
					 | 
				
			||||||
    send_cmd1(DisplayAllOnResume);
 | 
					 | 
				
			||||||
    send_cmd1(NormalDisplay);
 | 
					 | 
				
			||||||
    send_cmd1(DeActivateScroll);
 | 
					 | 
				
			||||||
    send_cmd1(DisplayOn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    send_cmd2(SetContrast, 0); // Dim
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    clear_display();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    success = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    iota_gfx_flush();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#    if DEBUG_TO_SCREEN
 | 
					 | 
				
			||||||
    print_set_sendchar(capture_sendchar);
 | 
					 | 
				
			||||||
#    endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
done:
 | 
					 | 
				
			||||||
    return success;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool iota_gfx_off(void) {
 | 
					 | 
				
			||||||
    bool success = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    send_cmd1(DisplayOff);
 | 
					 | 
				
			||||||
    success = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
done:
 | 
					 | 
				
			||||||
    return success;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool iota_gfx_on(void) {
 | 
					 | 
				
			||||||
    bool success = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    send_cmd1(DisplayOn);
 | 
					 | 
				
			||||||
    success = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
done:
 | 
					 | 
				
			||||||
    return success;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c) {
 | 
					 | 
				
			||||||
    *matrix->cursor = c;
 | 
					 | 
				
			||||||
    ++matrix->cursor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (matrix->cursor - &matrix->display[0][0] == sizeof(matrix->display)) {
 | 
					 | 
				
			||||||
        // We went off the end; scroll the display upwards by one line
 | 
					 | 
				
			||||||
        memmove(&matrix->display[0], &matrix->display[1], MatrixCols * (MatrixRows - 1));
 | 
					 | 
				
			||||||
        matrix->cursor = &matrix->display[MatrixRows - 1][0];
 | 
					 | 
				
			||||||
        memset(matrix->cursor, ' ', MatrixCols);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c) {
 | 
					 | 
				
			||||||
    matrix->dirty = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (c == '\n') {
 | 
					 | 
				
			||||||
        // Clear to end of line from the cursor and then move to the
 | 
					 | 
				
			||||||
        // start of the next line
 | 
					 | 
				
			||||||
        uint8_t cursor_col = (matrix->cursor - &matrix->display[0][0]) % MatrixCols;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while (cursor_col++ < MatrixCols) {
 | 
					 | 
				
			||||||
            matrix_write_char_inner(matrix, ' ');
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    matrix_write_char_inner(matrix, c);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void iota_gfx_write_char(uint8_t c) {
 | 
					 | 
				
			||||||
    matrix_write_char(&display, c);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void matrix_write(struct CharacterMatrix *matrix, const char *data) {
 | 
					 | 
				
			||||||
    const char *end = data + strlen(data);
 | 
					 | 
				
			||||||
    while (data < end) {
 | 
					 | 
				
			||||||
        matrix_write_char(matrix, *data);
 | 
					 | 
				
			||||||
        ++data;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void iota_gfx_write(const char *data) {
 | 
					 | 
				
			||||||
    matrix_write(&display, data);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void matrix_write_P(struct CharacterMatrix *matrix, const char *data) {
 | 
					 | 
				
			||||||
    while (true) {
 | 
					 | 
				
			||||||
        uint8_t c = pgm_read_byte(data);
 | 
					 | 
				
			||||||
        if (c == 0) {
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        matrix_write_char(matrix, c);
 | 
					 | 
				
			||||||
        ++data;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void iota_gfx_write_P(const char *data) {
 | 
					 | 
				
			||||||
    matrix_write_P(&display, data);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void matrix_clear(struct CharacterMatrix *matrix) {
 | 
					 | 
				
			||||||
    memset(matrix->display, ' ', sizeof(matrix->display));
 | 
					 | 
				
			||||||
    matrix->cursor = &matrix->display[0][0];
 | 
					 | 
				
			||||||
    matrix->dirty  = true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void iota_gfx_clear_screen(void) {
 | 
					 | 
				
			||||||
    matrix_clear(&display);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void matrix_render(struct CharacterMatrix *matrix) {
 | 
					 | 
				
			||||||
    last_flush = timer_read();
 | 
					 | 
				
			||||||
    iota_gfx_on();
 | 
					 | 
				
			||||||
#    if DEBUG_TO_SCREEN
 | 
					 | 
				
			||||||
    ++displaying;
 | 
					 | 
				
			||||||
#    endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Move to the home position
 | 
					 | 
				
			||||||
    send_cmd3(PageAddr, 0, MatrixRows - 1);
 | 
					 | 
				
			||||||
    send_cmd3(ColumnAddr, 0, (MatrixCols * FontWidth) - 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (i2c_start_write(SSD1306_ADDRESS)) {
 | 
					 | 
				
			||||||
        goto done;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (i2c_master_write(0x40)) {
 | 
					 | 
				
			||||||
        // Data mode
 | 
					 | 
				
			||||||
        goto done;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (uint8_t row = 0; row < MatrixRows; ++row) {
 | 
					 | 
				
			||||||
        for (uint8_t col = 0; col < MatrixCols; ++col) {
 | 
					 | 
				
			||||||
            const uint8_t *glyph = font + (matrix->display[row][col] * (FontWidth - 1));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            for (uint8_t glyphCol = 0; glyphCol < FontWidth - 1; ++glyphCol) {
 | 
					 | 
				
			||||||
                uint8_t colBits = pgm_read_byte(glyph + glyphCol);
 | 
					 | 
				
			||||||
                i2c_master_write(colBits);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // 1 column of space between chars (it's not included in the glyph)
 | 
					 | 
				
			||||||
            i2c_master_write(0);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    matrix->dirty = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
done:
 | 
					 | 
				
			||||||
    i2c_master_stop();
 | 
					 | 
				
			||||||
#    if DEBUG_TO_SCREEN
 | 
					 | 
				
			||||||
    --displaying;
 | 
					 | 
				
			||||||
#    endif
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void iota_gfx_flush(void) {
 | 
					 | 
				
			||||||
    matrix_render(&display);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
__attribute__((weak)) void iota_gfx_task_user(void) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void iota_gfx_task(void) {
 | 
					 | 
				
			||||||
    iota_gfx_task_user();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (display.dirty) {
 | 
					 | 
				
			||||||
        iota_gfx_flush();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (timer_elapsed(last_flush) > ScreenOffInterval) {
 | 
					 | 
				
			||||||
        iota_gfx_off();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
@ -1,87 +0,0 @@
 | 
				
			|||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum ssd1306_cmds {
 | 
					 | 
				
			||||||
    DisplayOff = 0xAE,
 | 
					 | 
				
			||||||
    DisplayOn  = 0xAF,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SetContrast        = 0x81,
 | 
					 | 
				
			||||||
    DisplayAllOnResume = 0xA4,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DisplayAllOn       = 0xA5,
 | 
					 | 
				
			||||||
    NormalDisplay      = 0xA6,
 | 
					 | 
				
			||||||
    InvertDisplay      = 0xA7,
 | 
					 | 
				
			||||||
    SetDisplayOffset   = 0xD3,
 | 
					 | 
				
			||||||
    SetComPins         = 0xda,
 | 
					 | 
				
			||||||
    SetVComDetect      = 0xdb,
 | 
					 | 
				
			||||||
    SetDisplayClockDiv = 0xD5,
 | 
					 | 
				
			||||||
    SetPreCharge       = 0xd9,
 | 
					 | 
				
			||||||
    SetMultiPlex       = 0xa8,
 | 
					 | 
				
			||||||
    SetLowColumn       = 0x00,
 | 
					 | 
				
			||||||
    SetHighColumn      = 0x10,
 | 
					 | 
				
			||||||
    SetStartLine       = 0x40,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SetMemoryMode = 0x20,
 | 
					 | 
				
			||||||
    ColumnAddr    = 0x21,
 | 
					 | 
				
			||||||
    PageAddr      = 0x22,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ComScanInc    = 0xc0,
 | 
					 | 
				
			||||||
    ComScanDec    = 0xc8,
 | 
					 | 
				
			||||||
    SegRemap      = 0xa0,
 | 
					 | 
				
			||||||
    SetChargePump = 0x8d,
 | 
					 | 
				
			||||||
    ExternalVcc   = 0x01,
 | 
					 | 
				
			||||||
    SwitchCapVcc  = 0x02,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ActivateScroll                   = 0x2f,
 | 
					 | 
				
			||||||
    DeActivateScroll                 = 0x2e,
 | 
					 | 
				
			||||||
    SetVerticalScrollArea            = 0xa3,
 | 
					 | 
				
			||||||
    RightHorizontalScroll            = 0x26,
 | 
					 | 
				
			||||||
    LeftHorizontalScroll             = 0x27,
 | 
					 | 
				
			||||||
    VerticalAndRightHorizontalScroll = 0x29,
 | 
					 | 
				
			||||||
    VerticalAndLeftHorizontalScroll  = 0x2a,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Controls the SSD1306 128x32 OLED display via i2c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef SSD1306_ADDRESS
 | 
					 | 
				
			||||||
#    define SSD1306_ADDRESS 0x3C
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define DisplayHeight 32
 | 
					 | 
				
			||||||
#define DisplayWidth 128
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define FontHeight 8
 | 
					 | 
				
			||||||
#define FontWidth 6
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define MatrixRows (DisplayHeight / FontHeight)
 | 
					 | 
				
			||||||
#define MatrixCols (DisplayWidth / FontWidth)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct CharacterMatrix {
 | 
					 | 
				
			||||||
    uint8_t  display[MatrixRows][MatrixCols];
 | 
					 | 
				
			||||||
    uint8_t *cursor;
 | 
					 | 
				
			||||||
    bool     dirty;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern struct CharacterMatrix display;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool iota_gfx_init(void);
 | 
					 | 
				
			||||||
void iota_gfx_task(void);
 | 
					 | 
				
			||||||
bool iota_gfx_off(void);
 | 
					 | 
				
			||||||
bool iota_gfx_on(void);
 | 
					 | 
				
			||||||
void iota_gfx_flush(void);
 | 
					 | 
				
			||||||
void iota_gfx_write_char(uint8_t c);
 | 
					 | 
				
			||||||
void iota_gfx_write(const char *data);
 | 
					 | 
				
			||||||
void iota_gfx_write_P(const char *data);
 | 
					 | 
				
			||||||
void iota_gfx_clear_screen(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void iota_gfx_task_user(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void matrix_clear(struct CharacterMatrix *matrix);
 | 
					 | 
				
			||||||
void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c);
 | 
					 | 
				
			||||||
void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c);
 | 
					 | 
				
			||||||
void matrix_write(struct CharacterMatrix *matrix, const char *data);
 | 
					 | 
				
			||||||
void matrix_write_P(struct CharacterMatrix *matrix, const char *data);
 | 
					 | 
				
			||||||
void matrix_render(struct CharacterMatrix *matrix);
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user