~ruther/qmk_firmware

3e1ac7a38fa4e6885053a762bc75f7c4e068eccb — Nick Brassel 1 year, 3 months ago be42ea3
Fixes for encoder abstraction. (#23195)

M quantum/encoder.c => quantum/encoder.c +67 -25
@@ 15,34 15,39 @@ __attribute__((weak)) bool should_process_encoder(void) {
}

static encoder_events_t encoder_events;
static bool             signal_queue_drain = false;

void encoder_init(void) {
    memset(&encoder_events, 0, sizeof(encoder_events));
    encoder_driver_init();
}

static bool encoder_handle_queue(void) {
    bool changed = false;
    while (encoder_events.tail != encoder_events.head) {
        encoder_event_t event = encoder_events.queue[encoder_events.tail];
        encoder_events.tail   = (encoder_events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
static void encoder_queue_drain(void) {
    encoder_events.tail     = encoder_events.head;
    encoder_events.dequeued = encoder_events.enqueued;
}

static bool encoder_handle_queue(void) {
    bool    changed = false;
    uint8_t index;
    bool    clockwise;
    while (encoder_dequeue_event(&index, &clockwise)) {
#ifdef ENCODER_MAP_ENABLE

        // The delays below cater for Windows and its wonderful requirements.
        action_exec(event.clockwise ? MAKE_ENCODER_CW_EVENT(event.index, true) : MAKE_ENCODER_CCW_EVENT(event.index, true));
        action_exec(clockwise ? MAKE_ENCODER_CW_EVENT(index, true) : MAKE_ENCODER_CCW_EVENT(index, true));
#    if ENCODER_MAP_KEY_DELAY > 0
        wait_ms(ENCODER_MAP_KEY_DELAY);
#    endif // ENCODER_MAP_KEY_DELAY > 0

        action_exec(event.clockwise ? MAKE_ENCODER_CW_EVENT(event.index, false) : MAKE_ENCODER_CCW_EVENT(event.index, false));
        action_exec(clockwise ? MAKE_ENCODER_CW_EVENT(index, false) : MAKE_ENCODER_CCW_EVENT(index, false));
#    if ENCODER_MAP_KEY_DELAY > 0
        wait_ms(ENCODER_MAP_KEY_DELAY);
#    endif // ENCODER_MAP_KEY_DELAY > 0

#else // ENCODER_MAP_ENABLE

        encoder_update_kb(event.index, event.clockwise ? true : false);
        encoder_update_kb(index, clockwise);

#endif // ENCODER_MAP_ENABLE



@@ 61,6 66,11 @@ bool encoder_task(void) {
    }
#endif // SPLIT_KEYBOARD

    if (signal_queue_drain) {
        signal_queue_drain = false;
        encoder_queue_drain();
    }

    // Let the encoder driver produce events
    encoder_driver_task();



@@ 72,39 82,71 @@ bool encoder_task(void) {
    return changed;
}

bool encoder_queue_event(uint8_t index, bool clockwise) {
bool encoder_queue_full_advanced(encoder_events_t *events) {
    return events->head == (events->tail - 1) % MAX_QUEUED_ENCODER_EVENTS;
}

bool encoder_queue_full(void) {
    return encoder_queue_full_advanced(&encoder_events);
}

bool encoder_queue_empty_advanced(encoder_events_t *events) {
    return events->head == events->tail;
}

bool encoder_queue_empty(void) {
    return encoder_queue_empty_advanced(&encoder_events);
}

bool encoder_queue_event_advanced(encoder_events_t *events, uint8_t index, bool clockwise) {
    // Drop out if we're full
    if ((encoder_events.head + 1) % MAX_QUEUED_ENCODER_EVENTS == encoder_events.tail) {
    if (encoder_queue_full_advanced(events)) {
        return false;
    }

    // Append the event
    encoder_event_t new_event                 = {.index = index, .clockwise = clockwise ? 1 : 0};
    encoder_events.queue[encoder_events.head] = new_event;
    encoder_event_t new_event   = {.index = index, .clockwise = clockwise ? 1 : 0};
    events->queue[events->head] = new_event;

    // Increment the head index
    encoder_events.head = (encoder_events.head + 1) % MAX_QUEUED_ENCODER_EVENTS;
    events->head = (events->head + 1) % MAX_QUEUED_ENCODER_EVENTS;
    events->enqueued++;

    return true;
}

void encoder_retrieve_events(encoder_events_t *events) {
    memcpy(events, &encoder_events, sizeof(encoder_events));
bool encoder_dequeue_event_advanced(encoder_events_t *events, uint8_t *index, bool *clockwise) {
    if (encoder_queue_empty_advanced(events)) {
        return false;
    }

    // Retrieve the event
    encoder_event_t event = events->queue[events->tail];
    *index                = event.index;
    *clockwise            = event.clockwise;

    // Increment the tail index
    events->tail = (events->tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
    events->dequeued++;

    return true;
}

#ifdef SPLIT_KEYBOARD
void encoder_set_tail_index(uint8_t tail_index) {
    encoder_events.tail = tail_index;
bool encoder_queue_event(uint8_t index, bool clockwise) {
    return encoder_queue_event_advanced(&encoder_events, index, clockwise);
}

void encoder_handle_slave_events(encoder_events_t *events) {
    while (events->tail != events->head) {
        encoder_event_t event = events->queue[events->tail];
        events->tail          = (events->tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
        encoder_queue_event(event.index, event.clockwise ? true : false);
    }
bool encoder_dequeue_event(uint8_t *index, bool *clockwise) {
    return encoder_dequeue_event_advanced(&encoder_events, index, clockwise);
}

void encoder_retrieve_events(encoder_events_t *events) {
    memcpy(events, &encoder_events, sizeof(encoder_events));
}

void encoder_signal_queue_drain(void) {
    signal_queue_drain = true;
}
#endif // SPLIT_KEYBOARD

__attribute__((weak)) bool encoder_update_user(uint8_t index, bool clockwise) {
    return true;

M quantum/encoder.h => quantum/encoder.h +9 -4
@@ 29,6 29,7 @@ __attribute__((weak)) bool should_process_encoder(void);
void encoder_init(void);
bool encoder_task(void);
bool encoder_queue_event(uint8_t index, bool clockwise);
bool encoder_dequeue_event(uint8_t *index, bool *clockwise);

bool encoder_update_kb(uint8_t index, bool clockwise);
bool encoder_update_user(uint8_t index, bool clockwise);


@@ 82,6 83,8 @@ typedef struct encoder_event_t {
} encoder_event_t;

typedef struct encoder_events_t {
    uint8_t         enqueued;
    uint8_t         dequeued;
    uint8_t         head;
    uint8_t         tail;
    encoder_event_t queue[MAX_QUEUED_ENCODER_EVENTS];


@@ 90,10 93,12 @@ typedef struct encoder_events_t {
// Get the current queued events
void encoder_retrieve_events(encoder_events_t *events);

#    ifdef SPLIT_KEYBOARD
void encoder_set_tail_index(uint8_t tail_index);
void encoder_handle_slave_events(encoder_events_t *events);
#    endif // SPLIT_KEYBOARD
// Encoder event queue management
bool encoder_queue_event_advanced(encoder_events_t *events, uint8_t index, bool clockwise);
bool encoder_dequeue_event_advanced(encoder_events_t *events, uint8_t *index, bool *clockwise);

// Reset the queue to be empty
void encoder_signal_queue_drain(void);

#    ifdef ENCODER_MAP_ENABLE
#        define NUM_DIRECTIONS 2

M quantum/split_common/transaction_id_define.h => quantum/split_common/transaction_id_define.h +1 -1
@@ 31,7 31,7 @@ enum serial_transaction_id {
#ifdef ENCODER_ENABLE
    GET_ENCODERS_CHECKSUM,
    GET_ENCODERS_DATA,
    PUT_ENCODER_TAIL,
    CMD_ENCODER_DRAIN,
#endif // ENCODER_ENABLE

#ifndef DISABLE_SYNC_TIMER

M quantum/split_common/transactions.c => quantum/split_common/transactions.c +24 -8
@@ 14,6 14,7 @@
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdint.h>
#include <string.h>
#include <stddef.h>



@@ 80,8 81,12 @@
    { 0, 0, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), cb }
#define trans_target2initiator_initializer(member) trans_target2initiator_initializer_cb(member, NULL)

#define trans_initiator2target_cb(cb) \
    { 0, 0, 0, 0, cb }

#define transport_write(id, data, length) transport_execute_transaction(id, data, length, NULL, 0)
#define transport_read(id, data, length) transport_execute_transaction(id, NULL, 0, data, length)
#define transport_exec(id) transport_execute_transaction(id, NULL, 0, NULL, 0)

#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
// Forward-declare the RPC callback handlers


@@ 234,14 239,26 @@ static void master_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_ro
#ifdef ENCODER_ENABLE

static bool encoder_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
    static uint32_t  last_update = 0;
    static uint32_t  last_update   = 0;
    static uint8_t   last_checksum = 0;
    encoder_events_t temp_events;

    bool okay = read_if_checksum_mismatch(GET_ENCODERS_CHECKSUM, GET_ENCODERS_DATA, &last_update, &temp_events, &split_shmem->encoders.events, sizeof(temp_events));
    if (okay) {
        encoder_handle_slave_events(&split_shmem->encoders.events);
        transport_write(PUT_ENCODER_TAIL, &split_shmem->encoders.events.tail, sizeof(split_shmem->encoders.events.tail));
        split_shmem->encoders.checksum = crc8(&split_shmem->encoders.events, sizeof(split_shmem->encoders.events));
        if (last_checksum != split_shmem->encoders.checksum) {
            bool    actioned = false;
            uint8_t index;
            bool    clockwise;
            while (okay && encoder_dequeue_event_advanced(&split_shmem->encoders.events, &index, &clockwise)) {
                okay &= encoder_queue_event(index, clockwise);
                actioned = true;
            }

            if (actioned) {
                okay &= transport_exec(CMD_ENCODER_DRAIN);
            }
            last_checksum = split_shmem->encoders.checksum;
        }
    }
    return okay;
}


@@ 253,9 270,8 @@ static void encoder_handlers_slave(matrix_row_t master_matrix[], matrix_row_t sl
    split_shmem->encoders.checksum = crc8(&split_shmem->encoders.events, sizeof(split_shmem->encoders.events));
}

static void encoder_handlers_slave_reset(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
    uint8_t tail_index = *(uint8_t *)initiator2target_buffer;
    encoder_set_tail_index(tail_index);
static void encoder_handlers_slave_drain(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
    encoder_signal_queue_drain();
}

// clang-format off


@@ 264,7 280,7 @@ static void encoder_handlers_slave_reset(uint8_t initiator2target_buffer_size, c
#    define TRANSACTIONS_ENCODERS_REGISTRATIONS \
    [GET_ENCODERS_CHECKSUM] = trans_target2initiator_initializer(encoders.checksum), \
    [GET_ENCODERS_DATA]     = trans_target2initiator_initializer(encoders.events), \
    [PUT_ENCODER_TAIL]      = trans_initiator2target_initializer_cb(encoders.events.tail, encoder_handlers_slave_reset),
    [CMD_ENCODER_DRAIN]     = trans_initiator2target_cb(encoder_handlers_slave_drain),
// clang-format on

#else // ENCODER_ENABLE

Do not follow this link