1
0
Fork 0

Extensible split data sync (#11930)

* Extensible split data sync capability through transactions.

- Split common transport has been split up between the transport layer
  and data layer.
- Split "transactions" model used, with convergence between I2C and
  serial data definitions.
- Slave matrix "generation count" is used to determine if the full slave
  matrix needs to be retrieved.
- Encoders get the same "generation count" treatment.
- All other blocks of data are synchronised when a change is detected.
- All transmissions have a globally-configurable deadline before a
  transmission is forced (`FORCED_SYNC_THROTTLE_MS`, default 100ms).
- Added atomicity for all core-synced data, preventing partial updates
- Added retries to AVR i2c_master's i2c_start, to minimise the number of
  failed transactions when interrupts are disabled on the slave due to
  atomicity checks.
- Some keyboards have had slight modifications made in order to ensure
  that they still build due to firmware size restrictions.

* Fixup LED_MATRIX compile.

* Parameterise ERROR_DISCONNECT_COUNT.
This commit is contained in:
Nick Brassel 2021-06-18 09:10:06 +10:00 committed by GitHub
parent ef92c9ee2c
commit 172e6a7030
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 1389 additions and 693 deletions

View file

@ -17,6 +17,7 @@
* GitHub repository: https://github.com/g4lvanix/I2C-slave-lib
*/
#include <stddef.h>
#include <avr/io.h>
#include <util/twi.h>
#include <avr/interrupt.h>
@ -24,6 +25,12 @@
#include "i2c_slave.h"
#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
# include "transactions.h"
static volatile bool is_callback_executor = false;
#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];
static volatile uint8_t buffer_address;
@ -48,11 +55,14 @@ ISR(TWI_vect) {
case TW_SR_SLA_ACK:
// The device is now a slave receiver
slave_has_register_set = false;
#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
is_callback_executor = false;
#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
break;
case TW_SR_DATA_ACK:
// This device is a slave receiver and has received data
// First byte is the location then the bytes will be writen in buffer with auto-incriment
// First byte is the location then the bytes will be writen in buffer with auto-increment
if (!slave_has_register_set) {
buffer_address = TWDR;
@ -60,10 +70,25 @@ ISR(TWI_vect) {
ack = 0;
buffer_address = 0;
}
slave_has_register_set = true; // address has been receaved now fill in buffer
slave_has_register_set = true; // address has been received now fill in buffer
#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
// Work out if we're attempting to execute a callback
is_callback_executor = buffer_address == split_transaction_table[I2C_EXECUTE_CALLBACK].initiator2target_offset;
#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
} else {
i2c_slave_reg[buffer_address] = TWDR;
buffer_address++;
#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
// If we're intending to execute a transaction callback, do so, as we've just received the transaction ID
if (is_callback_executor) {
split_transaction_desc_t *trans = &split_transaction_table[split_shmem->transaction_id];
if (trans->slave_callback) {
trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans));
}
}
#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
}
break;