#include QMK_KEYBOARD_H
#include "i2c_master.h"
extern i2c_status_t mcp23017_status;
#define I2C_TIMEOUT 1000
#define I2C_ADDR 0b0100000
#define I2C_ADDR_WRITE ((I2C_ADDR << 1) | I2C_WRITE)
#define I2C_ADDR_READ ((I2C_ADDR << 1) | I2C_READ)
#define IODIRA 0x00
#define IODIRB 0x01
#define GPPUA 0x0C
#define GPPUB 0x0D
#define GPIOA 0x12
#define GPIOB 0x13
#define OLATA 0x14
#define OLATB 0x15
bool i2c_initialized = 0;
i2c_status_t mcp23017_status = I2C_ADDR;
uint8_t init_mcp23017(void) {
print("starting init");
mcp23017_status = I2C_ADDR;
if (i2c_initialized == 0) {
i2c_init(); i2c_initialized = true;
wait_ms(I2C_TIMEOUT);
}
uint8_t buf[] = {IODIRA, 0b11111111, 0b11110000};
mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, buf, sizeof(buf), I2C_TIMEOUT);
if (!mcp23017_status) {
uint8_t pullup_buf[] = {GPPUA, 0b11111111, 0b11110000};
mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, pullup_buf, sizeof(pullup_buf), I2C_TIMEOUT);
}
return mcp23017_status;
}
static matrix_row_t matrix[MATRIX_ROWS];
static matrix_row_t read_cols(uint8_t row);
static void init_cols(void);
static void unselect_rows(void);
static void select_row(uint8_t row);
static uint8_t mcp23017_reset_loop;
void matrix_init_custom(void) {
mcp23017_status = init_mcp23017();
unselect_rows();
init_cols();
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
matrix[i] = 0;
}
}
void matrix_power_up(void) {
mcp23017_status = init_mcp23017();
unselect_rows();
init_cols();
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
matrix[i] = 0;
}
}
static inline bool store_matrix_row(matrix_row_t current_matrix[], uint8_t index) {
matrix_row_t temp = read_cols(index);
if (current_matrix[index] != temp) {
current_matrix[index] = temp;
return true;
}
return false;
}
bool matrix_scan_custom(matrix_row_t current_matrix[]) {
if (mcp23017_status) { if (++mcp23017_reset_loop == 0) {
dprint("trying to reset mcp23017\n");
mcp23017_status = init_mcp23017();
if (mcp23017_status) {
dprint("right side not responding\n");
} else {
dprint("right side attached\n");
}
}
}
bool changed = false;
for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
uint8_t left_index = i;
uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
select_row(left_index);
select_row(right_index);
changed |= store_matrix_row(current_matrix, left_index);
changed |= store_matrix_row(current_matrix, right_index);
unselect_rows();
}
return changed;
}
static void init_cols(void) {
pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_MCU;
for (int pin_index = 0; pin_index < MATRIX_COLS_PER_SIDE; pin_index++) {
pin_t pin = matrix_col_pins_mcu[pin_index];
setPinInput(pin);
writePinHigh(pin);
}
}
static matrix_row_t read_cols(uint8_t row) {
if (row < MATRIX_ROWS_PER_SIDE) {
pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_MCU;
matrix_row_t current_row_value = 0;
for (uint8_t col_index = 0; col_index < MATRIX_COLS_PER_SIDE; col_index++) {
uint8_t pin_state = readPin(matrix_col_pins_mcu[col_index]);
current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index);
}
return current_row_value;
} else {
if (mcp23017_status) { return 0;
} else {
uint8_t buf[] = {GPIOA};
mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, buf, sizeof(buf), I2C_TIMEOUT);
uint8_t data[] = {0};
if (!mcp23017_status) {
mcp23017_status = i2c_receive(I2C_ADDR_READ, data, sizeof(data), I2C_TIMEOUT);
data[0] = ~(data[0]);
}
return data[0];
}
}
}
static void unselect_rows(void) {
pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_MCU;
for (int pin_index = 0; pin_index < MATRIX_ROWS_PER_SIDE; pin_index++) {
pin_t pin = matrix_row_pins_mcu[pin_index];
setPinInput(pin);
writePinLow(pin);
}
}
static void select_row(uint8_t row) {
if (row < MATRIX_ROWS_PER_SIDE) {
pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_MCU;
pin_t pin = matrix_row_pins_mcu[row];
setPinOutput(pin);
writePinLow(pin);
} else {
if (mcp23017_status) { } else {
uint8_t buf[] = {GPIOB, 0xFF & ~(1 << (row - MATRIX_ROWS_PER_SIDE))};
mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, buf, sizeof(buf), I2C_TIMEOUT);
}
}
}