Integrate KeyboardioScanner as a driver

In the process of moving towards a single repository for everything
Kaleidoscope, integrate KeyboardioScanner as a driver. This is a direct copy of
KeyboardioScanner as of 2090cd426cae25b07c0ce3a6b7365b95c21dd87b, renamed and
namespaced to fit into Kaleidoscope.

Signed-off-by: Gergely Nagy <algernon@keyboard.io>
pull/994/head
Gergely Nagy 4 years ago committed by Jesse Vincent
parent dc21d751e2
commit 83c5e127ce
No known key found for this signature in database
GPG Key ID: 122F5DF7108E4046

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright © 2015 Jesse Vincent <jesse@fsck.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -38,14 +38,14 @@ constexpr uint8_t Model01LEDDriverProps::key_led_map[] PROGMEM;
/********* Model01Hands *********/
struct Model01Hands {
static KeyboardioScanner leftHand;
static KeyboardioScanner rightHand;
static driver::keyboardio::Model01Side leftHand;
static driver::keyboardio::Model01Side rightHand;
static void setup();
};
KeyboardioScanner Model01Hands::leftHand(0);
KeyboardioScanner Model01Hands::rightHand(3);
driver::keyboardio::Model01Side Model01Hands::leftHand(0);
driver::keyboardio::Model01Side Model01Hands::rightHand(3);
void Model01Hands::setup(void) {
// This lets the keyboard pull up to 1.6 amps from the host.
@ -135,12 +135,12 @@ boolean Model01LEDDriver::ledPowerFault() {
/********* Key scanner *********/
keydata_t Model01KeyScanner::leftHandState;
keydata_t Model01KeyScanner::rightHandState;
keydata_t Model01KeyScanner::previousLeftHandState;
keydata_t Model01KeyScanner::previousRightHandState;
keydata_t Model01KeyScanner::leftHandMask;
keydata_t Model01KeyScanner::rightHandMask;
driver::keyboardio::keydata_t Model01KeyScanner::leftHandState;
driver::keyboardio::keydata_t Model01KeyScanner::rightHandState;
driver::keyboardio::keydata_t Model01KeyScanner::previousLeftHandState;
driver::keyboardio::keydata_t Model01KeyScanner::previousRightHandState;
driver::keyboardio::keydata_t Model01KeyScanner::leftHandMask;
driver::keyboardio::keydata_t Model01KeyScanner::rightHandMask;
void Model01KeyScanner::enableScannerPower(void) {
// Turn on power to the LED net

@ -32,13 +32,10 @@ struct cRGB {
#include "kaleidoscope/device/ATmega32U4Keyboard.h"
#include "kaleidoscope/driver/keyscanner/Base.h"
#include "kaleidoscope/driver/keyboardio/Model01Side.h"
#include "kaleidoscope/driver/led/Base.h"
#include "kaleidoscope/driver/bootloader/avr/Caterina.h"
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
#include "KeyboardioScanner.h"
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
namespace kaleidoscope {
namespace device {
namespace keyboardio {
@ -102,13 +99,13 @@ class Model01KeyScanner : public kaleidoscope::driver::keyscanner::Base<Model01K
static void setKeyscanInterval(uint8_t interval);
protected:
static keydata_t leftHandState;
static keydata_t rightHandState;
static keydata_t previousLeftHandState;
static keydata_t previousRightHandState;
static driver::keyboardio::keydata_t leftHandState;
static driver::keyboardio::keydata_t rightHandState;
static driver::keyboardio::keydata_t previousLeftHandState;
static driver::keyboardio::keydata_t previousRightHandState;
static keydata_t leftHandMask;
static keydata_t rightHandMask;
static driver::keyboardio::keydata_t leftHandMask;
static driver::keyboardio::keydata_t rightHandMask;
static void actOnHalfRow(byte row, byte colState, byte colPrevState, byte startPos);
static void enableScannerPower();

@ -0,0 +1,214 @@
/* kaleidoscope::driver::keyboardio::Model01Side
* Copyright (C) 2015-2020 Keyboard.io, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
#include <Arduino.h>
#include "Model01Side.h"
extern "C" {
#include "kaleidoscope/device/keyboardio/twi.h"
}
#include "kaleidoscope/driver/color/GammaCorrection.h"
namespace kaleidoscope {
namespace driver {
namespace keyboardio {
#define SCANNER_I2C_ADDR_BASE 0x58
#define ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0]))
uint8_t twi_uninitialized = 1;
Model01Side::Model01Side(byte setAd01) {
ad01 = setAd01;
addr = SCANNER_I2C_ADDR_BASE | ad01;
if (twi_uninitialized--) {
twi_init();
}
}
// Returns the relative controller addresss. The expected range is 0-3
uint8_t Model01Side::controllerAddress() {
return ad01;
}
// Sets the keyscan interval. We currently do three reads.
// before declaring a key event debounced.
//
// Takes an integer value representing a counter.
//
// 0 - 0.1-0.25ms
// 1 - 0.125ms
// 10 - 0.35ms
// 25 - 0.8ms
// 50 - 1.6ms
// 100 - 3.15ms
//
// You should think of this as the _minimum_ keyscan interval.
// LED updates can cause a bit of jitter.
//
// returns the Wire.endTransmission code (0 = success)
// https://www.arduino.cc/en/Reference/WireEndTransmission
byte Model01Side::setKeyscanInterval(byte delay) {
uint8_t data[] = {TWI_CMD_KEYSCAN_INTERVAL, delay};
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0);
return result;
}
// returns -1 on error, otherwise returns the scanner version integer
int Model01Side::readVersion() {
return readRegister(TWI_CMD_VERSION);
}
// returns -1 on error, otherwise returns the scanner keyscan interval
int Model01Side::readKeyscanInterval() {
return readRegister(TWI_CMD_KEYSCAN_INTERVAL);
}
// returns -1 on error, otherwise returns the LED SPI Frequncy
int Model01Side::readLEDSPIFrequency() {
return readRegister(TWI_CMD_LED_SPI_FREQUENCY);
}
// Set the LED SPI Frequency. See wire-protocol-constants.h for
// values.
//
// returns the Wire.endTransmission code (0 = success)
// https://www.arduino.cc/en/Reference/WireEndTransmission
byte Model01Side::setLEDSPIFrequency(byte frequency) {
uint8_t data[] = {TWI_CMD_LED_SPI_FREQUENCY, frequency};
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0);
return result;
}
int Model01Side::readRegister(uint8_t cmd) {
byte return_value = 0;
uint8_t data[] = {cmd};
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0);
delayMicroseconds(15); // We may be able to drop this in the future
// but will need to verify with correctly
// sized pull-ups on both the left and right
// hands' i2c SDA and SCL lines
uint8_t rxBuffer[1];
// perform blocking read into buffer
uint8_t read = twi_readFrom(addr, rxBuffer, ELEMENTS(rxBuffer), true);
if (read > 0) {
return rxBuffer[0];
} else {
return -1;
}
}
// gives information on the key that was just pressed or released.
bool Model01Side::readKeys() {
uint8_t rxBuffer[5];
// perform blocking read into buffer
uint8_t read = twi_readFrom(addr, rxBuffer, ELEMENTS(rxBuffer), true);
if (rxBuffer[0] == TWI_REPLY_KEYDATA) {
keyData.rows[0] = rxBuffer[1];
keyData.rows[1] = rxBuffer[2];
keyData.rows[2] = rxBuffer[3];
keyData.rows[3] = rxBuffer[4];
return true;
} else {
return false;
}
}
keydata_t Model01Side::getKeyData() {
return keyData;
}
void Model01Side::sendLEDData() {
sendLEDBank(nextLEDBank++);
if (nextLEDBank == LED_BANKS) {
nextLEDBank = 0;
}
}
auto constexpr gamma8 = kaleidoscope::driver::color::gamma_correction;
void Model01Side::sendLEDBank(byte bank) {
uint8_t data[LED_BYTES_PER_BANK + 1];
data[0] = TWI_CMD_LED_BASE + bank;
for (uint8_t i = 0 ; i < LED_BYTES_PER_BANK; i++) {
/* While the ATTiny controller does have a global brightness command, it is
* limited to 32 levels, and those aren't nicely spread out either. For this
* reason, we're doing our own brightness adjustment on this side, because
* that results in a considerably smoother curve. */
uint8_t c = ledData.bytes[bank][i];
if (c > brightness_adjustment_)
c -= brightness_adjustment_;
else
c = 0;
data[i + 1] = pgm_read_byte(&gamma8[c]);
}
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0);
}
void Model01Side::setAllLEDsTo(cRGB color) {
uint8_t data[] = {TWI_CMD_LED_SET_ALL_TO,
pgm_read_byte(&gamma8[color.b]),
pgm_read_byte(&gamma8[color.g]),
pgm_read_byte(&gamma8[color.r])
};
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0);
}
void Model01Side::setOneLEDTo(byte led, cRGB color) {
uint8_t data[] = {TWI_CMD_LED_SET_ONE_TO,
led,
pgm_read_byte(&gamma8[color.b]),
pgm_read_byte(&gamma8[color.g]),
pgm_read_byte(&gamma8[color.r])
};
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0);
}
} // namespace keyboardio
} // namespace driver
} // namespace kaleidoscope
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD

