From 53c518f7d4552b0067619ffc2c7a3af5f3e44804 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Fri, 8 Jun 2018 02:07:28 -0400 Subject: [PATCH] start qwiic keyboard impl --- drivers/arm/twi2c.c | 71 +++++++++++++++++--- drivers/arm/twi2c.h | 6 ++ drivers/qwiic/qwiic_keyboard.c | 118 +++++++++++++++++++++++++++++++++ drivers/qwiic/qwiic_keyboard.h | 22 ++++++ 4 files changed, 207 insertions(+), 10 deletions(-) create mode 100644 drivers/qwiic/qwiic_keyboard.c create mode 100644 drivers/qwiic/qwiic_keyboard.h diff --git a/drivers/arm/twi2c.c b/drivers/arm/twi2c.c index 53af437bc..e3bed5db8 100644 --- a/drivers/arm/twi2c.c +++ b/drivers/arm/twi2c.c @@ -40,7 +40,7 @@ // 400000 // }; -I2CSlaveMsgCB twi2c_slave_message_process, catchError, clearAfterSend; +I2CSlaveMsgCB twi2c_incoming_message_process, twi2c_catch_error, twi2c_clear_after_send; #endif @@ -67,6 +67,12 @@ BaseSequentialStream *chp = NULL; // Used for serial logging #ifdef I2C_SLAVE_ENABLE + + + + + + // Handler when something sent to us const I2CSlaveMsg echoRx = { @@ -74,7 +80,7 @@ const I2CSlaveMsg echoRx = rxBody, /* body of received msg */ NULL, /* do nothing on address match */ twi2c_slave_message_process, /* Routine to process received messages */ - catchError /* Error hook */ + twi2c_catch_error /* Error hook */ }; @@ -85,7 +91,7 @@ I2CSlaveMsg initialReply = (uint8_t *)initialReplyBody, NULL, /* do nothing on address match */ NULL, /* do nothing after reply sent */ - catchError /* Error hook */ + twi2c_catch_error /* Error hook */ }; // // 'Empty' reply when nothing to say, and no message received. In RAM, to allow update @@ -95,7 +101,7 @@ I2CSlaveMsg initialReply = // NULL, // NULL, /* do nothing on address match */ // NULL, /* do nothing after reply sent */ -// catchError /* Error hook */ +// twi2c_catch_error /* Error hook */ // }; @@ -104,8 +110,8 @@ I2CSlaveMsg echoReply = { /* this is in RAM so size may be updated */ MATRIX_ROWS / 2, /* filled in with the length of the message to send */ txBody, /* Response message */ NULL, /* do nothing special on address match */ - clearAfterSend, /* Clear receive buffer once replied */ - catchError /* Error hook */ + twi2c_clear_after_send, /* Clear receive buffer once replied */ + twi2c_catch_error /* Error hook */ }; @@ -130,7 +136,7 @@ void noteI2cError(uint32_t flags) * * Called in interrupt context, so need to watch what we do */ -void catchError(I2CDriver *i2cp) +void twi2c_catch_error(I2CDriver *i2cp) { noteI2cError(i2cp->errors); } @@ -163,7 +169,7 @@ void twi2c_slave_message_process(I2CDriver *i2cp) { /** * Callback after sending of response complete - restores default reply in case polled */ -void clearAfterSend(I2CDriver *i2cp) +void twi2c_clear_after_send(I2CDriver *i2cp) { // echoReply.size = 0; // Clear receive message // i2cSlaveReplyI(i2cp, &initialReply); @@ -176,7 +182,7 @@ void clearAfterSend(I2CDriver *i2cp) * We then go into a loop checking for errors, and never return */ -void twi2c_slave_init(void) { +void twi2c_slave_init(twi2c_message_received * cb, uint8_t address) { twi2c_init(); @@ -193,7 +199,7 @@ void twi2c_slave_init(void) { i2cSlaveConfigure(&I2C_DRIVER, &echoRx, &echoReply); // Enable match address after everything else set up - i2cMatchAddress(&I2C_DRIVER, slaveI2Caddress/2); + i2cMatchAddress(&I2C_DRIVER, address/2); // i2cMatchAddress(&I2C_DRIVER, myOtherI2Caddress/2); // i2cMatchAddress(&I2C_DRIVER, 0); /* "all call" */ @@ -238,3 +244,48 @@ uint8_t twi2c_transmit(uint8_t address, uint8_t* data, uint16_t length) { i2cStart(&I2C_DRIVER, &i2cconfig); return i2cMasterTransmitTimeout(&I2C_DRIVER, twi2c_address/2, data, length, 0, 0, MS2ST(100)); } + +uint8_t twi2c_incoming_body[512]; +uint8_t twi2c_outgoing_body[512]; + +// Response to received messages +I2CSlaveMsg twi2c_incoming_message = { + sizeof(twi2c_incoming_body), + twi2c_incoming_body, + NULL, + twi2c_incoming_message_process, + twi2c_catch_error /* Error hook */ +}; + +void twi2c_incoming_message_process(I2CDriver *i2cp) { + size_t len = i2cSlaveBytes(i2cp); + twi2c_message_received_callback(twi2c_incoming_body, len); +} + +// Response to received messages +I2CSlaveMsg twi2c_outgoing_message = { /* this is in RAM so size may be updated */ + sizeof(twi2c_outgoing_body), /* filled in with the length of the message to send */ + twi2c_outgoing_body, + NULL, + twi2c_clear_after_send, + twi2c_catch_error /* Error hook */ +}; + +uint8_t twi2c_reply(uint8_t * data, uint16_t length) { + twi2c_outgoing_body = data; + twi2c_outgoing_message.size = length; + i2cSlaveReplyI(i2cp, &twi2c_outgoing_message); +} + +uint8_t twi2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t rx_body, uint16_t rx_length) { + return i2cMasterTransmitTimeout(&I2C_DRIVER, address/2, tx_body, tx_length, rx_body, rx_length, MS2ST(100)); +} + +uint8_t twi2c_start_listening(uint8_t address, twi2c_message_received callback) { + twi2c_message_received_callback = callback; + i2cStart(&I2C_DRIVER, &i2cconfig); + I2C_DRIVER.slaveTimeout = MS2ST(100); + i2cSlaveConfigure(&I2C_DRIVER, &twi2c_incoming_message, &twi2c_outgoing_message); + i2cMatchAddress(&I2C_DRIVER, address/2); + return 0; +} diff --git a/drivers/arm/twi2c.h b/drivers/arm/twi2c.h index 57cc54070..d3dc2a157 100644 --- a/drivers/arm/twi2c.h +++ b/drivers/arm/twi2c.h @@ -26,6 +26,9 @@ #ifdef I2C_SLAVE_ENABLE +typedef void twi2c_message_received(uint8_t * body, uint16_t size); +twi2c_message_received twi2c_message_received_callback; + I2CSlaveMsgCB twi2c_slave_message_process, catchError, clearAfterSend; void twi2c_slave_init(void); @@ -42,3 +45,6 @@ uint8_t twi2c_receive(uint8_t address, uint8_t* data, uint16_t length); uint8_t twi2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length); uint8_t twi2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length); void twi2c_stop(void); +uint8_t twi2c_reply(uint8_t * data, uint16_t length); +uint8_t twi2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t rx_body, uint16_t rx_length); +uint8_t twi2c_start_listening(uint8_t address, twi2c_message_received callback); diff --git a/drivers/qwiic/qwiic_keyboard.c b/drivers/qwiic/qwiic_keyboard.c new file mode 100644 index 000000000..b9e01a7f0 --- /dev/null +++ b/drivers/qwiic/qwiic_keyboard.c @@ -0,0 +1,118 @@ +/* Copyright 2018 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 . + */ + +#include "qwiic_keyboard.h" +#include "keymap.h" +#include "matrix.h" + +#define QWIIC_KEYBOARD_LAYERS 16 +#define QWIIC_KEYBOARD_ROWS 8 +#define QWIIC_KEYBOARD_COLS 8 + +#define QWIIC_KEYBOARD_HANDSHAKE_ADDRESS 0b01010100 +#define QWIIC_KEYBOARD_LISTENING_ADDRESS_START 0b01010110 +#define QWIIC_KEYBOARD_HANDSHAKE_MESSAGE_SIZE (2 + (QWIIC_KEYBOARD_LAYERS * QWIIC_KEYBOARD_ROWS * QWIIC_KEYBOARD_COLS)) +#define QWIIC_KEYBOARD_MATRIX_MESSAGE_SIZE MATRIX_ROWS + +bool qwiic_keyboard_master = false; +bool qwiic_keyboard_connected = false; +uint8_t * qwiic_keyboard_handshake_message = {0}; +uint8_t * qwiic_keyboard_matrix_message[QWIIC_KEYBOARD_ROWS] = {0}; + +uint16_t qwiic_keyboard_keymap[QWIIC_KEYBOARD_LAYERS][QWIIC_KEYBOARD_ROWS][QWIIC_KEYBOARD_COLS] = {0}; +uint8_t qwiic_keyboard_new_listening_address = QWIIC_KEYBOARD_LISTENING_ADDRESS_START; +uint8_t qwiic_keyboard_listening_address = QWIIC_KEYBOARD_LISTENING_ADDRESS_START; +uint8_t qwiic_keyboard_matrix_rows; +uint8_t qwiic_keyboard_matrix_cols; + +void qwiic_keyboard_setup(void) { + twi2c_start_listening(qwiic_keyboard_listening_address, qwiic_keyboard_message_received); +} + +void qwiic_keyboard_set_master() { + twi2c_stop(); + qwiic_keyboard_master = true; +} + +void qwiic_keyboard_task(void) { + if (qwiic_keyboard_master) { + if (qwiic_keyboard_connected) { + if (MSG_OK == twi2c_transmit_receive(qwiic_keyboard_listening_address, + NULL, 0, + qwiic_keyboard_matrix_message, QWIIC_KEYBOARD_MATRIX_MESSAGE_SIZE + )) { + // process key event + } else { + // disconnect + } + } + if (MSG_OK == twi2c_transmit_receive(QWIIC_KEYBOARD_HANDSHAKE_ADDRESS, + qwiic_keyboard_new_listening_address, 1, + qwiic_keyboard_handshake_message, QWIIC_KEYBOARD_HANDSHAKE_MESSAGE_SIZE + )) { + qwiic_keyboard_new_listening_address+=2; + uint8_t * message_pointer = qwiic_keyboard_handshake_message; + qwiic_keyboard_matrix_rows = *message_pointer++; + qwiic_keyboard_matrix_cols = *message_pointer++; + qwiic_keyboard_read_keymap(message_pointer); + } + } +} + +twi2c_message_received qwiic_keyboard_message_received; +extern matrix_row_t matrix[MATRIX_ROWS]; +uint8_t * qwiic_keyboard_reply; + +void qwiic_keyboard_message_received(uint8_t * body, uint16_t size) { + if (qwiic_keyboard_connected) { + memcpy(qwiic_keyboard_reply, matrix, QWIIC_KEYBOARD_MATRIX_MESSAGE_SIZE); + twi2c_reply(qwiic_keyboard_reply, QWIIC_KEYBOARD_MATRIX_MESSAGE_SIZE); + } else { + qwiic_keyboard_connected = true; + qwiic_keyboard_listening_address + uint8_t * message_pointer = qwiic_keyboard_reply; + *message_pointer++ = MATRIX_ROWS; + *message_pointer++ = MATRIX_COLS; + qwiic_keyboard_write_keymap(message_pointer); + twi2c_reply(qwiic_keyboard_reply, QWIIC_KEYBOARD_HANDSHAKE_MESSAGE_SIZE); + twi2c_stop(); + twi2c_start_listening(qwiic_keyboard_listening_address, qwiic_keyboard_message_received); + } +} + +void qwiic_keyboard_write_keymap(uint8_t * pointer) { + for (uint8_t layer = 0; layer < QWIIC_KEYBOARD_LAYERS; layer++) { + for (uint8_t row = 0; row < QWIIC_KEYBOARD_ROWS; row++) { + for (uint8_t col = 0; col < QWIIC_KEYBOARD_COLS; col++) { + uint16_t keycode = pgm_read_word(&keymaps[layer][row][col]); + *pointer++ = (keycode >> 8); + *pointer++ = (keycode & 0xFF); + } + } + } +} + +void qwiic_keyboard_read_keymap(uint8_t * pointer) { + for (uint8_t layer = 0; layer < QWIIC_KEYBOARD_LAYERS; layer++) { + for (uint8_t row = 0; row < QWIIC_KEYBOARD_ROWS; row++) { + for (uint8_t col = 0; col < QWIIC_KEYBOARD_COLS; col++) { + uint16_t keycode = *pointer++; + keycode |= (*pointer++) << 8; + qwiic_keyboard_keymap[layer][row][col] = keycode; + } + } + } +} diff --git a/drivers/qwiic/qwiic_keyboard.h b/drivers/qwiic/qwiic_keyboard.h new file mode 100644 index 000000000..d73544a9a --- /dev/null +++ b/drivers/qwiic/qwiic_keyboard.h @@ -0,0 +1,22 @@ +/* Copyright 2018 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 . + */ + +#ifndef QWIIC_KEYBOARD_H +#define QWIIC_KEYBOARD_H + +#include "quantum.h" + +#endif