diff --git a/plugins/Kaleidoscope-Hardware-Keyboardio-Model100/src/kaleidoscope/driver/keyboardio/Model100Side.cpp b/plugins/Kaleidoscope-Hardware-Keyboardio-Model100/src/kaleidoscope/driver/keyboardio/Model100Side.cpp index a5c7ff02..152fcdc1 100644 --- a/plugins/Kaleidoscope-Hardware-Keyboardio-Model100/src/kaleidoscope/driver/keyboardio/Model100Side.cpp +++ b/plugins/Kaleidoscope-Hardware-Keyboardio-Model100/src/kaleidoscope/driver/keyboardio/Model100Side.cpp @@ -103,23 +103,67 @@ byte Model100Side::setLEDSPIFrequency(byte frequency) { } +// 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() { +// if we don’t know the device is around, + 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; + } + + // 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 { + Wire.beginTransmission (wire_result); + wire_result = Wire.endTransmission(); + + // 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; + } + +} + +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)); + // 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(15); // 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 @@ -132,6 +176,7 @@ int Model100Side::readRegister(uint8_t cmd) { if (Wire.available()) { return Wire.read(); } else { + //markDeviceUnavailable(); return -1; } @@ -140,15 +185,21 @@ 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 row_counter = 0; // perform blocking read into buffer uint8_t read = 0; - Wire.requestFrom(addr, 5); // request 1 byte from the keyscanner + 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(); } diff --git a/plugins/Kaleidoscope-Hardware-Keyboardio-Model100/src/kaleidoscope/driver/keyboardio/Model100Side.h b/plugins/Kaleidoscope-Hardware-Keyboardio-Model100/src/kaleidoscope/driver/keyboardio/Model100Side.h index bc10680e..35df1b1f 100644 --- a/plugins/Kaleidoscope-Hardware-Keyboardio-Model100/src/kaleidoscope/driver/keyboardio/Model100Side.h +++ b/plugins/Kaleidoscope-Hardware-Keyboardio-Model100/src/kaleidoscope/driver/keyboardio/Model100Side.h @@ -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,6 +96,10 @@ 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_ = 1; + static const uint16_t UNAVAILABLE_DEVICE_COUNTDOWN_MAX = 0xFFFFU; byte nextLEDBank = 0; void sendLEDBank(byte bank); int readRegister(uint8_t cmd);