@ -0,0 +1,106 @@
// -*- mode: c++ -*-
/* kaleidoscope::driver::keyboardio::Model01Side
* Copyright (C) 2015-2020 Keyboard.io, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
namespace kaleidoscope {
namespace driver {
namespace keyboardio {
#include <Arduino.h>
#include "wire-protocol-constants.h"
// We allow cRGB/CRGB to be defined already when this is included.
//
#ifndef CRGB
struct cRGB {
uint8_t b;
uint8_t g;
uint8_t r;
};
#define CRGB(r,g,b) (cRGB){b, g, r}
#endif
#define LED_BANKS 4
#define LEDS_PER_HAND 32
#define LED_BYTES_PER_BANK sizeof(cRGB) * LEDS_PER_HAND/LED_BANKS
typedef union {
cRGB leds[LEDS_PER_HAND];
byte bytes[LED_BANKS][LED_BYTES_PER_BANK];
} LEDData_t;
typedef union {
uint8_t rows[4];
uint32_t all;
} keydata_t;
// config options
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
// used to configure interrupts, configuration for a particular controller
class Model01Side {
public:
explicit Model01Side(byte setAd01);
~Model01Side() {}
int readVersion();
byte setKeyscanInterval(byte delay);
int readKeyscanInterval();
byte setLEDSPIFrequency(byte frequency);
int readLEDSPIFrequency();
void sendLEDData();
void setOneLEDTo(byte led, cRGB color);
void setAllLEDsTo(cRGB color);
keydata_t getKeyData();
bool readKeys();
LEDData_t ledData;
uint8_t controllerAddress();
void setBrightness(uint8_t brightness) {
brightness_adjustment_ = 255 - brightness;
}
uint8_t getBrightness() {
return 255 - brightness_adjustment_;
}
private:
uint8_t brightness_adjustment_ = 0;
int addr;
int ad01;
keydata_t keyData;
byte nextLEDBank = 0;
void sendLEDBank(byte bank);
int readRegister(uint8_t cmd);
};
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
class Model01Side;
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
} // namespace keyboardio
} // namespace driver
} // namespace kaleidoscope

@ -0,0 +1,51 @@
/* KeyboardioScanner
* Copyright (C) 2015-2018 Keyboard.io, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#define TWI_CMD_NONE 0x00
#define TWI_CMD_VERSION 0x01
#define TWI_CMD_KEYSCAN_INTERVAL 0x02
#define TWI_CMD_LED_SET_ALL_TO 0x03
#define TWI_CMD_LED_SET_ONE_TO 0x04
#define TWI_CMD_COLS_USE_PULLUPS 0x05
#define TWI_CMD_LED_SPI_FREQUENCY 0x06
#define LED_SPI_FREQUENCY_4MHZ 0x07
#define LED_SPI_FREQUENCY_2MHZ 0x06
#define LED_SPI_FREQUENCY_1MHZ 0x05
#define LED_SPI_FREQUENCY_512KHZ 0x04
#define LED_SPI_FREQUENCY_256KHZ 0x03
#define LED_SPI_FREQUENCY_128KHZ 0x02
#define LED_SPI_FREQUENCY_64KHZ 0x01
#define LED_SPI_OFF 0x00
// 512KHZ seems to be the sweet spot in early testing
// so make it the default
#define LED_SPI_FREQUENCY_DEFAULT LED_SPI_FREQUENCY_512KHZ
#define TWI_CMD_LED_BASE 0x80
#define TWI_REPLY_NONE 0x00
#define TWI_REPLY_KEYDATA 0x01
Loading…
Cancel
Save