zephyr/drivers/input/input_analog_axis_settings.c
Fabio Baltieri 55c14e6fa6 input: analog_axis: rework deadzone calibration code
Rework the data scaling algorithm for the "deadzone" mode so that the
deadzone is subtracted from the input rather than from the output. This
makes the whole output range usable rather than making the output jump
from the center value to the minimum deadzone range.

This changes the calibration data structure as well so now all values
refer to the input data, which is more coherent.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
2024-03-26 11:10:10 -04:00

112 lines
2.6 KiB
C

/*
* Copyright 2023 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <zephyr/device.h>
#include <zephyr/input/input_analog_axis.h>
#include <zephyr/input/input_analog_axis_settings.h>
#include <zephyr/logging/log.h>
#include <zephyr/settings/settings.h>
#include <zephyr/sys/printk.h>
LOG_MODULE_REGISTER(analog_axis_settings, CONFIG_INPUT_LOG_LEVEL);
#define ANALOG_AXIS_SETTINGS_PATH_MAX 32
#define MAX_AXES CONFIG_INPUT_ANALOG_AXIS_SETTINGS_MAX_AXES
static void analog_axis_calibration_log(const struct device *dev)
{
struct analog_axis_calibration cal;
int i;
for (i = 0; i < analog_axis_num_axes(dev); i++) {
analog_axis_calibration_get(dev, i, &cal);
LOG_INF("%s: ch: %d min: %d max: %d deadzone: %d",
dev->name, i, cal.in_min, cal.in_max, cal.in_deadzone);
}
}
static int analog_axis_calibration_load(const char *key, size_t len_rd,
settings_read_cb read_cb, void *cb_arg)
{
const struct device *dev;
struct analog_axis_calibration cal[MAX_AXES];
int axes;
char dev_name[ANALOG_AXIS_SETTINGS_PATH_MAX];
const char *next;
int nlen;
ssize_t len;
nlen = settings_name_next(key, &next);
if (nlen + 1 > sizeof(dev_name)) {
LOG_ERR("Setting name too long: %d", nlen);
return -EINVAL;
}
memcpy(dev_name, key, nlen);
dev_name[nlen] = '\0';
dev = device_get_binding(dev_name);
if (dev == NULL) {
LOG_ERR("Cannot restore: device %s not available", dev_name);
return -ENODEV;
}
len = read_cb(cb_arg, cal, sizeof(cal));
if (len < 0) {
LOG_ERR("Data restore error: %d", len);
}
axes = analog_axis_num_axes(dev);
if (len != sizeof(struct analog_axis_calibration) * axes) {
LOG_ERR("Invalid settings data length: %d, expected %d",
len, sizeof(struct analog_axis_calibration) * axes);
return -EIO;
}
for (int i = 0; i < axes; i++) {
analog_axis_calibration_set(dev, i, &cal[i]);
}
analog_axis_calibration_log(dev);
return 0;
}
SETTINGS_STATIC_HANDLER_DEFINE(analog_axis, "aa-cal", NULL,
analog_axis_calibration_load, NULL, NULL);
int analog_axis_calibration_save(const struct device *dev)
{
struct analog_axis_calibration cal[MAX_AXES];
int axes;
char path[ANALOG_AXIS_SETTINGS_PATH_MAX];
int ret;
analog_axis_calibration_log(dev);
ret = snprintk(path, sizeof(path), "aa-cal/%s", dev->name);
if (ret < 0) {
return -EINVAL;
}
axes = analog_axis_num_axes(dev);
for (int i = 0; i < axes; i++) {
analog_axis_calibration_get(dev, i, &cal[i]);
}
ret = settings_save_one(path, &cal[0],
sizeof(struct analog_axis_calibration) * axes);
if (ret < 0) {
LOG_ERR("Settings save errord: %d", ret);
return ret;
}
return 0;
}