1 /*
2  * Copyright 2023 Google LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdlib.h>
8 #include <zephyr/device.h>
9 #include <zephyr/input/input_analog_axis.h>
10 #include <zephyr/input/input_analog_axis_settings.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/settings/settings.h>
13 #include <zephyr/sys/printk.h>
14 
15 LOG_MODULE_REGISTER(analog_axis_settings, CONFIG_INPUT_LOG_LEVEL);
16 
17 #define ANALOG_AXIS_SETTINGS_PATH_MAX 32
18 
19 #define MAX_AXES CONFIG_INPUT_ANALOG_AXIS_SETTINGS_MAX_AXES
20 
analog_axis_calibration_log(const struct device * dev)21 static void analog_axis_calibration_log(const struct device *dev)
22 {
23 	struct analog_axis_calibration cal;
24 	int i;
25 
26 	for (i = 0; i < analog_axis_num_axes(dev); i++) {
27 		analog_axis_calibration_get(dev, i, &cal);
28 
29 		LOG_INF("%s: ch: %d min: %d max: %d deadzone: %d",
30 			dev->name, i, cal.in_min, cal.in_max, cal.in_deadzone);
31 	}
32 }
33 
analog_axis_calibration_load(const char * key,size_t len_rd,settings_read_cb read_cb,void * cb_arg)34 static int analog_axis_calibration_load(const char *key, size_t len_rd,
35 					settings_read_cb read_cb, void *cb_arg)
36 {
37 	const struct device *dev;
38 	struct analog_axis_calibration cal[MAX_AXES];
39 	int axes;
40 	char dev_name[ANALOG_AXIS_SETTINGS_PATH_MAX];
41 	const char *next;
42 	int nlen;
43 	ssize_t len;
44 
45 	nlen = settings_name_next(key, &next);
46 	if (nlen + 1 > sizeof(dev_name)) {
47 		LOG_ERR("Setting name too long: %d", nlen);
48 		return -EINVAL;
49 	}
50 
51 	memcpy(dev_name, key, nlen);
52 	dev_name[nlen] = '\0';
53 
54 	dev = device_get_binding(dev_name);
55 	if (dev == NULL) {
56 		LOG_ERR("Cannot restore: device %s not available", dev_name);
57 		return -ENODEV;
58 	}
59 
60 	len = read_cb(cb_arg, cal, sizeof(cal));
61 	if (len < 0) {
62 		LOG_ERR("Data restore error: %d", len);
63 	}
64 
65 	axes = analog_axis_num_axes(dev);
66 	if (len != sizeof(struct analog_axis_calibration) * axes) {
67 		LOG_ERR("Invalid settings data length: %d, expected %d",
68 			len, sizeof(struct analog_axis_calibration) * axes);
69 		return -EIO;
70 	}
71 
72 	for (int i = 0; i < axes; i++) {
73 		analog_axis_calibration_set(dev, i, &cal[i]);
74 	}
75 
76 	analog_axis_calibration_log(dev);
77 
78 	return 0;
79 }
80 
81 SETTINGS_STATIC_HANDLER_DEFINE(analog_axis, "aa-cal", NULL,
82 			       analog_axis_calibration_load, NULL, NULL);
83 
analog_axis_calibration_save(const struct device * dev)84 int analog_axis_calibration_save(const struct device *dev)
85 {
86 	struct analog_axis_calibration cal[MAX_AXES];
87 	int axes;
88 	char path[ANALOG_AXIS_SETTINGS_PATH_MAX];
89 	int ret;
90 
91 	analog_axis_calibration_log(dev);
92 
93 	ret = snprintk(path, sizeof(path), "aa-cal/%s", dev->name);
94 	if (ret < 0) {
95 		return -EINVAL;
96 	}
97 
98 	axes = analog_axis_num_axes(dev);
99 	for (int i = 0; i < axes; i++) {
100 		analog_axis_calibration_get(dev, i, &cal[i]);
101 	}
102 
103 	ret = settings_save_one(path, &cal[0],
104 				sizeof(struct analog_axis_calibration) * axes);
105 	if (ret < 0) {
106 		LOG_ERR("Settings save errord: %d", ret);
107 		return ret;
108 	}
109 
110 	return 0;
111 }
112