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 #include "sensor_shell.h"
20
21 LOG_MODULE_REGISTER(sensor_shell, CONFIG_SENSOR_LOG_LEVEL);
22
23 #define SENSOR_GET_HELP \
24 "Get sensor data. Channel names are optional. All channels are read " \
25 "when no channels are provided. Syntax:\n" \
26 "<device_name> <channel name 0> .. <channel name N>"
27
28 #define SENSOR_STREAM_HELP \
29 "Start/stop streaming sensor data. Data ready trigger will be used if no triggers " \
30 "are provided. Syntax:\n" \
31 "<device_name> on|off <trigger name> incl|drop|nop"
32
33 #define SENSOR_ATTR_GET_HELP \
34 "Get the sensor's channel attribute. Syntax:\n" \
35 "<device_name> [<channel_name 0> <attribute_name 0> .. " \
36 "<channel_name N> <attribute_name N>]"
37
38 #define SENSOR_ATTR_SET_HELP \
39 "Set the sensor's channel attribute.\n" \
40 "<device_name> <channel_name> <attribute_name> <value>"
41
42 #define SENSOR_INFO_HELP "Get sensor info, such as vendor and model name, for all sensors."
43
44 #define SENSOR_TRIG_HELP \
45 "Get or set the trigger type on a sensor. Currently only supports `data_ready`.\n" \
46 "<device_name> <on/off> <trigger_name>"
47
48 static const char *sensor_channel_name[SENSOR_CHAN_COMMON_COUNT] = {
49 [SENSOR_CHAN_ACCEL_X] = "accel_x",
50 [SENSOR_CHAN_ACCEL_Y] = "accel_y",
51 [SENSOR_CHAN_ACCEL_Z] = "accel_z",
52 [SENSOR_CHAN_ACCEL_XYZ] = "accel_xyz",
53 [SENSOR_CHAN_GYRO_X] = "gyro_x",
54 [SENSOR_CHAN_GYRO_Y] = "gyro_y",
55 [SENSOR_CHAN_GYRO_Z] = "gyro_z",
56 [SENSOR_CHAN_GYRO_XYZ] = "gyro_xyz",
57 [SENSOR_CHAN_MAGN_X] = "magn_x",
58 [SENSOR_CHAN_MAGN_Y] = "magn_y",
59 [SENSOR_CHAN_MAGN_Z] = "magn_z",
60 [SENSOR_CHAN_MAGN_XYZ] = "magn_xyz",
61 [SENSOR_CHAN_DIE_TEMP] = "die_temp",
62 [SENSOR_CHAN_AMBIENT_TEMP] = "ambient_temp",
63 [SENSOR_CHAN_PRESS] = "press",
64 [SENSOR_CHAN_PROX] = "prox",
65 [SENSOR_CHAN_HUMIDITY] = "humidity",
66 [SENSOR_CHAN_LIGHT] = "light",
67 [SENSOR_CHAN_IR] = "ir",
68 [SENSOR_CHAN_RED] = "red",
69 [SENSOR_CHAN_GREEN] = "green",
70 [SENSOR_CHAN_BLUE] = "blue",
71 [SENSOR_CHAN_ALTITUDE] = "altitude",
72 [SENSOR_CHAN_PM_1_0] = "pm_1_0",
73 [SENSOR_CHAN_PM_2_5] = "pm_2_5",
74 [SENSOR_CHAN_PM_10] = "pm_10",
75 [SENSOR_CHAN_DISTANCE] = "distance",
76 [SENSOR_CHAN_CO2] = "co2",
77 [SENSOR_CHAN_O2] = "o2",
78 [SENSOR_CHAN_VOC] = "voc",
79 [SENSOR_CHAN_GAS_RES] = "gas_resistance",
80 [SENSOR_CHAN_VOLTAGE] = "voltage",
81 [SENSOR_CHAN_VSHUNT] = "vshunt",
82 [SENSOR_CHAN_CURRENT] = "current",
83 [SENSOR_CHAN_POWER] = "power",
84 [SENSOR_CHAN_RESISTANCE] = "resistance",
85 [SENSOR_CHAN_ROTATION] = "rotation",
86 [SENSOR_CHAN_POS_DX] = "pos_dx",
87 [SENSOR_CHAN_POS_DY] = "pos_dy",
88 [SENSOR_CHAN_POS_DZ] = "pos_dz",
89 [SENSOR_CHAN_POS_DXYZ] = "pos_dxyz",
90 [SENSOR_CHAN_RPM] = "rpm",
91 [SENSOR_CHAN_GAUGE_VOLTAGE] = "gauge_voltage",
92 [SENSOR_CHAN_GAUGE_AVG_CURRENT] = "gauge_avg_current",
93 [SENSOR_CHAN_GAUGE_STDBY_CURRENT] = "gauge_stdby_current",
94 [SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT] = "gauge_max_load_current",
95 [SENSOR_CHAN_GAUGE_TEMP] = "gauge_temp",
96 [SENSOR_CHAN_GAUGE_STATE_OF_CHARGE] = "gauge_state_of_charge",
97 [SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY] = "gauge_full_cap",
98 [SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY] = "gauge_remaining_cap",
99 [SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY] = "gauge_nominal_cap",
100 [SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY] = "gauge_full_avail_cap",
101 [SENSOR_CHAN_GAUGE_AVG_POWER] = "gauge_avg_power",
102 [SENSOR_CHAN_GAUGE_STATE_OF_HEALTH] = "gauge_state_of_health",
103 [SENSOR_CHAN_GAUGE_TIME_TO_EMPTY] = "gauge_time_to_empty",
104 [SENSOR_CHAN_GAUGE_TIME_TO_FULL] = "gauge_time_to_full",
105 [SENSOR_CHAN_GAUGE_CYCLE_COUNT] = "gauge_cycle_count",
106 [SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE] = "gauge_design_voltage",
107 [SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE] = "gauge_desired_voltage",
108 [SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT] = "gauge_desired_charging_current",
109 [SENSOR_CHAN_ALL] = "all",
110 };
111
112 static const char *sensor_attribute_name[SENSOR_ATTR_COMMON_COUNT] = {
113 [SENSOR_ATTR_SAMPLING_FREQUENCY] = "sampling_frequency",
114 [SENSOR_ATTR_LOWER_THRESH] = "lower_thresh",
115 [SENSOR_ATTR_UPPER_THRESH] = "upper_thresh",
116 [SENSOR_ATTR_SLOPE_TH] = "slope_th",
117 [SENSOR_ATTR_SLOPE_DUR] = "slope_dur",
118 [SENSOR_ATTR_HYSTERESIS] = "hysteresis",
119 [SENSOR_ATTR_OVERSAMPLING] = "oversampling",
120 [SENSOR_ATTR_FULL_SCALE] = "full_scale",
121 [SENSOR_ATTR_OFFSET] = "offset",
122 [SENSOR_ATTR_CALIB_TARGET] = "calib_target",
123 [SENSOR_ATTR_CONFIGURATION] = "configuration",
124 [SENSOR_ATTR_CALIBRATION] = "calibration",
125 [SENSOR_ATTR_FEATURE_MASK] = "feature_mask",
126 [SENSOR_ATTR_ALERT] = "alert",
127 [SENSOR_ATTR_FF_DUR] = "ff_dur",
128 [SENSOR_ATTR_BATCH_DURATION] = "batch_dur",
129 };
130
131 enum sample_stats_state {
132 SAMPLE_STATS_STATE_UNINITIALIZED = 0,
133 SAMPLE_STATS_STATE_ENABLED,
134 SAMPLE_STATS_STATE_DISABLED,
135 };
136
137 struct sample_stats {
138 int64_t accumulator;
139 uint64_t sample_window_start;
140 uint32_t count;
141 enum sample_stats_state state;
142 };
143
144 static struct sample_stats sensor_stats[CONFIG_SENSOR_SHELL_MAX_TRIGGER_DEVICES][SENSOR_CHAN_ALL];
145
146 static const struct device *sensor_trigger_devices[CONFIG_SENSOR_SHELL_MAX_TRIGGER_DEVICES];
147
device_is_sensor(const struct device * dev)148 static bool device_is_sensor(const struct device *dev)
149 {
150 #ifdef CONFIG_SENSOR_INFO
151 STRUCT_SECTION_FOREACH(sensor_info, sensor) {
152 if (sensor->dev == dev) {
153 return true;
154 }
155 }
156 return false;
157 #else
158 return true;
159 #endif /* CONFIG_SENSOR_INFO */
160 }
161
find_sensor_trigger_device(const struct device * sensor)162 static int find_sensor_trigger_device(const struct device *sensor)
163 {
164 for (int i = 0; i < CONFIG_SENSOR_SHELL_MAX_TRIGGER_DEVICES; i++) {
165 if (sensor_trigger_devices[i] == sensor) {
166 return i;
167 }
168 }
169 return -1;
170 }
171
172 /* Forward declaration */
173 static void data_ready_trigger_handler(const struct device *sensor,
174 const struct sensor_trigger *trigger);
175
176 #define TRIGGER_DATA_ENTRY(trig_enum, str_name, handler_func) \
177 [(trig_enum)] = {.name = #str_name, \
178 .handler = (handler_func), \
179 .trigger = {.chan = SENSOR_CHAN_ALL, .type = (trig_enum)}}
180
181 /**
182 * @brief This table stores a mapping of string trigger names along with the sensor_trigger struct
183 * that gets passed to the driver to enable that trigger, plus a function pointer to a handler. If
184 * that pointer is NULL, this indicates there is not currently support for that trigger type in the
185 * sensor shell.
186 */
187 static const struct {
188 const char *name;
189 sensor_trigger_handler_t handler;
190 struct sensor_trigger trigger;
191 } sensor_trigger_table[SENSOR_TRIG_COMMON_COUNT] = {
192 TRIGGER_DATA_ENTRY(SENSOR_TRIG_TIMER, timer, NULL),
193 TRIGGER_DATA_ENTRY(SENSOR_TRIG_DATA_READY, data_ready, data_ready_trigger_handler),
194 TRIGGER_DATA_ENTRY(SENSOR_TRIG_DELTA, delta, NULL),
195 TRIGGER_DATA_ENTRY(SENSOR_TRIG_NEAR_FAR, near_far, NULL),
196 TRIGGER_DATA_ENTRY(SENSOR_TRIG_THRESHOLD, threshold, NULL),
197 TRIGGER_DATA_ENTRY(SENSOR_TRIG_TAP, tap, NULL),
198 TRIGGER_DATA_ENTRY(SENSOR_TRIG_DOUBLE_TAP, double_tap, NULL),
199 TRIGGER_DATA_ENTRY(SENSOR_TRIG_FREEFALL, freefall, NULL),
200 TRIGGER_DATA_ENTRY(SENSOR_TRIG_MOTION, motion, NULL),
201 TRIGGER_DATA_ENTRY(SENSOR_TRIG_STATIONARY, stationary, NULL),
202 TRIGGER_DATA_ENTRY(SENSOR_TRIG_FIFO_WATERMARK, fifo_wm, NULL),
203 TRIGGER_DATA_ENTRY(SENSOR_TRIG_FIFO_FULL, fifo_full, NULL),
204 };
205
206 /**
207 * Lookup the sensor trigger data by name
208 *
209 * @param name The name of the trigger
210 * @return < 0 on error
211 * @return >= 0 if found
212 */
sensor_trigger_name_lookup(const char * name)213 static int sensor_trigger_name_lookup(const char *name)
214 {
215 for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); ++i) {
216 if (strcmp(name, sensor_trigger_table[i].name) == 0) {
217 return i;
218 }
219 }
220 return -1;
221 }
222
223 enum dynamic_command_context {
224 NONE,
225 CTX_GET,
226 CTX_ATTR_GET_SET,
227 CTX_STREAM_ON_OFF,
228 };
229
230 static enum dynamic_command_context current_cmd_ctx = NONE;
231
232 /* Mutex for accessing shared RTIO/IODEV data structures */
233 K_MUTEX_DEFINE(cmd_get_mutex);
234
235 /* Crate a single common config for one-shot reading */
236 static struct sensor_chan_spec iodev_sensor_shell_channels[SENSOR_CHAN_ALL];
237 static struct sensor_read_config iodev_sensor_shell_read_config = {
238 .sensor = NULL,
239 .is_streaming = false,
240 .channels = iodev_sensor_shell_channels,
241 .count = 0,
242 .max = ARRAY_SIZE(iodev_sensor_shell_channels),
243 };
244 RTIO_IODEV_DEFINE(iodev_sensor_shell_read, &__sensor_iodev_api, &iodev_sensor_shell_read_config);
245
246 /* Create the RTIO context to service the reading */
247 RTIO_DEFINE_WITH_MEMPOOL(sensor_read_rtio, 8, 8, 32, 64, 4);
248
parse_named_int(const char * name,const char * heystack[],size_t count)249 static int parse_named_int(const char *name, const char *heystack[], size_t count)
250 {
251 char *endptr;
252 int i;
253
254 /* Attempt to parse channel name as a number first */
255 i = strtoul(name, &endptr, 0);
256
257 if (*endptr == '\0') {
258 return i;
259 }
260
261 /* Channel name is not a number, look it up */
262 for (i = 0; i < count; i++) {
263 if (strcmp(name, heystack[i]) == 0) {
264 return i;
265 }
266 }
267
268 return -ENOTSUP;
269 }
270
parse_sensor_value(const char * val_str,struct sensor_value * out)271 static int parse_sensor_value(const char *val_str, struct sensor_value *out)
272 {
273 const bool is_negative = val_str[0] == '-';
274 const char *decimal_pos = strchr(val_str, '.');
275 long value;
276 char *endptr;
277
278 /* Parse int portion */
279 value = strtol(val_str, &endptr, 0);
280
281 if (*endptr != '\0' && *endptr != '.') {
282 return -EINVAL;
283 }
284 if (value > INT32_MAX || value < INT32_MIN) {
285 return -EINVAL;
286 }
287 out->val1 = (int32_t)value;
288
289 if (decimal_pos == NULL) {
290 return 0;
291 }
292
293 /* Parse the decimal portion */
294 value = strtoul(decimal_pos + 1, &endptr, 0);
295 if (*endptr != '\0') {
296 return -EINVAL;
297 }
298 while (value < 100000) {
299 value *= 10;
300 }
301 if (value > INT32_C(999999)) {
302 return -EINVAL;
303 }
304 out->val2 = (int32_t)value;
305 if (is_negative) {
306 out->val2 *= -1;
307 }
308 return 0;
309 }
310
sensor_shell_processing_callback(int result,uint8_t * buf,uint32_t buf_len,void * userdata)311 void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len, void *userdata)
312 {
313 struct sensor_shell_processing_context *ctx = userdata;
314 const struct sensor_decoder_api *decoder;
315 uint8_t decoded_buffer[128];
316 struct {
317 uint64_t base_timestamp_ns;
318 int count;
319 uint64_t timestamp_delta;
320 int64_t values[3];
321 int8_t shift;
322 } accumulator_buffer;
323 int rc;
324
325 ARG_UNUSED(buf_len);
326
327 if (result < 0) {
328 shell_error(ctx->sh, "Read failed");
329 return;
330 }
331
332 rc = sensor_get_decoder(ctx->dev, &decoder);
333 if (rc != 0) {
334 shell_error(ctx->sh, "Failed to get decoder for '%s'", ctx->dev->name);
335 return;
336 }
337
338 for (int trigger = 0; decoder->has_trigger != NULL && trigger < SENSOR_TRIG_COMMON_COUNT;
339 ++trigger) {
340 if (!decoder->has_trigger(buf, trigger)) {
341 continue;
342 }
343 shell_info(ctx->sh, "Trigger (%d / %s) detected", trigger,
344 (sensor_trigger_table[trigger].name == NULL
345 ? "UNKNOWN"
346 : sensor_trigger_table[trigger].name));
347 }
348
349
350
351 for (struct sensor_chan_spec ch = {0, 0}; ch.chan_type < SENSOR_CHAN_ALL; ch.chan_type++) {
352 uint32_t fit = 0;
353 size_t base_size;
354 size_t frame_size;
355 uint16_t frame_count;
356
357 /* Channels with multi-axis equivalents are skipped */
358 switch (ch.chan_type) {
359 case SENSOR_CHAN_ACCEL_X:
360 case SENSOR_CHAN_ACCEL_Y:
361 case SENSOR_CHAN_ACCEL_Z:
362 case SENSOR_CHAN_GYRO_X:
363 case SENSOR_CHAN_GYRO_Y:
364 case SENSOR_CHAN_GYRO_Z:
365 case SENSOR_CHAN_MAGN_X:
366 case SENSOR_CHAN_MAGN_Y:
367 case SENSOR_CHAN_MAGN_Z:
368 case SENSOR_CHAN_POS_DX:
369 case SENSOR_CHAN_POS_DY:
370 case SENSOR_CHAN_POS_DZ:
371 continue;
372 }
373
374 rc = decoder->get_size_info(ch, &base_size, &frame_size);
375 if (rc != 0) {
376 LOG_DBG("skipping unsupported channel %s:%d",
377 sensor_channel_name[ch.chan_type], ch.chan_idx);
378 /* Channel not supported, skipping */
379 continue;
380 }
381
382 if (base_size > ARRAY_SIZE(decoded_buffer)) {
383 shell_error(ctx->sh,
384 "Channel (type %d, idx %d) requires %zu bytes to decode, but "
385 "only %zu are available",
386 ch.chan_type, ch.chan_idx, base_size,
387 ARRAY_SIZE(decoded_buffer));
388 continue;
389 }
390
391 while (decoder->get_frame_count(buf, ch, &frame_count) == 0) {
392 LOG_DBG("decoding %d frames from channel %s:%d",
393 frame_count, sensor_channel_name[ch.chan_type], ch.chan_idx);
394 fit = 0;
395 memset(&accumulator_buffer, 0, sizeof(accumulator_buffer));
396 while (decoder->decode(buf, ch, &fit, 1, decoded_buffer) > 0) {
397 switch (ch.chan_type) {
398 case SENSOR_CHAN_ACCEL_XYZ:
399 case SENSOR_CHAN_GYRO_XYZ:
400 case SENSOR_CHAN_MAGN_XYZ:
401 case SENSOR_CHAN_POS_DXYZ: {
402 struct sensor_three_axis_data *data =
403 (struct sensor_three_axis_data *)decoded_buffer;
404
405 if (accumulator_buffer.count == 0) {
406 accumulator_buffer.base_timestamp_ns =
407 data->header.base_timestamp_ns;
408 }
409 accumulator_buffer.count++;
410 accumulator_buffer.shift = data->shift;
411 accumulator_buffer.timestamp_delta +=
412 data->readings[0].timestamp_delta;
413 accumulator_buffer.values[0] += data->readings[0].values[0];
414 accumulator_buffer.values[1] += data->readings[0].values[1];
415 accumulator_buffer.values[2] += data->readings[0].values[2];
416 break;
417 }
418 case SENSOR_CHAN_PROX: {
419 struct sensor_byte_data *data =
420 (struct sensor_byte_data *)decoded_buffer;
421
422 if (accumulator_buffer.count == 0) {
423 accumulator_buffer.base_timestamp_ns =
424 data->header.base_timestamp_ns;
425 }
426 accumulator_buffer.count++;
427 accumulator_buffer.timestamp_delta +=
428 data->readings[0].timestamp_delta;
429 accumulator_buffer.values[0] += data->readings[0].is_near;
430 break;
431 }
432 default: {
433 struct sensor_q31_data *data =
434 (struct sensor_q31_data *)decoded_buffer;
435
436 if (accumulator_buffer.count == 0) {
437 accumulator_buffer.base_timestamp_ns =
438 data->header.base_timestamp_ns;
439 }
440 accumulator_buffer.count++;
441 accumulator_buffer.shift = data->shift;
442 accumulator_buffer.timestamp_delta +=
443 data->readings[0].timestamp_delta;
444 accumulator_buffer.values[0] += data->readings[0].value;
445 break;
446 }
447 }
448 }
449
450 /* Print the accumulated value average */
451 switch (ch.chan_type) {
452 case SENSOR_CHAN_ACCEL_XYZ:
453 case SENSOR_CHAN_GYRO_XYZ:
454 case SENSOR_CHAN_MAGN_XYZ:
455 case SENSOR_CHAN_POS_DXYZ: {
456 struct sensor_three_axis_data *data =
457 (struct sensor_three_axis_data *)decoded_buffer;
458
459 data->header.base_timestamp_ns =
460 accumulator_buffer.base_timestamp_ns;
461 data->header.reading_count = 1;
462 data->shift = accumulator_buffer.shift;
463 data->readings[0].timestamp_delta =
464 (uint32_t)(accumulator_buffer.timestamp_delta /
465 accumulator_buffer.count);
466 data->readings[0].values[0] = (q31_t)(accumulator_buffer.values[0] /
467 accumulator_buffer.count);
468 data->readings[0].values[1] = (q31_t)(accumulator_buffer.values[1] /
469 accumulator_buffer.count);
470 data->readings[0].values[2] = (q31_t)(accumulator_buffer.values[2] /
471 accumulator_buffer.count);
472 shell_info(ctx->sh,
473 "channel type=%d(%s) index=%d shift=%d num_samples=%d "
474 "value=%" PRIsensor_three_axis_data,
475 ch.chan_type, sensor_channel_name[ch.chan_type],
476 ch.chan_idx, data->shift, accumulator_buffer.count,
477 PRIsensor_three_axis_data_arg(*data, 0));
478 break;
479 }
480 case SENSOR_CHAN_PROX: {
481 struct sensor_byte_data *data =
482 (struct sensor_byte_data *)decoded_buffer;
483
484 data->header.base_timestamp_ns =
485 accumulator_buffer.base_timestamp_ns;
486 data->header.reading_count = 1;
487 data->readings[0].timestamp_delta =
488 (uint32_t)(accumulator_buffer.timestamp_delta /
489 accumulator_buffer.count);
490 data->readings[0].is_near =
491 accumulator_buffer.values[0] / accumulator_buffer.count;
492
493 shell_info(ctx->sh,
494 "channel type=%d(%s) index=%d num_samples=%d "
495 "value=%" PRIsensor_byte_data(is_near),
496 ch.chan_type, sensor_channel_name[ch.chan_type],
497 ch.chan_idx, accumulator_buffer.count,
498 PRIsensor_byte_data_arg(*data, 0, is_near));
499 break;
500 }
501 default: {
502 struct sensor_q31_data *data =
503 (struct sensor_q31_data *)decoded_buffer;
504
505 data->header.base_timestamp_ns =
506 accumulator_buffer.base_timestamp_ns;
507 data->header.reading_count = 1;
508 data->shift = accumulator_buffer.shift;
509 data->readings[0].timestamp_delta =
510 (uint32_t)(accumulator_buffer.timestamp_delta /
511 accumulator_buffer.count);
512 data->readings[0].value = (q31_t)(accumulator_buffer.values[0] /
513 accumulator_buffer.count);
514
515 shell_info(ctx->sh,
516 "channel type=%d(%s) index=%d shift=%d num_samples=%d "
517 "value=%" PRIsensor_q31_data,
518 ch.chan_type,
519 (ch.chan_type >= ARRAY_SIZE(sensor_channel_name))
520 ? ""
521 : sensor_channel_name[ch.chan_type],
522 ch.chan_idx,
523 data->shift, accumulator_buffer.count,
524 PRIsensor_q31_data_arg(*data, 0));
525 }
526 }
527 ++ch.chan_idx;
528 }
529 ch.chan_idx = 0;
530 }
531 }
532
cmd_get_sensor(const struct shell * sh,size_t argc,char * argv[])533 static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[])
534 {
535 static struct sensor_shell_processing_context ctx;
536 const struct device *dev;
537 int count = 0;
538 int err;
539
540 err = k_mutex_lock(&cmd_get_mutex, K_NO_WAIT);
541 if (err < 0) {
542 shell_error(sh, "Another sensor reading in progress");
543 return err;
544 }
545
546 dev = device_get_binding(argv[1]);
547 if (dev == NULL) {
548 shell_error(sh, "Device unknown (%s)", argv[1]);
549 k_mutex_unlock(&cmd_get_mutex);
550 return -ENODEV;
551 }
552
553 if (!device_is_sensor(dev)) {
554 shell_error(sh, "Device is not a sensor (%s)", argv[1]);
555 k_mutex_unlock(&cmd_get_mutex);
556 return -ENODEV;
557 }
558
559 if (argc == 2) {
560 /* read all channel types */
561 for (int i = 0; i < ARRAY_SIZE(iodev_sensor_shell_channels); ++i) {
562 if (SENSOR_CHANNEL_3_AXIS(i)) {
563 continue;
564 }
565 iodev_sensor_shell_channels[count++] = (struct sensor_chan_spec){i, 0};
566 }
567 } else {
568 /* read specific channels */
569 for (int i = 2; i < argc; ++i) {
570 int chan = parse_named_int(argv[i], sensor_channel_name,
571 ARRAY_SIZE(sensor_channel_name));
572
573 if (chan < 0) {
574 shell_error(sh, "Failed to read channel (%s)", argv[i]);
575 continue;
576 }
577 iodev_sensor_shell_channels[count++] =
578 (struct sensor_chan_spec){chan, 0};
579 }
580 }
581
582 if (count == 0) {
583 shell_error(sh, "No channels to read, bailing");
584 k_mutex_unlock(&cmd_get_mutex);
585 return -EINVAL;
586 }
587 iodev_sensor_shell_read_config.sensor = dev;
588 iodev_sensor_shell_read_config.count = count;
589
590 ctx.dev = dev;
591 ctx.sh = sh;
592 err = sensor_read_async_mempool(&iodev_sensor_shell_read, &sensor_read_rtio, &ctx);
593 if (err < 0) {
594 shell_error(sh, "Failed to read sensor: %d", err);
595 }
596 if (!IS_ENABLED(CONFIG_SENSOR_SHELL_STREAM)) {
597 /*
598 * Streaming enables a thread that polls the RTIO context, so if it's enabled, we
599 * don't need a blocking read here.
600 */
601 sensor_processing_with_callback(&sensor_read_rtio,
602 sensor_shell_processing_callback);
603 }
604
605 k_mutex_unlock(&cmd_get_mutex);
606
607 return 0;
608 }
609
cmd_sensor_attr_set(const struct shell * shell_ptr,size_t argc,char * argv[])610 static int cmd_sensor_attr_set(const struct shell *shell_ptr, size_t argc, char *argv[])
611 {
612 const struct device *dev;
613 int rc;
614
615 dev = device_get_binding(argv[1]);
616 if (dev == NULL) {
617 shell_error(shell_ptr, "Device unknown (%s)", argv[1]);
618 return -ENODEV;
619 }
620
621 if (!device_is_sensor(dev)) {
622 shell_error(shell_ptr, "Device is not a sensor (%s)", argv[1]);
623 k_mutex_unlock(&cmd_get_mutex);
624 return -ENODEV;
625 }
626
627 for (size_t i = 2; i < argc; i += 3) {
628 int channel = parse_named_int(argv[i], sensor_channel_name,
629 ARRAY_SIZE(sensor_channel_name));
630 int attr = parse_named_int(argv[i + 1], sensor_attribute_name,
631 ARRAY_SIZE(sensor_attribute_name));
632 struct sensor_value value = {0};
633
634 if (channel < 0) {
635 shell_error(shell_ptr, "Channel '%s' unknown", argv[i]);
636 return -EINVAL;
637 }
638 if (attr < 0) {
639 shell_error(shell_ptr, "Attribute '%s' unknown", argv[i + 1]);
640 return -EINVAL;
641 }
642 if (parse_sensor_value(argv[i + 2], &value)) {
643 shell_error(shell_ptr, "Sensor value '%s' invalid", argv[i + 2]);
644 return -EINVAL;
645 }
646
647 rc = sensor_attr_set(dev, channel, attr, &value);
648 if (rc) {
649 shell_error(shell_ptr, "Failed to set channel(%s) attribute(%s): %d",
650 sensor_channel_name[channel], sensor_attribute_name[attr], rc);
651 continue;
652 }
653 shell_info(shell_ptr, "%s channel=%s, attr=%s set to value=%s", dev->name,
654 sensor_channel_name[channel], sensor_attribute_name[attr], argv[i + 2]);
655 }
656 return 0;
657 }
658
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)659 static void cmd_sensor_attr_get_handler(const struct shell *shell_ptr, const struct device *dev,
660 const char *channel_name, const char *attr_name,
661 bool print_missing_attribute)
662 {
663 int channel =
664 parse_named_int(channel_name, sensor_channel_name, ARRAY_SIZE(sensor_channel_name));
665 int attr = parse_named_int(attr_name, sensor_attribute_name,
666 ARRAY_SIZE(sensor_attribute_name));
667 struct sensor_value value = {0};
668 int rc;
669
670 if (channel < 0) {
671 shell_error(shell_ptr, "Channel '%s' unknown", channel_name);
672 return;
673 }
674 if (attr < 0) {
675 shell_error(shell_ptr, "Attribute '%s' unknown", attr_name);
676 return;
677 }
678
679 rc = sensor_attr_get(dev, channel, attr, &value);
680
681 if (rc != 0) {
682 if (rc == -EINVAL && !print_missing_attribute) {
683 return;
684 }
685 shell_error(shell_ptr, "Failed to get channel(%s) attribute(%s): %d",
686 sensor_channel_name[channel], sensor_attribute_name[attr], rc);
687 return;
688 }
689
690 shell_info(shell_ptr, "%s(channel=%s, attr=%s) value=%.6f", dev->name,
691 sensor_channel_name[channel], sensor_attribute_name[attr],
692 sensor_value_to_double(&value));
693 }
694
cmd_sensor_attr_get(const struct shell * shell_ptr,size_t argc,char * argv[])695 static int cmd_sensor_attr_get(const struct shell *shell_ptr, size_t argc, char *argv[])
696 {
697 const struct device *dev;
698
699 dev = device_get_binding(argv[1]);
700 if (dev == NULL) {
701 shell_error(shell_ptr, "Device unknown (%s)", argv[1]);
702 return -ENODEV;
703 }
704
705 if (!device_is_sensor(dev)) {
706 shell_error(shell_ptr, "Device is not a sensor (%s)", argv[1]);
707 k_mutex_unlock(&cmd_get_mutex);
708 return -ENODEV;
709 }
710
711 if (argc > 2) {
712 for (size_t i = 2; i < argc; i += 2) {
713 cmd_sensor_attr_get_handler(shell_ptr, dev, argv[i], argv[i + 1],
714 /*print_missing_attribute=*/true);
715 }
716 } else {
717 for (size_t channel_idx = 0; channel_idx < ARRAY_SIZE(sensor_channel_name);
718 ++channel_idx) {
719 for (size_t attr_idx = 0; attr_idx < ARRAY_SIZE(sensor_attribute_name);
720 ++attr_idx) {
721 cmd_sensor_attr_get_handler(shell_ptr, dev,
722 sensor_channel_name[channel_idx],
723 sensor_attribute_name[attr_idx],
724 /*print_missing_attribute=*/false);
725 }
726 }
727 }
728 return 0;
729 }
730
731 static void channel_name_get(size_t idx, struct shell_static_entry *entry);
732 SHELL_DYNAMIC_CMD_CREATE(dsub_channel_name, channel_name_get);
733
734 static void attribute_name_get(size_t idx, struct shell_static_entry *entry);
735 SHELL_DYNAMIC_CMD_CREATE(dsub_attribute_name, attribute_name_get);
736
channel_name_get(size_t idx,struct shell_static_entry * entry)737 static void channel_name_get(size_t idx, struct shell_static_entry *entry)
738 {
739 int cnt = 0;
740
741 entry->syntax = NULL;
742 entry->handler = NULL;
743 entry->help = NULL;
744 if (current_cmd_ctx == CTX_GET) {
745 entry->subcmd = &dsub_channel_name;
746 } else if (current_cmd_ctx == CTX_ATTR_GET_SET) {
747 entry->subcmd = &dsub_attribute_name;
748 } else {
749 entry->subcmd = NULL;
750 }
751
752 for (int i = 0; i < ARRAY_SIZE(sensor_channel_name); i++) {
753 if (sensor_channel_name[i] != NULL) {
754 if (cnt == idx) {
755 entry->syntax = sensor_channel_name[i];
756 break;
757 }
758 cnt++;
759 }
760 }
761 }
762
attribute_name_get(size_t idx,struct shell_static_entry * entry)763 static void attribute_name_get(size_t idx, struct shell_static_entry *entry)
764 {
765 int cnt = 0;
766
767 entry->syntax = NULL;
768 entry->handler = NULL;
769 entry->help = NULL;
770 entry->subcmd = &dsub_channel_name;
771
772 for (int i = 0; i < ARRAY_SIZE(sensor_attribute_name); i++) {
773 if (sensor_attribute_name[i] != NULL) {
774 if (cnt == idx) {
775 entry->syntax = sensor_attribute_name[i];
776 break;
777 }
778 cnt++;
779 }
780 }
781 }
782
783 static void trigger_opt_get_for_stream(size_t idx, struct shell_static_entry *entry);
784 SHELL_DYNAMIC_CMD_CREATE(dsub_trigger_opt_get_for_stream, trigger_opt_get_for_stream);
785
trigger_opt_get_for_stream(size_t idx,struct shell_static_entry * entry)786 static void trigger_opt_get_for_stream(size_t idx, struct shell_static_entry *entry)
787 {
788 entry->syntax = NULL;
789 entry->handler = NULL;
790 entry->help = NULL;
791 entry->subcmd = NULL;
792
793 switch (idx) {
794 case SENSOR_STREAM_DATA_INCLUDE:
795 entry->syntax = "incl";
796 break;
797 case SENSOR_STREAM_DATA_DROP:
798 entry->syntax = "drop";
799 break;
800 case SENSOR_STREAM_DATA_NOP:
801 entry->syntax = "nop";
802 break;
803 }
804 }
805
806 static void trigger_name_get_for_stream(size_t idx, struct shell_static_entry *entry);
807 SHELL_DYNAMIC_CMD_CREATE(dsub_trigger_name_for_stream, trigger_name_get_for_stream);
808
trigger_name_get_for_stream(size_t idx,struct shell_static_entry * entry)809 static void trigger_name_get_for_stream(size_t idx, struct shell_static_entry *entry)
810 {
811 int cnt = 0;
812
813 entry->syntax = NULL;
814 entry->handler = NULL;
815 entry->help = NULL;
816 entry->subcmd = &dsub_trigger_opt_get_for_stream;
817
818 for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); i++) {
819 if (sensor_trigger_table[i].name != NULL) {
820 if (cnt == idx) {
821 entry->syntax = sensor_trigger_table[i].name;
822 break;
823 }
824 cnt++;
825 }
826 }
827 }
828
stream_on_off(size_t idx,struct shell_static_entry * entry)829 static void stream_on_off(size_t idx, struct shell_static_entry *entry)
830 {
831 entry->syntax = NULL;
832 entry->handler = NULL;
833 entry->help = NULL;
834
835 if (idx == 0) {
836 entry->syntax = "on";
837 entry->subcmd = &dsub_trigger_name_for_stream;
838 } else if (idx == 1) {
839 entry->syntax = "off";
840 entry->subcmd = NULL;
841 }
842 }
843 SHELL_DYNAMIC_CMD_CREATE(dsub_stream_on_off, stream_on_off);
844
845 static void device_name_get(size_t idx, struct shell_static_entry *entry);
846
847 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
848
device_name_get(size_t idx,struct shell_static_entry * entry)849 static void device_name_get(size_t idx, struct shell_static_entry *entry)
850 {
851 const struct device *dev = shell_device_lookup(idx, NULL);
852
853 current_cmd_ctx = CTX_GET;
854 entry->syntax = (dev != NULL) ? dev->name : NULL;
855 entry->handler = NULL;
856 entry->help = NULL;
857 entry->subcmd = &dsub_channel_name;
858 }
859
device_name_get_for_attr(size_t idx,struct shell_static_entry * entry)860 static void device_name_get_for_attr(size_t idx, struct shell_static_entry *entry)
861 {
862 const struct device *dev = shell_device_lookup(idx, NULL);
863
864 current_cmd_ctx = CTX_ATTR_GET_SET;
865 entry->syntax = (dev != NULL) ? dev->name : NULL;
866 entry->handler = NULL;
867 entry->help = NULL;
868 entry->subcmd = &dsub_channel_name;
869 }
870 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name_for_attr, device_name_get_for_attr);
871
trigger_name_get(size_t idx,struct shell_static_entry * entry)872 static void trigger_name_get(size_t idx, struct shell_static_entry *entry)
873 {
874 int cnt = 0;
875
876 entry->syntax = NULL;
877 entry->handler = NULL;
878 entry->help = NULL;
879 entry->subcmd = NULL;
880
881 for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); i++) {
882 if (sensor_trigger_table[i].name != NULL) {
883 if (cnt == idx) {
884 entry->syntax = sensor_trigger_table[i].name;
885 break;
886 }
887 cnt++;
888 }
889 }
890 }
891
892 SHELL_DYNAMIC_CMD_CREATE(dsub_trigger_name, trigger_name_get);
893
trigger_on_off_get(size_t idx,struct shell_static_entry * entry)894 static void trigger_on_off_get(size_t idx, struct shell_static_entry *entry)
895 {
896 entry->handler = NULL;
897 entry->help = NULL;
898 entry->subcmd = &dsub_trigger_name;
899
900 switch (idx) {
901 case 0:
902 entry->syntax = "on";
903 break;
904 case 1:
905 entry->syntax = "off";
906 break;
907 default:
908 entry->syntax = NULL;
909 break;
910 }
911 }
912
913 SHELL_DYNAMIC_CMD_CREATE(dsub_trigger_onoff, trigger_on_off_get);
914
device_name_get_for_trigger(size_t idx,struct shell_static_entry * entry)915 static void device_name_get_for_trigger(size_t idx, struct shell_static_entry *entry)
916 {
917 const struct device *dev = shell_device_lookup(idx, NULL);
918
919 entry->syntax = (dev != NULL) ? dev->name : NULL;
920 entry->handler = NULL;
921 entry->help = NULL;
922 entry->subcmd = &dsub_trigger_onoff;
923 }
924
925 SHELL_DYNAMIC_CMD_CREATE(dsub_trigger, device_name_get_for_trigger);
926
device_name_get_for_stream(size_t idx,struct shell_static_entry * entry)927 static void device_name_get_for_stream(size_t idx, struct shell_static_entry *entry)
928 {
929 const struct device *dev = shell_device_lookup(idx, NULL);
930
931 current_cmd_ctx = CTX_STREAM_ON_OFF;
932 entry->syntax = (dev != NULL) ? dev->name : NULL;
933 entry->handler = NULL;
934 entry->help = NULL;
935 entry->subcmd = &dsub_stream_on_off;
936 }
937 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name_for_stream, device_name_get_for_stream);
938
cmd_get_sensor_info(const struct shell * sh,size_t argc,char ** argv)939 static int cmd_get_sensor_info(const struct shell *sh, size_t argc, char **argv)
940 {
941 ARG_UNUSED(argc);
942 ARG_UNUSED(argv);
943
944 #ifdef CONFIG_SENSOR_INFO
945 const char *null_str = "(null)";
946
947 STRUCT_SECTION_FOREACH(sensor_info, sensor) {
948 shell_print(sh,
949 "device name: %s, vendor: %s, model: %s, "
950 "friendly name: %s",
951 sensor->dev->name, sensor->vendor ? sensor->vendor : null_str,
952 sensor->model ? sensor->model : null_str,
953 sensor->friendly_name ? sensor->friendly_name : null_str);
954 }
955 return 0;
956 #else
957 return -EINVAL;
958 #endif
959 }
960
data_ready_trigger_handler(const struct device * sensor,const struct sensor_trigger * trigger)961 static void data_ready_trigger_handler(const struct device *sensor,
962 const struct sensor_trigger *trigger)
963 {
964 const int64_t now = k_uptime_get();
965 struct sensor_value value;
966 int sensor_idx = find_sensor_trigger_device(sensor);
967 struct sample_stats *stats;
968 int sensor_name_len_before_at;
969 const char *sensor_name;
970
971 if (sensor_idx < 0) {
972 LOG_ERR("Unable to find sensor trigger device");
973 return;
974 }
975 stats = sensor_stats[sensor_idx];
976 sensor_name = sensor_trigger_devices[sensor_idx]->name;
977 if (sensor_name) {
978 sensor_name_len_before_at = strchr(sensor_name, '@') - sensor_name;
979 } else {
980 sensor_name_len_before_at = 0;
981 }
982
983 if (sensor_sample_fetch(sensor)) {
984 LOG_ERR("Failed to fetch samples on data ready handler");
985 }
986 for (int i = 0; i < SENSOR_CHAN_ALL; ++i) {
987 int rc;
988
989 /* Skip disabled channels */
990 if (stats[i].state == SAMPLE_STATS_STATE_DISABLED) {
991 continue;
992 }
993 /* Skip 3 axis channels */
994 if (SENSOR_CHANNEL_3_AXIS(i)) {
995 continue;
996 }
997
998 rc = sensor_channel_get(sensor, i, &value);
999 if (stats[i].state == SAMPLE_STATS_STATE_UNINITIALIZED) {
1000 if (rc == -ENOTSUP) {
1001 /*
1002 * Stop reading this channel if the driver told us
1003 * it's not supported.
1004 */
1005 stats[i].state = SAMPLE_STATS_STATE_DISABLED;
1006 } else if (rc == 0) {
1007 stats[i].state = SAMPLE_STATS_STATE_ENABLED;
1008 }
1009 }
1010 if (rc != 0) {
1011 /* Skip on any error. */
1012 continue;
1013 }
1014 /* Do something with the data */
1015 stats[i].accumulator += value.val1 * INT64_C(1000000) + value.val2;
1016 if (stats[i].count++ == 0) {
1017 stats[i].sample_window_start = now;
1018 } else if (now > stats[i].sample_window_start +
1019 CONFIG_SENSOR_SHELL_TRIG_PRINT_TIMEOUT_MS) {
1020 int64_t micro_value = stats[i].accumulator / stats[i].count;
1021
1022 value.val1 = micro_value / 1000000;
1023 value.val2 = (int32_t)llabs(micro_value - (value.val1 * 1000000));
1024 LOG_INF("sensor=%.*s, chan=%s, num_samples=%u, data=%d.%06d",
1025 sensor_name_len_before_at, sensor_name,
1026 sensor_channel_name[i],
1027 stats[i].count,
1028 value.val1, value.val2);
1029
1030 stats[i].accumulator = 0;
1031 stats[i].count = 0;
1032 }
1033 }
1034 }
1035
cmd_trig_sensor(const struct shell * sh,size_t argc,char ** argv)1036 static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv)
1037 {
1038 const struct device *dev;
1039 int trigger;
1040 bool trigger_enabled = false;
1041 int err;
1042
1043 if (argc < 4) {
1044 shell_error(sh, "Wrong number of args");
1045 return -EINVAL;
1046 }
1047
1048 /* Parse device name */
1049 dev = device_get_binding(argv[1]);
1050 if (dev == NULL) {
1051 shell_error(sh, "Device unknown (%s)", argv[1]);
1052 return -ENODEV;
1053 }
1054
1055 /* Map the trigger string to an enum value */
1056 trigger = sensor_trigger_name_lookup(argv[3]);
1057 if (trigger < 0 || sensor_trigger_table[trigger].handler == NULL) {
1058 shell_error(sh, "Unsupported trigger type (%s)", argv[3]);
1059 return -ENOTSUP;
1060 }
1061
1062 /* Parse on/off */
1063 if (strcmp(argv[2], "on") == 0) {
1064 /* find a free entry in sensor_trigger_devices[] */
1065 int sensor_idx = find_sensor_trigger_device(NULL);
1066
1067 if (sensor_idx < 0) {
1068 shell_error(sh, "Unable to support more simultaneous sensor trigger"
1069 " devices");
1070 err = -ENOTSUP;
1071 } else {
1072 struct sample_stats *stats = sensor_stats[sensor_idx];
1073
1074 sensor_trigger_devices[sensor_idx] = dev;
1075 /* reset stats state to UNINITIALIZED */
1076 for (unsigned int ch = 0; ch < SENSOR_CHAN_ALL; ch++) {
1077 stats[ch].state = SAMPLE_STATS_STATE_UNINITIALIZED;
1078 }
1079 err = sensor_trigger_set(dev, &sensor_trigger_table[trigger].trigger,
1080 sensor_trigger_table[trigger].handler);
1081 trigger_enabled = true;
1082 }
1083 } else if (strcmp(argv[2], "off") == 0) {
1084 /* Clear the handler for the given trigger on this device */
1085 err = sensor_trigger_set(dev, &sensor_trigger_table[trigger].trigger, NULL);
1086 if (!err) {
1087 /* find entry in sensor_trigger_devices[] and free it */
1088 int sensor_idx = find_sensor_trigger_device(dev);
1089
1090 if (sensor_idx < 0) {
1091 shell_error(sh, "Unable to find sensor device in trigger array");
1092 } else {
1093 sensor_trigger_devices[sensor_idx] = NULL;
1094 }
1095 }
1096 } else {
1097 shell_error(sh, "Pass 'on' or 'off' to enable/disable trigger");
1098 return -EINVAL;
1099 }
1100
1101 if (err) {
1102 shell_error(sh, "Error while setting trigger %d on device %s (%d)", trigger,
1103 argv[1], err);
1104 } else {
1105 shell_info(sh, "%s trigger idx=%d %s on device %s",
1106 trigger_enabled ? "Enabled" : "Disabled", trigger,
1107 sensor_trigger_table[trigger].name, argv[1]);
1108 }
1109
1110 return err;
1111 }
1112
1113 /* clang-format off */
1114 SHELL_STATIC_SUBCMD_SET_CREATE(sub_sensor,
1115 SHELL_CMD_ARG(get, &dsub_device_name, SENSOR_GET_HELP, cmd_get_sensor,
1116 2, 255),
1117 SHELL_CMD_ARG(attr_set, &dsub_device_name_for_attr, SENSOR_ATTR_SET_HELP,
1118 cmd_sensor_attr_set, 2, 255),
1119 SHELL_CMD_ARG(attr_get, &dsub_device_name_for_attr, SENSOR_ATTR_GET_HELP,
1120 cmd_sensor_attr_get, 2, 255),
1121 SHELL_COND_CMD(CONFIG_SENSOR_SHELL_STREAM, stream, &dsub_device_name_for_stream,
1122 SENSOR_STREAM_HELP, cmd_sensor_stream),
1123 SHELL_COND_CMD(CONFIG_SENSOR_INFO, info, NULL, SENSOR_INFO_HELP,
1124 cmd_get_sensor_info),
1125 SHELL_CMD_ARG(trig, &dsub_trigger, SENSOR_TRIG_HELP, cmd_trig_sensor,
1126 2, 255),
1127 SHELL_SUBCMD_SET_END
1128 );
1129 /* clang-format on */
1130
1131 SHELL_CMD_REGISTER(sensor, &sub_sensor, "Sensor commands", NULL);
1132