1 /*
2  * Copyright (c) 2018 Diego Sueiro
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/sensor.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/rtio/rtio.h>
15 #include <zephyr/shell/shell.h>
16 #include <zephyr/sys/iterable_sections.h>
17 #include <zephyr/sys/util.h>
18 
19 LOG_MODULE_REGISTER(sensor_shell);
20 
21 #define SENSOR_GET_HELP                                                                            \
22 	"Get sensor data. Channel names are optional. All channels are read "                      \
23 	"when no channels are provided. Syntax:\n"                                                 \
24 	"<device_name> <channel name 0> .. <channel name N>"
25 
26 #define SENSOR_ATTR_GET_HELP                                                                       \
27 	"Get the sensor's channel attribute. Syntax:\n"                                            \
28 	"<device_name> [<channel_name 0> <attribute_name 0> .. "                                   \
29 	"<channel_name N> <attribute_name N>]"
30 
31 #define SENSOR_ATTR_SET_HELP                                                                       \
32 	"Set the sensor's channel attribute.\n"                                                    \
33 	"<device_name> <channel_name> <attribute_name> <value>"
34 
35 #define SENSOR_INFO_HELP "Get sensor info, such as vendor and model name, for all sensors."
36 
37 #define SENSOR_TRIG_HELP                                                                           \
38 	"Get or set the trigger type on a sensor. Currently only supports `data_ready`.\n"         \
39 	"<device_name> <on/off> <trigger_name>"
40 
41 const char *sensor_channel_name[SENSOR_CHAN_ALL] = {
42 	[SENSOR_CHAN_ACCEL_X] = "accel_x",
43 	[SENSOR_CHAN_ACCEL_Y] = "accel_y",
44 	[SENSOR_CHAN_ACCEL_Z] = "accel_z",
45 	[SENSOR_CHAN_ACCEL_XYZ] = "accel_xyz",
46 	[SENSOR_CHAN_GYRO_X] = "gyro_x",
47 	[SENSOR_CHAN_GYRO_Y] = "gyro_y",
48 	[SENSOR_CHAN_GYRO_Z] = "gyro_z",
49 	[SENSOR_CHAN_GYRO_XYZ] = "gyro_xyz",
50 	[SENSOR_CHAN_MAGN_X] = "magn_x",
51 	[SENSOR_CHAN_MAGN_Y] = "magn_y",
52 	[SENSOR_CHAN_MAGN_Z] = "magn_z",
53 	[SENSOR_CHAN_MAGN_XYZ] = "magn_xyz",
54 	[SENSOR_CHAN_DIE_TEMP] = "die_temp",
55 	[SENSOR_CHAN_AMBIENT_TEMP] = "ambient_temp",
56 	[SENSOR_CHAN_PRESS] = "press",
57 	[SENSOR_CHAN_PROX] = "prox",
58 	[SENSOR_CHAN_HUMIDITY] = "humidity",
59 	[SENSOR_CHAN_LIGHT] = "light",
60 	[SENSOR_CHAN_IR] = "ir",
61 	[SENSOR_CHAN_RED] = "red",
62 	[SENSOR_CHAN_GREEN] = "green",
63 	[SENSOR_CHAN_BLUE] = "blue",
64 	[SENSOR_CHAN_ALTITUDE] = "altitude",
65 	[SENSOR_CHAN_PM_1_0] = "pm_1_0",
66 	[SENSOR_CHAN_PM_2_5] = "pm_2_5",
67 	[SENSOR_CHAN_PM_10] = "pm_10",
68 	[SENSOR_CHAN_DISTANCE] = "distance",
69 	[SENSOR_CHAN_CO2] = "co2",
70 	[SENSOR_CHAN_VOC] = "voc",
71 	[SENSOR_CHAN_GAS_RES] = "gas_resistance",
72 	[SENSOR_CHAN_VOLTAGE] = "voltage",
73 	[SENSOR_CHAN_CURRENT] = "current",
74 	[SENSOR_CHAN_POWER] = "power",
75 	[SENSOR_CHAN_RESISTANCE] = "resistance",
76 	[SENSOR_CHAN_ROTATION] = "rotation",
77 	[SENSOR_CHAN_POS_DX] = "pos_dx",
78 	[SENSOR_CHAN_POS_DY] = "pos_dy",
79 	[SENSOR_CHAN_POS_DZ] = "pos_dz",
80 	[SENSOR_CHAN_RPM] = "rpm",
81 	[SENSOR_CHAN_GAUGE_VOLTAGE] = "gauge_voltage",
82 	[SENSOR_CHAN_GAUGE_AVG_CURRENT] = "gauge_avg_current",
83 	[SENSOR_CHAN_GAUGE_STDBY_CURRENT] = "gauge_stdby_current",
84 	[SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT] = "gauge_max_load_current",
85 	[SENSOR_CHAN_GAUGE_TEMP] = "gauge_temp",
86 	[SENSOR_CHAN_GAUGE_STATE_OF_CHARGE] = "gauge_state_of_charge",
87 	[SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY] = "gauge_full_cap",
88 	[SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY] = "gauge_remaining_cap",
89 	[SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY] = "gauge_nominal_cap",
90 	[SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY] = "gauge_full_avail_cap",
91 	[SENSOR_CHAN_GAUGE_AVG_POWER] = "gauge_avg_power",
92 	[SENSOR_CHAN_GAUGE_STATE_OF_HEALTH] = "gauge_state_of_health",
93 	[SENSOR_CHAN_GAUGE_TIME_TO_EMPTY] = "gauge_time_to_empty",
94 	[SENSOR_CHAN_GAUGE_TIME_TO_FULL] = "gauge_time_to_full",
95 	[SENSOR_CHAN_GAUGE_CYCLE_COUNT] = "gauge_cycle_count",
96 	[SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE] = "gauge_design_voltage",
97 	[SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE] = "gauge_desired_voltage",
98 	[SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT] = "gauge_desired_charging_current",
99 };
100 
101 static const char *sensor_attribute_name[SENSOR_ATTR_COMMON_COUNT] = {
102 	[SENSOR_ATTR_SAMPLING_FREQUENCY] = "sampling_frequency",
103 	[SENSOR_ATTR_LOWER_THRESH] = "lower_thresh",
104 	[SENSOR_ATTR_UPPER_THRESH] = "upper_thresh",
105 	[SENSOR_ATTR_SLOPE_TH] = "slope_th",
106 	[SENSOR_ATTR_SLOPE_DUR] = "slope_dur",
107 	[SENSOR_ATTR_HYSTERESIS] = "hysteresis",
108 	[SENSOR_ATTR_OVERSAMPLING] = "oversampling",
109 	[SENSOR_ATTR_FULL_SCALE] = "full_scale",
110 	[SENSOR_ATTR_OFFSET] = "offset",
111 	[SENSOR_ATTR_CALIB_TARGET] = "calib_target",
112 	[SENSOR_ATTR_CONFIGURATION] = "configuration",
113 	[SENSOR_ATTR_CALIBRATION] = "calibration",
114 	[SENSOR_ATTR_FEATURE_MASK] = "feature_mask",
115 	[SENSOR_ATTR_ALERT] = "alert",
116 	[SENSOR_ATTR_FF_DUR] = "ff_dur",
117 };
118 
119 /* Forward declaration */
120 static void data_ready_trigger_handler(const struct device *sensor,
121 				       const struct sensor_trigger *trigger);
122 
123 #define TRIGGER_DATA_ENTRY(trig_enum, str_name, handler_func)                                      \
124 	[(trig_enum)] = {.name = #str_name,                                                        \
125 			 .handler = (handler_func),                                                \
126 			 .trigger = {.chan = SENSOR_CHAN_ALL, .type = (trig_enum)}}
127 
128 /**
129  * @brief This table stores a mapping of string trigger names along with the sensor_trigger struct
130  * that gets passed to the driver to enable that trigger, plus a function pointer to a handler. If
131  * that pointer is NULL, this indicates there is not currently support for that trigger type in the
132  * sensor shell.
133  */
134 static const struct {
135 	const char *name;
136 	sensor_trigger_handler_t handler;
137 	struct sensor_trigger trigger;
138 } sensor_trigger_table[SENSOR_TRIG_COMMON_COUNT] = {
139 	TRIGGER_DATA_ENTRY(SENSOR_TRIG_TIMER, timer, NULL),
140 	TRIGGER_DATA_ENTRY(SENSOR_TRIG_DATA_READY, data_ready, data_ready_trigger_handler),
141 	TRIGGER_DATA_ENTRY(SENSOR_TRIG_DELTA, delta, NULL),
142 	TRIGGER_DATA_ENTRY(SENSOR_TRIG_NEAR_FAR, near_far, NULL),
143 	TRIGGER_DATA_ENTRY(SENSOR_TRIG_THRESHOLD, threshold, NULL),
144 	TRIGGER_DATA_ENTRY(SENSOR_TRIG_TAP, tap, NULL),
145 	TRIGGER_DATA_ENTRY(SENSOR_TRIG_DOUBLE_TAP, double_tap, NULL),
146 	TRIGGER_DATA_ENTRY(SENSOR_TRIG_FREEFALL, freefall, NULL),
147 	TRIGGER_DATA_ENTRY(SENSOR_TRIG_MOTION, motion, NULL),
148 	TRIGGER_DATA_ENTRY(SENSOR_TRIG_STATIONARY, stationary, NULL),
149 };
150 
151 enum dynamic_command_context {
152 	NONE,
153 	CTX_GET,
154 	CTX_ATTR_GET_SET,
155 };
156 
157 static enum dynamic_command_context current_cmd_ctx = NONE;
158 
159 /* Mutex for accessing shared RTIO/IODEV data structures */
160 K_MUTEX_DEFINE(cmd_get_mutex);
161 
162 /* Crate a single common config for one-shot reading */
163 static enum sensor_channel iodev_sensor_shell_channels[SENSOR_CHAN_ALL];
164 static struct sensor_read_config iodev_sensor_shell_read_config = {
165 	.sensor = NULL,
166 	.channels = iodev_sensor_shell_channels,
167 	.count = 0,
168 	.max = ARRAY_SIZE(iodev_sensor_shell_channels),
169 };
170 RTIO_IODEV_DEFINE(iodev_sensor_shell_read, &__sensor_iodev_api, &iodev_sensor_shell_read_config);
171 
172 /* Create the RTIO context to service the reading */
173 RTIO_DEFINE_WITH_MEMPOOL(sensor_read_rtio, 8, 8, 32, 64, 4);
174 
parse_named_int(const char * name,const char * heystack[],size_t count)175 static int parse_named_int(const char *name, const char *heystack[], size_t count)
176 {
177 	char *endptr;
178 	int i;
179 
180 	/* Attempt to parse channel name as a number first */
181 	i = strtoul(name, &endptr, 0);
182 
183 	if (*endptr == '\0') {
184 		return i;
185 	}
186 
187 	/* Channel name is not a number, look it up */
188 	for (i = 0; i < count; i++) {
189 		if (strcmp(name, heystack[i]) == 0) {
190 			return i;
191 		}
192 	}
193 
194 	return -ENOTSUP;
195 }
196 
parse_sensor_value(const char * val_str,struct sensor_value * out)197 static int parse_sensor_value(const char *val_str, struct sensor_value *out)
198 {
199 	const bool is_negative = val_str[0] == '-';
200 	const char *decimal_pos = strchr(val_str, '.');
201 	long value;
202 	char *endptr;
203 
204 	/* Parse int portion */
205 	value = strtol(val_str, &endptr, 0);
206 
207 	if (*endptr != '\0' && *endptr != '.') {
208 		return -EINVAL;
209 	}
210 	if (value > INT32_MAX || value < INT32_MIN) {
211 		return -EINVAL;
212 	}
213 	out->val1 = (int32_t)value;
214 
215 	if (decimal_pos == NULL) {
216 		return 0;
217 	}
218 
219 	/* Parse the decimal portion */
220 	value = strtoul(decimal_pos + 1, &endptr, 0);
221 	if (*endptr != '\0') {
222 		return -EINVAL;
223 	}
224 	while (value < 100000) {
225 		value *= 10;
226 	}
227 	if (value > INT32_C(999999)) {
228 		return -EINVAL;
229 	}
230 	out->val2 = (int32_t)value;
231 	if (is_negative) {
232 		out->val2 *= -1;
233 	}
234 	return 0;
235 }
236 
237 struct sensor_shell_processing_context {
238 	const struct device *dev;
239 	const struct shell *sh;
240 };
241 
sensor_shell_processing_callback(int result,uint8_t * buf,uint32_t buf_len,void * userdata)242 static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len,
243 					     void *userdata)
244 {
245 	struct sensor_shell_processing_context *ctx = userdata;
246 	const struct sensor_decoder_api *decoder;
247 	uint8_t decoded_buffer[128];
248 	int rc;
249 
250 	ARG_UNUSED(buf_len);
251 
252 	if (result < 0) {
253 		shell_error(ctx->sh, "Read failed");
254 		return;
255 	}
256 
257 	rc = sensor_get_decoder(ctx->dev, &decoder);
258 	if (rc != 0) {
259 		shell_error(ctx->sh, "Failed to get decoder for '%s'", ctx->dev->name);
260 		return;
261 	}
262 
263 	for (int channel = 0; channel < SENSOR_CHAN_ALL; ++channel) {
264 		uint32_t fit = 0;
265 		size_t base_size;
266 		size_t frame_size;
267 		size_t channel_idx = 0;
268 		uint16_t frame_count;
269 
270 		if (channel == SENSOR_CHAN_ACCEL_X || channel == SENSOR_CHAN_ACCEL_Y ||
271 		    channel == SENSOR_CHAN_ACCEL_Z || channel == SENSOR_CHAN_GYRO_X ||
272 		    channel == SENSOR_CHAN_GYRO_Y || channel == SENSOR_CHAN_GYRO_Z ||
273 		    channel == SENSOR_CHAN_MAGN_X || channel == SENSOR_CHAN_MAGN_Y ||
274 		    channel == SENSOR_CHAN_MAGN_Z || channel == SENSOR_CHAN_POS_DY ||
275 		    channel == SENSOR_CHAN_POS_DZ) {
276 			continue;
277 		}
278 
279 		rc = decoder->get_size_info(channel, &base_size, &frame_size);
280 		if (rc != 0) {
281 			/* Channel not supported, skipping */
282 			continue;
283 		}
284 
285 		if (base_size > ARRAY_SIZE(decoded_buffer)) {
286 			shell_error(ctx->sh,
287 				    "Channel (%d) requires %zu bytes to decode, but only %zu are "
288 				    "available",
289 				    channel, base_size, ARRAY_SIZE(decoded_buffer));
290 			continue;
291 		}
292 
293 		while (decoder->get_frame_count(buf, channel, channel_idx, &frame_count) == 0) {
294 			fit = 0;
295 			while (decoder->decode(buf, channel, channel_idx, &fit, 1, decoded_buffer) >
296 			       0) {
297 
298 				switch (channel) {
299 				case SENSOR_CHAN_ACCEL_XYZ:
300 				case SENSOR_CHAN_GYRO_XYZ:
301 				case SENSOR_CHAN_MAGN_XYZ:
302 				case SENSOR_CHAN_POS_DX: {
303 					struct sensor_three_axis_data *data =
304 						(struct sensor_three_axis_data *)decoded_buffer;
305 
306 					shell_info(ctx->sh,
307 						   "channel idx=%d %s shift=%d "
308 						   "value=%" PRIsensor_three_axis_data,
309 						   channel, sensor_channel_name[channel],
310 						   data->shift,
311 						   PRIsensor_three_axis_data_arg(*data, 0));
312 					break;
313 				}
314 				case SENSOR_CHAN_PROX: {
315 					struct sensor_byte_data *data =
316 						(struct sensor_byte_data *)decoded_buffer;
317 
318 					shell_info(ctx->sh,
319 						   "channel idx=%d %s value=%" PRIsensor_byte_data(
320 							   is_near),
321 						   channel, sensor_channel_name[channel],
322 						   PRIsensor_byte_data_arg(*data, 0, is_near));
323 					break;
324 				}
325 				default: {
326 					struct sensor_q31_data *data =
327 						(struct sensor_q31_data *)decoded_buffer;
328 
329 					shell_info(ctx->sh,
330 						   "channel idx=%d %s shift=%d "
331 						   "value=%" PRIsensor_q31_data,
332 						   channel,
333 						   (channel >= ARRAY_SIZE(sensor_channel_name))
334 							   ? ""
335 							   : sensor_channel_name[channel],
336 						   data->shift, PRIsensor_q31_data_arg(*data, 0));
337 					break;
338 				}
339 				}
340 			}
341 			++channel_idx;
342 		}
343 	}
344 }
345 
cmd_get_sensor(const struct shell * sh,size_t argc,char * argv[])346 static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[])
347 {
348 	const struct device *dev;
349 	int count = 0;
350 	int err;
351 
352 	err = k_mutex_lock(&cmd_get_mutex, K_NO_WAIT);
353 	if (err < 0) {
354 		shell_error(sh, "Another sensor reading in progress");
355 		return err;
356 	}
357 
358 	dev = device_get_binding(argv[1]);
359 	if (dev == NULL) {
360 		shell_error(sh, "Device unknown (%s)", argv[1]);
361 		k_mutex_unlock(&cmd_get_mutex);
362 		return -ENODEV;
363 	}
364 
365 	if (argc == 2) {
366 		/* read all channels */
367 		for (int i = 0; i < ARRAY_SIZE(iodev_sensor_shell_channels); ++i) {
368 			if (SENSOR_CHANNEL_3_AXIS(i)) {
369 				continue;
370 			}
371 			iodev_sensor_shell_channels[count++] = i;
372 		}
373 	} else {
374 		/* read specific channels */
375 		for (int i = 2; i < argc; ++i) {
376 			int chan = parse_named_int(argv[i], sensor_channel_name,
377 						   ARRAY_SIZE(sensor_channel_name));
378 
379 			if (chan < 0) {
380 				shell_error(sh, "Failed to read channel (%s)", argv[i]);
381 				continue;
382 			}
383 			iodev_sensor_shell_channels[count++] = chan;
384 		}
385 	}
386 
387 	if (count == 0) {
388 		shell_error(sh, "No channels to read, bailing");
389 		k_mutex_unlock(&cmd_get_mutex);
390 		return -EINVAL;
391 	}
392 	iodev_sensor_shell_read_config.sensor = dev;
393 	iodev_sensor_shell_read_config.count = count;
394 
395 	struct sensor_shell_processing_context ctx = {
396 		.dev = dev,
397 		.sh = sh,
398 	};
399 	err = sensor_read(&iodev_sensor_shell_read, &sensor_read_rtio, &ctx);
400 	if (err < 0) {
401 		shell_error(sh, "Failed to read sensor: %d", err);
402 	}
403 	sensor_processing_with_callback(&sensor_read_rtio, sensor_shell_processing_callback);
404 
405 	k_mutex_unlock(&cmd_get_mutex);
406 
407 	return 0;
408 }
409 
cmd_sensor_attr_set(const struct shell * shell_ptr,size_t argc,char * argv[])410 static int cmd_sensor_attr_set(const struct shell *shell_ptr, size_t argc, char *argv[])
411 {
412 	const struct device *dev;
413 	int rc;
414 
415 	dev = device_get_binding(argv[1]);
416 	if (dev == NULL) {
417 		shell_error(shell_ptr, "Device unknown (%s)", argv[1]);
418 		return -ENODEV;
419 	}
420 
421 	for (size_t i = 2; i < argc; i += 3) {
422 		int channel = parse_named_int(argv[i], sensor_channel_name,
423 					      ARRAY_SIZE(sensor_channel_name));
424 		int attr = parse_named_int(argv[i + 1], sensor_attribute_name,
425 					   ARRAY_SIZE(sensor_attribute_name));
426 		struct sensor_value value = {0};
427 
428 		if (channel < 0) {
429 			shell_error(shell_ptr, "Channel '%s' unknown", argv[i]);
430 			return -EINVAL;
431 		}
432 		if (attr < 0) {
433 			shell_error(shell_ptr, "Attribute '%s' unknown", argv[i + 1]);
434 			return -EINVAL;
435 		}
436 		if (parse_sensor_value(argv[i + 2], &value)) {
437 			shell_error(shell_ptr, "Sensor value '%s' invalid", argv[i + 2]);
438 			return -EINVAL;
439 		}
440 
441 		rc = sensor_attr_set(dev, channel, attr, &value);
442 		if (rc) {
443 			shell_error(shell_ptr, "Failed to set channel(%s) attribute(%s): %d",
444 				    sensor_channel_name[channel], sensor_attribute_name[attr], rc);
445 			continue;
446 		}
447 		shell_info(shell_ptr, "%s channel=%s, attr=%s set to value=%s", dev->name,
448 			   sensor_channel_name[channel], sensor_attribute_name[attr], argv[i + 2]);
449 	}
450 	return 0;
451 }
452 
cmd_sensor_attr_get_handler(const struct shell * shell_ptr,const struct device * dev,const char * channel_name,const char * attr_name,bool print_missing_attribute)453 static void cmd_sensor_attr_get_handler(const struct shell *shell_ptr, const struct device *dev,
454 					const char *channel_name, const char *attr_name,
455 					bool print_missing_attribute)
456 {
457 	int channel =
458 		parse_named_int(channel_name, sensor_channel_name, ARRAY_SIZE(sensor_channel_name));
459 	int attr = parse_named_int(attr_name, sensor_attribute_name,
460 				   ARRAY_SIZE(sensor_attribute_name));
461 	struct sensor_value value = {0};
462 	int rc;
463 
464 	if (channel < 0) {
465 		shell_error(shell_ptr, "Channel '%s' unknown", channel_name);
466 		return;
467 	}
468 	if (attr < 0) {
469 		shell_error(shell_ptr, "Attribute '%s' unknown", attr_name);
470 		return;
471 	}
472 
473 	rc = sensor_attr_get(dev, channel, attr, &value);
474 
475 	if (rc != 0) {
476 		if (rc == -EINVAL && !print_missing_attribute) {
477 			return;
478 		}
479 		shell_error(shell_ptr, "Failed to get channel(%s) attribute(%s): %d",
480 			    sensor_channel_name[channel], sensor_attribute_name[attr], rc);
481 		return;
482 	}
483 
484 	shell_info(shell_ptr, "%s(channel=%s, attr=%s) value=%.6f", dev->name,
485 		   sensor_channel_name[channel], sensor_attribute_name[attr],
486 		   sensor_value_to_double(&value));
487 }
488 
cmd_sensor_attr_get(const struct shell * shell_ptr,size_t argc,char * argv[])489 static int cmd_sensor_attr_get(const struct shell *shell_ptr, size_t argc, char *argv[])
490 {
491 	const struct device *dev;
492 
493 	dev = device_get_binding(argv[1]);
494 	if (dev == NULL) {
495 		shell_error(shell_ptr, "Device unknown (%s)", argv[1]);
496 		return -ENODEV;
497 	}
498 
499 	if (argc > 2) {
500 		for (size_t i = 2; i < argc; i += 2) {
501 			cmd_sensor_attr_get_handler(shell_ptr, dev, argv[i], argv[i + 1],
502 						    /*print_missing_attribute=*/true);
503 		}
504 	} else {
505 		for (size_t channel_idx = 0; channel_idx < ARRAY_SIZE(sensor_channel_name);
506 		     ++channel_idx) {
507 			for (size_t attr_idx = 0; attr_idx < ARRAY_SIZE(sensor_attribute_name);
508 			     ++attr_idx) {
509 				cmd_sensor_attr_get_handler(shell_ptr, dev,
510 							    sensor_channel_name[channel_idx],
511 							    sensor_attribute_name[attr_idx],
512 							    /*print_missing_attribute=*/false);
513 			}
514 		}
515 	}
516 	return 0;
517 }
518 
519 static void channel_name_get(size_t idx, struct shell_static_entry *entry);
520 
521 SHELL_DYNAMIC_CMD_CREATE(dsub_channel_name, channel_name_get);
522 
attribute_name_get(size_t idx,struct shell_static_entry * entry)523 static void attribute_name_get(size_t idx, struct shell_static_entry *entry)
524 {
525 	int cnt = 0;
526 
527 	entry->syntax = NULL;
528 	entry->handler = NULL;
529 	entry->help = NULL;
530 	entry->subcmd = &dsub_channel_name;
531 
532 	for (int i = 0; i < SENSOR_ATTR_COMMON_COUNT; i++) {
533 		if (sensor_attribute_name[i] != NULL) {
534 			if (cnt == idx) {
535 				entry->syntax = sensor_attribute_name[i];
536 				break;
537 			}
538 			cnt++;
539 		}
540 	}
541 }
542 SHELL_DYNAMIC_CMD_CREATE(dsub_attribute_name, attribute_name_get);
543 
channel_name_get(size_t idx,struct shell_static_entry * entry)544 static void channel_name_get(size_t idx, struct shell_static_entry *entry)
545 {
546 	int cnt = 0;
547 
548 	entry->syntax = NULL;
549 	entry->handler = NULL;
550 	entry->help = NULL;
551 	if (current_cmd_ctx == CTX_GET) {
552 		entry->subcmd = &dsub_channel_name;
553 	} else if (current_cmd_ctx == CTX_ATTR_GET_SET) {
554 		entry->subcmd = &dsub_attribute_name;
555 	} else {
556 		entry->subcmd = NULL;
557 	}
558 
559 	for (int i = 0; i < SENSOR_CHAN_ALL; i++) {
560 		if (sensor_channel_name[i] != NULL) {
561 			if (cnt == idx) {
562 				entry->syntax = sensor_channel_name[i];
563 				break;
564 			}
565 			cnt++;
566 		}
567 	}
568 }
569 
570 static void device_name_get(size_t idx, struct shell_static_entry *entry);
571 
572 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
573 
device_name_get(size_t idx,struct shell_static_entry * entry)574 static void device_name_get(size_t idx, struct shell_static_entry *entry)
575 {
576 	const struct device *dev = shell_device_lookup(idx, NULL);
577 
578 	current_cmd_ctx = CTX_GET;
579 	entry->syntax = (dev != NULL) ? dev->name : NULL;
580 	entry->handler = NULL;
581 	entry->help = NULL;
582 	entry->subcmd = &dsub_channel_name;
583 }
584 
device_name_get_for_attr(size_t idx,struct shell_static_entry * entry)585 static void device_name_get_for_attr(size_t idx, struct shell_static_entry *entry)
586 {
587 	const struct device *dev = shell_device_lookup(idx, NULL);
588 
589 	current_cmd_ctx = CTX_ATTR_GET_SET;
590 	entry->syntax = (dev != NULL) ? dev->name : NULL;
591 	entry->handler = NULL;
592 	entry->help = NULL;
593 	entry->subcmd = &dsub_channel_name;
594 }
595 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name_for_attr, device_name_get_for_attr);
596 
trigger_name_get(size_t idx,struct shell_static_entry * entry)597 static void trigger_name_get(size_t idx, struct shell_static_entry *entry)
598 {
599 	int cnt = 0;
600 
601 	entry->syntax = NULL;
602 	entry->handler = NULL;
603 	entry->help = NULL;
604 	entry->subcmd = NULL;
605 
606 	for (int i = 0; i < SENSOR_TRIG_COMMON_COUNT; i++) {
607 		if (sensor_trigger_table[i].name != NULL) {
608 			if (cnt == idx) {
609 				entry->syntax = sensor_trigger_table[i].name;
610 				break;
611 			}
612 			cnt++;
613 		}
614 	}
615 }
616 
617 SHELL_DYNAMIC_CMD_CREATE(dsub_trigger_name, trigger_name_get);
618 
trigger_on_off_get(size_t idx,struct shell_static_entry * entry)619 static void trigger_on_off_get(size_t idx, struct shell_static_entry *entry)
620 {
621 	entry->handler = NULL;
622 	entry->help = NULL;
623 	entry->subcmd = &dsub_trigger_name;
624 
625 	switch (idx) {
626 	case 0:
627 		entry->syntax = "on";
628 		break;
629 	case 1:
630 		entry->syntax = "off";
631 		break;
632 	default:
633 		entry->syntax = NULL;
634 		break;
635 	}
636 }
637 
638 SHELL_DYNAMIC_CMD_CREATE(dsub_trigger_onoff, trigger_on_off_get);
639 
device_name_get_for_trigger(size_t idx,struct shell_static_entry * entry)640 static void device_name_get_for_trigger(size_t idx, struct shell_static_entry *entry)
641 {
642 	const struct device *dev = shell_device_lookup(idx, NULL);
643 
644 	entry->syntax = (dev != NULL) ? dev->name : NULL;
645 	entry->handler = NULL;
646 	entry->help = NULL;
647 	entry->subcmd = &dsub_trigger_onoff;
648 }
649 
650 SHELL_DYNAMIC_CMD_CREATE(dsub_trigger, device_name_get_for_trigger);
651 
cmd_get_sensor_info(const struct shell * sh,size_t argc,char ** argv)652 static int cmd_get_sensor_info(const struct shell *sh, size_t argc, char **argv)
653 {
654 	ARG_UNUSED(argc);
655 	ARG_UNUSED(argv);
656 
657 #ifdef CONFIG_SENSOR_INFO
658 	const char *null_str = "(null)";
659 
660 	STRUCT_SECTION_FOREACH(sensor_info, sensor) {
661 		shell_print(sh,
662 			    "device name: %s, vendor: %s, model: %s, "
663 			    "friendly name: %s",
664 			    sensor->dev->name, sensor->vendor ? sensor->vendor : null_str,
665 			    sensor->model ? sensor->model : null_str,
666 			    sensor->friendly_name ? sensor->friendly_name : null_str);
667 	}
668 	return 0;
669 #else
670 	return -EINVAL;
671 #endif
672 }
673 
674 enum sample_stats_state {
675 	SAMPLE_STATS_STATE_UNINITIALIZED = 0,
676 	SAMPLE_STATS_STATE_ENABLED,
677 	SAMPLE_STATS_STATE_DISABLED,
678 };
679 
680 struct sample_stats {
681 	int64_t accumulator;
682 	uint32_t count;
683 	uint64_t sample_window_start;
684 	enum sample_stats_state state;
685 };
686 
data_ready_trigger_handler(const struct device * sensor,const struct sensor_trigger * trigger)687 static void data_ready_trigger_handler(const struct device *sensor,
688 				       const struct sensor_trigger *trigger)
689 {
690 	static struct sample_stats stats[SENSOR_CHAN_ALL];
691 	const int64_t now = k_uptime_get();
692 	struct sensor_value value;
693 
694 	if (sensor_sample_fetch(sensor)) {
695 		LOG_ERR("Failed to fetch samples on data ready handler");
696 	}
697 	for (int i = 0; i < SENSOR_CHAN_ALL; ++i) {
698 		int rc;
699 
700 		/* Skip disabled channels */
701 		if (stats[i].state == SAMPLE_STATS_STATE_DISABLED) {
702 			continue;
703 		}
704 		/* Skip 3 axis channels */
705 		if (i == SENSOR_CHAN_ACCEL_XYZ || i == SENSOR_CHAN_GYRO_XYZ ||
706 		    i == SENSOR_CHAN_MAGN_XYZ) {
707 			continue;
708 		}
709 
710 		rc = sensor_channel_get(sensor, i, &value);
711 		if (rc == -ENOTSUP && stats[i].state == SAMPLE_STATS_STATE_UNINITIALIZED) {
712 			/* Stop reading this channel if the driver told us it's not supported. */
713 			stats[i].state = SAMPLE_STATS_STATE_DISABLED;
714 		}
715 		if (rc != 0) {
716 			/* Skip on any error. */
717 			continue;
718 		}
719 		/* Do something with the data */
720 		stats[i].accumulator += value.val1 * INT64_C(1000000) + value.val2;
721 		if (stats[i].count++ == 0) {
722 			stats[i].sample_window_start = now;
723 		} else if (now > stats[i].sample_window_start +
724 					 CONFIG_SENSOR_SHELL_TRIG_PRINT_TIMEOUT_MS) {
725 			int64_t micro_value = stats[i].accumulator / stats[i].count;
726 
727 			value.val1 = micro_value / 1000000;
728 			value.val2 = (int32_t)llabs(micro_value - (value.val1 * 1000000));
729 			LOG_INF("chan=%d, num_samples=%u, data=%d.%06d", i, stats[i].count,
730 				value.val1, value.val2);
731 
732 			stats[i].accumulator = 0;
733 			stats[i].count = 0;
734 		}
735 	}
736 }
737 
cmd_trig_sensor(const struct shell * sh,size_t argc,char ** argv)738 static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv)
739 {
740 	const struct device *dev;
741 	enum sensor_trigger_type trigger;
742 	int err;
743 
744 	if (argc < 4) {
745 		shell_error(sh, "Wrong number of args");
746 		return -EINVAL;
747 	}
748 
749 	/* Parse device name */
750 	dev = device_get_binding(argv[1]);
751 	if (dev == NULL) {
752 		shell_error(sh, "Device unknown (%s)", argv[1]);
753 		return -ENODEV;
754 	}
755 
756 	/* Map the trigger string to an enum value */
757 	for (trigger = 0; trigger < ARRAY_SIZE(sensor_trigger_table); trigger++) {
758 		if (strcmp(argv[3], sensor_trigger_table[trigger].name) == 0) {
759 			break;
760 		}
761 	}
762 	if (trigger >= SENSOR_TRIG_COMMON_COUNT || sensor_trigger_table[trigger].handler == NULL) {
763 		shell_error(sh, "Unsupported trigger type (%s)", argv[3]);
764 		return -ENOTSUP;
765 	}
766 
767 	/* Parse on/off */
768 	if (strcmp(argv[2], "on") == 0) {
769 		err = sensor_trigger_set(dev, &sensor_trigger_table[trigger].trigger,
770 					 sensor_trigger_table[trigger].handler);
771 	} else if (strcmp(argv[2], "off") == 0) {
772 		/* Clear the handler for the given trigger on this device */
773 		err = sensor_trigger_set(dev, &sensor_trigger_table[trigger].trigger, NULL);
774 	} else {
775 		shell_error(sh, "Pass 'on' or 'off' to enable/disable trigger");
776 		return -EINVAL;
777 	}
778 
779 	if (err) {
780 		shell_error(sh, "Error while setting trigger %d on device %s (%d)", trigger,
781 			    argv[1], err);
782 	}
783 
784 	return err;
785 }
786 
787 /* clang-format off */
788 SHELL_STATIC_SUBCMD_SET_CREATE(sub_sensor,
789 	SHELL_CMD_ARG(get, &dsub_device_name, SENSOR_GET_HELP, cmd_get_sensor,
790 			2, 255),
791 	SHELL_CMD_ARG(attr_set, &dsub_device_name_for_attr, SENSOR_ATTR_SET_HELP,
792 			cmd_sensor_attr_set, 2, 255),
793 	SHELL_CMD_ARG(attr_get, &dsub_device_name_for_attr, SENSOR_ATTR_GET_HELP,
794 			cmd_sensor_attr_get, 2, 255),
795 	SHELL_COND_CMD(CONFIG_SENSOR_INFO, info, NULL, SENSOR_INFO_HELP,
796 			cmd_get_sensor_info),
797 	SHELL_CMD_ARG(trig, &dsub_trigger, SENSOR_TRIG_HELP, cmd_trig_sensor,
798 			2, 255),
799 	SHELL_SUBCMD_SET_END
800 	);
801 /* clang-format on */
802 
803 SHELL_CMD_REGISTER(sensor, &sub_sensor, "Sensor commands", NULL);
804