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"
// 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
#include "Kaleidoscope-MouseKeys.h"
@ -430,16 +430,16 @@ KALEIDOSCOPE_INIT_PLUGINS(
// Focus allows bi-directional communication with the host, and is the
// interface through which the keymap in EEPROM can be edited.
Focus,
//Focus,
// FocusSettingsCommand adds a few Focus commands, intended to aid in
// changing some settings of the keyboard, such as the default layer (via the
// `settings.defaultLayer` command)
FocusSettingsCommand,
//FocusSettingsCommand,
// FocusEEPROMCommand adds a set of Focus commands, which are very helpful in
// 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
// 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)
// This draws more than 500mA, but looks much nicer than a dimmer effect
LEDRainbowEffect.brightness(150);
LEDRainbowWaveEffect.brightness(150);
LEDRainbowEffect.brightness(255);
LEDRainbowWaveEffect.brightness(255);
// Set the action key the test mode should listen for to Left Fn
HardwareTestMode.setActionKey(R3C6);
@ -551,12 +551,12 @@ void setup() {
// 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
// `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
// maps for. To make things simple, we set it to five layers, which is how
// 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.

@ -15,16 +15,16 @@
* 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 "kaleidoscope/device/keyboardio/Model100.h" // for Model100LEDDriver...
#include "kaleidoscope/key_events.h"
#include "kaleidoscope/driver/keyscanner/Base_Impl.h"
#include "Wire.h"
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
#include <KeyboardioHID.h>
#include <avr/wdt.h>
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
namespace kaleidoscope {
@ -48,14 +48,13 @@ driver::keyboardio::Model100Side Model100Hands::leftHand(0);
driver::keyboardio::Model100Side Model100Hands::rightHand(3);
void Model100Hands::setup(void) {
// This lets the keyboard pull up to 1.6 amps from the host.
// That violates the USB spec. But it sure is pretty looking
DDRE |= _BV(6);
PORTE &= ~_BV(6);
delay(100);
pinMode(PB9, OUTPUT_OPEN_DRAIN);
digitalWrite(PB9, LOW);
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 *********/
@ -103,7 +102,6 @@ cRGB Model100LEDDriver::getCrgbAt(uint8_t i) {
void Model100LEDDriver::syncLeds() {
if (!isLEDChanged)
return;
// LED Data is stored in four "banks" for each side
// We send it all at once to make it look nicer.
// We alternate left and right hands because otherwise
@ -125,10 +123,6 @@ void Model100LEDDriver::syncLeds() {
isLEDChanged = false;
}
boolean Model100LEDDriver::ledPowerFault() {
// TODO remove - obsolete
}
/********* Key scanner *********/
driver::keyboardio::keydata_t Model100KeyScanner::leftHandState;
@ -137,16 +131,26 @@ driver::keyboardio::keydata_t Model100KeyScanner::previousLeftHandState;
driver::keyboardio::keydata_t Model100KeyScanner::previousRightHandState;
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
//
pinMode(PC13, OUTPUT_OPEN_DRAIN);
digitalWrite(PC13, LOW);
pinMode(PB9, OUTPUT_OPEN_DRAIN);
digitalWrite(PB9, HIGH);
}
void Model100KeyScanner::setup() {
wdt_disable();
delay(100);
enableScannerPower();
delay(250);
}
void Model100KeyScanner::readMatrix() {
@ -228,6 +232,7 @@ uint8_t Model100KeyScanner::previousPressedKeyswitchCount() {
/********* Hardware plugin *********/
void Model100::setup() {
Model100KeyScanner::setup();
Model100Hands::setup();
kaleidoscope::device::Base<Model100Props>::setup();
}

@ -17,7 +17,11 @@
#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>
@ -29,17 +33,24 @@ struct cRGB {
uint8_t r;
};
#include "kaleidoscope/device/ATmega32U4Keyboard.h"
#include "kaleidoscope/driver/keyscanner/Base.h"
#include "kaleidoscope/driver/storage/GD32Flash.h"
#include "kaleidoscope/driver/keyboardio/Model100Side.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"
namespace kaleidoscope {
namespace device {
namespace keyboardio {
struct Model100StorageProps: public kaleidoscope::driver::storage::GD32FlashProps {
static constexpr uint16_t length = EEPROM_EMULATION_SIZE;
};
struct Model100LEDDriverProps : public kaleidoscope::driver::led::BaseProps {
static constexpr uint8_t led_count = 64;
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 void enableHighPowerLeds();
static boolean ledPowerFault();
private:
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 enableScannerPower();
static void disableScannerPower();
};
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
class Model100KeyScanner;
#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 Model100LEDDriver LEDDriver;
typedef Model100KeyScannerProps KeyScannerProps;
typedef Model100KeyScanner KeyScanner;
typedef Model100StorageProps StorageProps;
typedef kaleidoscope::driver::storage::GD32Flash<StorageProps> Storage;
typedef kaleidoscope::driver::bootloader::gd32::Base BootLoader;
static constexpr const char *short_name = "kbio100";
};

@ -24,10 +24,8 @@
#include <Arduino.h>
#include "Model100Side.h"
extern "C" {
#include "kaleidoscope/device/keyboardio/twi.h"
}
#include <Wire.h>
#include <utility/twi.h>
#include "kaleidoscope/driver/color/GammaCorrection.h"
@ -43,9 +41,7 @@ uint8_t twi_uninitialized = 1;
Model100Side::Model100Side(byte setAd01) {
ad01 = setAd01;
addr = SCANNER_I2C_ADDR_BASE | ad01;
if (twi_uninitialized--) {
twi_init();
}
markDeviceUnavailable();
}
// 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
byte Model100Side::setKeyscanInterval(byte 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;
}
@ -103,34 +98,84 @@ int Model100Side::readLEDSPIFrequency() {
// https://www.arduino.cc/en/Reference/WireEndTransmission
byte Model100Side::setLEDSPIFrequency(byte 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;
}
// 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
byte return_value = 0;
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;
}
uint8_t data[] = {cmd};
uint8_t result = twi_writeTo(addr, data, ELEMENTS(data), 1, 0);
}
void Model100Side::markDeviceUnavailable() {
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));
delayMicroseconds(15); // We may be able to drop this in the future
// If the setup failed, return. This means there was a problem asking for the register
if (result) {
return -1;
}
delayMicroseconds(50); // TODO 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];
uint8_t rxBuffer[1] = {0};
// perform blocking read into buffer
uint8_t read = twi_readFrom(addr, rxBuffer, ELEMENTS(rxBuffer), true);
if (read > 0) {
return rxBuffer[0];
Wire.requestFrom(addr, 1); // request 1 byte from the keyscanner
if (Wire.available()) {
return Wire.read();
} else {
markDeviceUnavailable();
return -1;
}
@ -139,20 +184,28 @@ int Model100Side::readRegister(uint8_t cmd) {
// gives information on the key that was just pressed or released.
bool Model100Side::readKeys() {
if (isDeviceAvailable() == false) {
return false;
}
uint8_t rxBuffer[5];
uint8_t row_counter = 0;
// 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 {
uint8_t read = 0;
uint8_t bytes_returned = 0;
bytes_returned = Wire.requestFrom(addr, 5); // request 5 bytes from the keyscanner
if (bytes_returned < 5) {
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() {
@ -184,7 +237,7 @@ void Model100Side::sendLEDBank(byte bank) {
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) {
@ -193,7 +246,7 @@ void Model100Side::setAllLEDsTo(cRGB color) {
pgm_read_byte(&gamma8[color.g]),
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) {
@ -203,7 +256,7 @@ void Model100Side::setOneLEDTo(byte led, cRGB color) {
pgm_read_byte(&gamma8[color.g]),
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);
keydata_t getKeyData();
bool readKeys();
LEDData_t ledData;
uint8_t controllerAddress();
uint8_t controllerAddress();
bool isDeviceAvailable();
void markDeviceUnavailable();
void setBrightness(uint8_t brightness) {
brightness_adjustment_ = 255 - brightness;
}
@ -93,9 +96,14 @@ class Model100Side {
int addr;
int ad01;
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;
void sendLEDBank(byte bank);
int readRegister(uint8_t cmd);
uint8_t writeData(uint8_t* data, uint8_t length);
};
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
class Model100Side;

Loading…
Cancel
Save