zmk/app/src/split/service.c
2024-08-28 23:33:13 -04:00

128 lines
4.1 KiB
C

/*
* Copyright (c) 2023 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <zephyr/types.h>
#include <zephyr/sys/util.h>
#include <zephyr/init.h>
#include <zmk/events/sensor_event.h>
#include <zmk/sensors.h>
#include <zmk/split/service.h>
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
static uint8_t position_state[ZMK_SPLIT_POS_STATE_LEN];
#if ZMK_KEYMAP_HAS_SENSORS
static struct sensor_event last_sensor_event;
#endif
K_THREAD_STACK_DEFINE(service_q_stack, CONFIG_ZMK_SPLIT_PERIPHERAL_STACK_SIZE);
struct k_work_q service_work_q;
K_MSGQ_DEFINE(position_state_msgq, sizeof(char[ZMK_SPLIT_POS_STATE_LEN]),
CONFIG_ZMK_SPLIT_PERIPHERAL_POSITION_QUEUE_SIZE, 4);
void send_position_state_callback(struct k_work *work) {
uint8_t state[ZMK_SPLIT_POS_STATE_LEN];
while (k_msgq_get(&position_state_msgq, &state, K_NO_WAIT) == 0) {
send_position_state_impl(state, sizeof(state));
}
};
K_WORK_DEFINE(service_position_notify_work, send_position_state_callback);
int send_position_state() {
int err = k_msgq_put(&position_state_msgq, position_state, K_MSEC(100));
if (err) {
switch (err) {
case -EAGAIN: {
LOG_WRN("Position state message queue full, popping first message and queueing again");
uint8_t discarded_state[ZMK_SPLIT_POS_STATE_LEN];
k_msgq_get(&position_state_msgq, &discarded_state, K_NO_WAIT);
return send_position_state();
}
default:
LOG_WRN("Failed to queue position state to send (%d)", err);
return err;
}
}
k_work_submit_to_queue(&service_work_q, &service_position_notify_work);
return 0;
}
int zmk_split_position_pressed(uint8_t position) {
WRITE_BIT(position_state[position / 8], position % 8, true);
return send_position_state();
}
int zmk_split_position_released(uint8_t position) {
WRITE_BIT(position_state[position / 8], position % 8, false);
return send_position_state();
}
#if ZMK_KEYMAP_HAS_SENSORS
K_MSGQ_DEFINE(sensor_state_msgq, sizeof(struct sensor_event),
CONFIG_ZMK_SPLIT_PERIPHERAL_POSITION_QUEUE_SIZE, 4);
void send_sensor_state_callback(struct k_work *work) {
while (k_msgq_get(&sensor_state_msgq, &last_sensor_event, K_NO_WAIT) == 0) {
send_sensor_state_impl(&last_sensor_event, sizeof(last_sensor_event));
}
};
K_WORK_DEFINE(service_sensor_notify_work, send_sensor_state_callback);
int send_sensor_state(struct sensor_event ev) {
int err = k_msgq_put(&sensor_state_msgq, &ev, K_MSEC(100));
if (err) {
// retry...
switch (err) {
case -EAGAIN: {
LOG_WRN("Sensor state message queue full, popping first message and queueing again");
struct sensor_event discarded_state;
k_msgq_get(&sensor_state_msgq, &discarded_state, K_NO_WAIT);
return send_sensor_state(ev);
}
default:
LOG_WRN("Failed to queue sensor state to send (%d)", err);
return err;
}
}
k_work_submit_to_queue(&service_work_q, &service_sensor_notify_work);
return 0;
}
int zmk_split_sensor_triggered(uint8_t sensor_index,
const struct zmk_sensor_channel_data channel_data[],
size_t channel_data_size) {
if (channel_data_size > ZMK_SENSOR_EVENT_MAX_CHANNELS) {
return -EINVAL;
}
struct sensor_event ev =
(struct sensor_event){.sensor_index = sensor_index, .channel_data_size = channel_data_size};
memcpy(ev.channel_data, channel_data,
channel_data_size * sizeof(struct zmk_sensor_channel_data));
return send_sensor_state(ev);
}
#endif /* ZMK_KEYMAP_HAS_SENSORS */
static int service_init(void) {
static const struct k_work_queue_config queue_config = {
.name = "Split Peripheral Notification Queue"};
k_work_queue_start(&service_work_q, service_q_stack, K_THREAD_STACK_SIZEOF(service_q_stack),
CONFIG_ZMK_SPLIT_PERIPHERAL_PRIORITY, &queue_config);
return 0;
}
SYS_INIT(service_init, APPLICATION, CONFIG_ZMK_SPLIT_INIT_PRIORITY);