Initial implemetation of Model 100 hardware driver

pull/1088/head
Jesse Vincent 3 years ago
parent 1d70cf2dc8
commit d3216aed95
No known key found for this signature in database
GPG Key ID: 122F5DF7108E4046

@ -21,7 +21,7 @@
#include "Kaleidoscope-EEPROM-Keymap.h" #include "Kaleidoscope-EEPROM-Keymap.h"
// Support for communicating with the host via a simple Serial protocol // Support for communicating with the host via a simple Serial protocol
#include "Kaleidoscope-FocusSerial.h" //#include "Kaleidoscope-FocusSerial.h"
// Support for keys that move the mouse // Support for keys that move the mouse
#include "Kaleidoscope-MouseKeys.h" #include "Kaleidoscope-MouseKeys.h"
@ -430,16 +430,16 @@ KALEIDOSCOPE_INIT_PLUGINS(
// Focus allows bi-directional communication with the host, and is the // Focus allows bi-directional communication with the host, and is the
// interface through which the keymap in EEPROM can be edited. // interface through which the keymap in EEPROM can be edited.
Focus, //Focus,
// FocusSettingsCommand adds a few Focus commands, intended to aid in // FocusSettingsCommand adds a few Focus commands, intended to aid in
// changing some settings of the keyboard, such as the default layer (via the // changing some settings of the keyboard, such as the default layer (via the
// `settings.defaultLayer` command) // `settings.defaultLayer` command)
FocusSettingsCommand, //FocusSettingsCommand,
// FocusEEPROMCommand adds a set of Focus commands, which are very helpful in // FocusEEPROMCommand adds a set of Focus commands, which are very helpful in
// both debugging, and in backing up one's EEPROM contents. // both debugging, and in backing up one's EEPROM contents.
FocusEEPROMCommand, // FocusEEPROMCommand,
// The boot greeting effect pulses the LED button for 10 seconds after the // The boot greeting effect pulses the LED button for 10 seconds after the
// keyboard is first connected // keyboard is first connected
@ -530,8 +530,8 @@ void setup() {
// We set the brightness of the rainbow effects to 150 (on a scale of 0-255) // We set the brightness of the rainbow effects to 150 (on a scale of 0-255)
// This draws more than 500mA, but looks much nicer than a dimmer effect // This draws more than 500mA, but looks much nicer than a dimmer effect
LEDRainbowEffect.brightness(150); LEDRainbowEffect.brightness(255);
LEDRainbowWaveEffect.brightness(150); LEDRainbowWaveEffect.brightness(255);
// Set the action key the test mode should listen for to Left Fn // Set the action key the test mode should listen for to Left Fn
HardwareTestMode.setActionKey(R3C6); HardwareTestMode.setActionKey(R3C6);
@ -551,12 +551,12 @@ void setup() {
// one wants to use these layers, just set the default layer to one in EEPROM, // one wants to use these layers, just set the default layer to one in EEPROM,
// by using the `settings.defaultLayer` Focus command, or by using the // by using the `settings.defaultLayer` Focus command, or by using the
// `keymap.onlyCustom` command to use EEPROM layers only. // `keymap.onlyCustom` command to use EEPROM layers only.
EEPROMKeymap.setup(5); //EEPROMKeymap.setup(5);
// We need to tell the Colormap plugin how many layers we want to have custom // We need to tell the Colormap plugin how many layers we want to have custom
// maps for. To make things simple, we set it to five layers, which is how // maps for. To make things simple, we set it to five layers, which is how
// many editable layers we have (see above). // many editable layers we have (see above).
ColormapEffect.max_layers(5); //ColormapEffect.max_layers(5);
} }
/** loop is the second of the standard Arduino sketch functions. /** loop is the second of the standard Arduino sketch functions.

@ -15,16 +15,16 @@
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef ARDUINO_GD32_keyboardio_model_100 #ifdef ARDUINO_keyboardio_model_100
#include "Arduino.h" // for PROGMEM #include "Arduino.h" // for PROGMEM
#include "kaleidoscope/device/keyboardio/Model100.h" // for Model100LEDDriver... #include "kaleidoscope/device/keyboardio/Model100.h" // for Model100LEDDriver...
#include "kaleidoscope/key_events.h" #include "kaleidoscope/key_events.h"
#include "kaleidoscope/driver/keyscanner/Base_Impl.h" #include "kaleidoscope/driver/keyscanner/Base_Impl.h"
#include "Wire.h"
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD #ifndef KALEIDOSCOPE_VIRTUAL_BUILD
#include <KeyboardioHID.h>
#include <avr/wdt.h>
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
namespace kaleidoscope { namespace kaleidoscope {
@ -48,14 +48,13 @@ driver::keyboardio::Model100Side Model100Hands::leftHand(0);
driver::keyboardio::Model100Side Model100Hands::rightHand(3); driver::keyboardio::Model100Side Model100Hands::rightHand(3);
void Model100Hands::setup(void) { void Model100Hands::setup(void) {
// This lets the keyboard pull up to 1.6 amps from the host. delay(100);
// That violates the USB spec. But it sure is pretty looking pinMode(PB9, OUTPUT_OPEN_DRAIN);
DDRE |= _BV(6); digitalWrite(PB9, LOW);
PORTE &= ~_BV(6); delay(105); // TODO remove this when we remove it from the attiny code
Wire.begin();
Wire.setClock(400000);
// Set B4, the overcurrent check to an input with an internal pull-up
DDRB &= ~_BV(4); // set bit, input
PORTB &= ~_BV(4); // set bit, enable pull-up resistor
} }
/********* LED Driver *********/ /********* LED Driver *********/
@ -103,7 +102,6 @@ cRGB Model100LEDDriver::getCrgbAt(uint8_t i) {
void Model100LEDDriver::syncLeds() { void Model100LEDDriver::syncLeds() {
if (!isLEDChanged) if (!isLEDChanged)
return; return;
// LED Data is stored in four "banks" for each side // LED Data is stored in four "banks" for each side
// We send it all at once to make it look nicer. // We send it all at once to make it look nicer.
// We alternate left and right hands because otherwise // We alternate left and right hands because otherwise
@ -125,10 +123,6 @@ void Model100LEDDriver::syncLeds() {
isLEDChanged = false; isLEDChanged = false;
} }
boolean Model100LEDDriver::ledPowerFault() {
// TODO remove - obsolete
}
/********* Key scanner *********/ /********* Key scanner *********/
driver::keyboardio::keydata_t Model100KeyScanner::leftHandState; driver::keyboardio::keydata_t Model100KeyScanner::leftHandState;
@ -137,16 +131,26 @@ driver::keyboardio::keydata_t Model100KeyScanner::previousLeftHandState;
driver::keyboardio::keydata_t Model100KeyScanner::previousRightHandState; driver::keyboardio::keydata_t Model100KeyScanner::previousRightHandState;
void Model100KeyScanner::enableScannerPower(void) { void Model100KeyScanner::enableScannerPower(void) {
// Turn on the switched 5V network.
// make sure this happens at least 100ms after USB connect
// to satisfy inrush limits
//
pinMode(PB9, OUTPUT_OPEN_DRAIN);
digitalWrite(PB9, LOW);
}
void Model100KeyScanner::disableScannerPower(void) {
// Turn on power to the 5V net // Turn on power to the 5V net
// //
pinMode(PC13, OUTPUT_OPEN_DRAIN); pinMode(PB9, OUTPUT_OPEN_DRAIN);
digitalWrite(PC13, LOW); digitalWrite(PB9, HIGH);
} }
void Model100KeyScanner::setup() { void Model100KeyScanner::setup() {
wdt_disable();
delay(100);
enableScannerPower(); enableScannerPower();
delay(250);
} }
void Model100KeyScanner::readMatrix() { void Model100KeyScanner::readMatrix() {
@ -228,6 +232,7 @@ uint8_t Model100KeyScanner::previousPressedKeyswitchCount() {
/********* Hardware plugin *********/ /********* Hardware plugin *********/
void Model100::setup() { void Model100::setup() {
Model100KeyScanner::setup();
Model100Hands::setup(); Model100Hands::setup();
kaleidoscope::device::Base<Model100Props>::setup(); kaleidoscope::device::Base<Model100Props>::setup();
} }

@ -17,7 +17,11 @@
#pragma once #pragma once
#ifdef ARDUINO_GD32_keyboardio_model_100 #ifdef ARDUINO_keyboardio_model_100
#ifndef EEPROM_EMULATION_SIZE
#define EEPROM_EMULATION_SIZE 4096
#endif
#include <Arduino.h> #include <Arduino.h>
@ -29,17 +33,24 @@ struct cRGB {
uint8_t r; uint8_t r;
}; };
#include "kaleidoscope/device/ATmega32U4Keyboard.h"
#include "kaleidoscope/driver/keyscanner/Base.h" #include "kaleidoscope/driver/keyscanner/Base.h"
#include "kaleidoscope/driver/storage/GD32Flash.h"
#include "kaleidoscope/driver/keyboardio/Model100Side.h" #include "kaleidoscope/driver/keyboardio/Model100Side.h"
#include "kaleidoscope/driver/led/Base.h" #include "kaleidoscope/driver/led/Base.h"
#include "kaleidoscope/device/Base.h"
#include "kaleidoscope/driver/hid/Keyboardio.h"
#include "kaleidoscope/driver/bootloader/gd32/Base.h" #include "kaleidoscope/driver/bootloader/gd32/Base.h"
namespace kaleidoscope { namespace kaleidoscope {
namespace device { namespace device {
namespace keyboardio { namespace keyboardio {
struct Model100StorageProps: public kaleidoscope::driver::storage::GD32FlashProps {
static constexpr uint16_t length = EEPROM_EMULATION_SIZE;
};
struct Model100LEDDriverProps : public kaleidoscope::driver::led::BaseProps { struct Model100LEDDriverProps : public kaleidoscope::driver::led::BaseProps {
static constexpr uint8_t led_count = 64; static constexpr uint8_t led_count = 64;
static constexpr uint8_t key_led_map[] PROGMEM = { static constexpr uint8_t key_led_map[] PROGMEM = {
@ -60,7 +71,6 @@ class Model100LEDDriver : public kaleidoscope::driver::led::Base<Model100LEDDriv
static uint8_t getBrightness(); static uint8_t getBrightness();
static void enableHighPowerLeds(); static void enableHighPowerLeds();
static boolean ledPowerFault();
private: private:
static bool isLEDChanged; static bool isLEDChanged;
@ -101,16 +111,23 @@ class Model100KeyScanner : public kaleidoscope::driver::keyscanner::Base<Model10
static void actOnHalfRow(byte row, byte colState, byte colPrevState, byte startPos); static void actOnHalfRow(byte row, byte colState, byte colPrevState, byte startPos);
static void enableScannerPower(); static void enableScannerPower();
static void disableScannerPower();
}; };
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
class Model100KeyScanner; class Model100KeyScanner;
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
struct Model100Props : public kaleidoscope::device::BaseKeyboardProps { struct Model100Props : public kaleidoscope::device::BaseProps {
typedef kaleidoscope::driver::hid::KeyboardioProps HIDProps;
typedef kaleidoscope::driver::hid::Keyboardio<HIDProps> HID;
typedef Model100LEDDriverProps LEDDriverProps; typedef Model100LEDDriverProps LEDDriverProps;
typedef Model100LEDDriver LEDDriver; typedef Model100LEDDriver LEDDriver;
typedef Model100KeyScannerProps KeyScannerProps; typedef Model100KeyScannerProps KeyScannerProps;
typedef Model100KeyScanner KeyScanner; typedef Model100KeyScanner KeyScanner;
typedef Model100StorageProps StorageProps;
typedef kaleidoscope::driver::storage::GD32Flash<StorageProps> Storage;
typedef kaleidoscope::driver::bootloader::gd32::Base BootLoader; typedef kaleidoscope::driver::bootloader::gd32::Base BootLoader;
static constexpr const char *short_name = "kbio100"; static constexpr const char *short_name = "kbio100";
}; };

@ -24,10 +24,8 @@
#include <Arduino.h> #include <Arduino.h>
#include "Model100Side.h" #include "Model100Side.h"
#include <Wire.h>
extern "C" { #include <utility/twi.h>
#include "kaleidoscope/device/keyboardio/twi.h"
}
#include "kaleidoscope/driver/color/GammaCorrection.h" #include "kaleidoscope/driver/color/GammaCorrection.h"
@ -43,9 +41,7 @@ uint8_t twi_uninitialized = 1;
Model100Side::Model100Side(byte setAd01) { Model100Side::Model100Side(byte setAd01) {
ad01 = setAd01; ad01 = setAd01;
addr = SCANNER_I2C_ADDR_BASE | ad01; addr = SCANNER_I2C_ADDR_BASE | ad01;
if (twi_uninitialized--) { markDeviceUnavailable();
twi_init();
}
} }
// Returns the relative controller addresss. The expected range is 0-3 // Returns the relative controller addresss. The expected range is 0-3
@ -72,8 +68,7 @@ uint8_t Model100Side::controllerAddress() {
// https://www.arduino.cc/en/Reference/WireEndTransmission // https://www.arduino.cc/en/Reference/WireEndTransmission
byte Model100Side::setKeyscanInterval(byte delay) { byte Model100Side::setKeyscanInterval(byte delay) {
uint8_t data[] = {TWI_CMD_KEYSCAN_INTERVAL, delay}; uint8_t data[] = {TWI_CMD_KEYSCAN_INTERVAL, delay};
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0); uint8_t result = writeData(data, ELEMENTS(data));
return result; return result;
} }
@ -103,34 +98,84 @@ int Model100Side::readLEDSPIFrequency() {
// https://www.arduino.cc/en/Reference/WireEndTransmission // https://www.arduino.cc/en/Reference/WireEndTransmission
byte Model100Side::setLEDSPIFrequency(byte frequency) { byte Model100Side::setLEDSPIFrequency(byte frequency) {
uint8_t data[] = {TWI_CMD_LED_SPI_FREQUENCY, frequency}; uint8_t data[] = {TWI_CMD_LED_SPI_FREQUENCY, frequency};
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0); uint8_t result = writeData(data, ELEMENTS(data));
return result; return result;
} }
// GD32 I2C implements timeouts which will cause a stall when a device does not answer.
// This method will verify that the device is around and ready to talk.
bool Model100Side::isDeviceAvailable() {
return true;
// if the counter is zero, that's the special value that means "we know it's there"
if (unavailable_device_check_countdown_ == 0) {
return true;
}
int Model100Side::readRegister(uint8_t cmd) { // if the time to check counter is 1, check for the device
else if (--unavailable_device_check_countdown_ == 0) {
uint8_t wire_result;
Wire.beginTransmission(addr);
wire_result = Wire.endTransmission();
//if the check succeeds
if (wire_result == 0) {
// unavailable_device_check_countdown_ = 0; // TODO this is already true
return true;
} else {
// set the time to check counter to max
unavailable_device_check_countdown_ = UNAVAILABLE_DEVICE_COUNTDOWN_MAX;
return false;
}
} else {
// we've decremented the counter, but it's not time to probe for the device yet.
return false;
}
byte return_value = 0; }
uint8_t data[] = {cmd}; void Model100Side::markDeviceUnavailable() {
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0); unavailable_device_check_countdown_ = 1; // We think there was a comms problem. Check on the next cycle
}
uint8_t Model100Side::writeData(uint8_t *data, uint8_t length) {
if (isDeviceAvailable() == false) {
return 1;
}
Wire.beginTransmission(addr);
Wire.write(data, length);
uint8_t result = Wire.endTransmission();
if (result) {
markDeviceUnavailable();
}
return result;
}
int Model100Side::readRegister(uint8_t cmd) {
byte return_value = 0;
uint8_t data[] = {cmd};
uint8_t result = writeData(data, ELEMENTS(data));
// If the setup failed, return. This means there was a problem asking for the register
if (result) {
return -1;
}
delayMicroseconds(15); // We may be able to drop this in the future delayMicroseconds(50); // TODO We may be able to drop this in the future
// but will need to verify with correctly // but will need to verify with correctly
// sized pull-ups on both the left and right // sized pull-ups on both the left and right
// hands' i2c SDA and SCL lines // hands' i2c SDA and SCL lines
uint8_t rxBuffer[1]; uint8_t rxBuffer[1] = {0};
// perform blocking read into buffer // perform blocking read into buffer
uint8_t read = twi_readFrom(addr, rxBuffer, ELEMENTS(rxBuffer), true);
if (read > 0) { Wire.requestFrom(addr, 1); // request 1 byte from the keyscanner
return rxBuffer[0]; if (Wire.available()) {
return Wire.read();
} else { } else {
markDeviceUnavailable();
return -1; return -1;
} }
@ -139,20 +184,28 @@ int Model100Side::readRegister(uint8_t cmd) {
// gives information on the key that was just pressed or released. // gives information on the key that was just pressed or released.
bool Model100Side::readKeys() { bool Model100Side::readKeys() {
if (isDeviceAvailable() == false) {
return false;
}
uint8_t rxBuffer[5]; uint8_t row_counter = 0;
// perform blocking read into buffer // perform blocking read into buffer
uint8_t read = twi_readFrom(addr, rxBuffer, ELEMENTS(rxBuffer), true); uint8_t read = 0;
if (rxBuffer[0] == TWI_REPLY_KEYDATA) { uint8_t bytes_returned = 0;
keyData.rows[0] = rxBuffer[1]; bytes_returned = Wire.requestFrom(addr, 5); // request 5 bytes from the keyscanner
keyData.rows[1] = rxBuffer[2]; if (bytes_returned < 5) {
keyData.rows[2] = rxBuffer[3];
keyData.rows[3] = rxBuffer[4];
return true;
} else {
return false; return false;
} }
if (Wire.available()) {
read = Wire.read();
if (TWI_REPLY_KEYDATA == read) {
while (Wire.available()) {
keyData.rows[row_counter++] = Wire.read();
}
return true;
}
}
return false;
} }
keydata_t Model100Side::getKeyData() { keydata_t Model100Side::getKeyData() {
@ -184,7 +237,7 @@ void Model100Side::sendLEDBank(byte bank) {
data[i + 1] = pgm_read_byte(&gamma8[c]); data[i + 1] = pgm_read_byte(&gamma8[c]);
} }
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0); uint8_t result = writeData(data, ELEMENTS(data));
} }
void Model100Side::setAllLEDsTo(cRGB color) { void Model100Side::setAllLEDsTo(cRGB color) {
@ -193,7 +246,7 @@ void Model100Side::setAllLEDsTo(cRGB color) {
pgm_read_byte(&gamma8[color.g]), pgm_read_byte(&gamma8[color.g]),
pgm_read_byte(&gamma8[color.r]) pgm_read_byte(&gamma8[color.r])
}; };
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0); uint8_t result = writeData(data, ELEMENTS(data));
} }
void Model100Side::setOneLEDTo(byte led, cRGB color) { void Model100Side::setOneLEDTo(byte led, cRGB color) {
@ -203,7 +256,7 @@ void Model100Side::setOneLEDTo(byte led, cRGB color) {
pgm_read_byte(&gamma8[color.g]), pgm_read_byte(&gamma8[color.g]),
pgm_read_byte(&gamma8[color.r]) pgm_read_byte(&gamma8[color.r])
}; };
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0); uint8_t result = writeData(data, ELEMENTS(data));
} }

@ -78,9 +78,12 @@ class Model100Side {
void setAllLEDsTo(cRGB color); void setAllLEDsTo(cRGB color);
keydata_t getKeyData(); keydata_t getKeyData();
bool readKeys(); bool readKeys();
LEDData_t ledData; LEDData_t ledData;
uint8_t controllerAddress();
uint8_t controllerAddress();
bool isDeviceAvailable();
void markDeviceUnavailable();
void setBrightness(uint8_t brightness) { void setBrightness(uint8_t brightness) {
brightness_adjustment_ = 255 - brightness; brightness_adjustment_ = 255 - brightness;
} }
@ -93,9 +96,14 @@ class Model100Side {
int addr; int addr;
int ad01; int ad01;
keydata_t keyData; keydata_t keyData;
// a value of 0 is "device seen" - anything else is how many cycles before we should
// check for the device
uint16_t unavailable_device_check_countdown_ = 0;
static const uint16_t UNAVAILABLE_DEVICE_COUNTDOWN_MAX = 0x00FFU;
byte nextLEDBank = 0; byte nextLEDBank = 0;
void sendLEDBank(byte bank); void sendLEDBank(byte bank);
int readRegister(uint8_t cmd); int readRegister(uint8_t cmd);
uint8_t writeData(uint8_t* data, uint8_t length);
}; };
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
class Model100Side; class Model100Side;

Loading…
Cancel
Save