From 11d1a3389abb822bc1515fbc2082e261223dfadc Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Mon, 5 Jun 2023 20:26:19 -0600 Subject: [PATCH 01/10] sensors: Add streaming APIs Introduce a streaming API that uses the same data path as the async API. This includes features to the decoder: * Checking if triggers are present Adding streaming features built ontop of existing triggers: * Adding 3 operations to be done on a trigger * include - include the data with the trigger information * nop - do nothing * drop - drop the data (flush) * Add a new sensor_stream() API to mirror sensor_read() but add an optional handler to be able to cancel the stream. Signed-off-by: Yuval Peress topic#sensor_stream --- drivers/sensor/Kconfig | 9 + drivers/sensor/default_rtio_sensor.c | 4 +- drivers/sensor/sensor_shell.c | 331 +++++++++++++++--- include/zephyr/drivers/sensor.h | 77 +++- .../sensor_shell/boards/tdk_robokit1.conf | 3 + 5 files changed, 371 insertions(+), 53 deletions(-) create mode 100644 samples/sensor/sensor_shell/boards/tdk_robokit1.conf diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index a91ea8824bd0c8..92851845e376b1 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -36,6 +36,15 @@ config SENSOR_SHELL help This shell provides access to basic sensor data. +config SENSOR_SHELL_THREAD_STACK_SIZE + int "Stack size for the sensor shell data processing thread" + depends on SENSOR_SHELL + default 1024 + help + The sensor shell uses a dedicated thread to process data coming from the + sensors in either one-shot or streaming mode. Use this config to control + the size of that thread's stack. + config SENSOR_SHELL_BATTERY bool "Sensor shell 'battery' command" depends on SHELL diff --git a/drivers/sensor/default_rtio_sensor.c b/drivers/sensor/default_rtio_sensor.c index 55db893f4d89c0..a86bd81ec1d48f 100644 --- a/drivers/sensor/default_rtio_sensor.c +++ b/drivers/sensor/default_rtio_sensor.c @@ -22,8 +22,10 @@ static void sensor_iodev_submit(struct rtio_iodev_sqe *iodev_sqe) if (api->submit != NULL) { api->submit(dev, iodev_sqe); - } else { + } else if (!cfg->is_streaming) { sensor_submit_fallback(dev, iodev_sqe); + } else { + rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP); } } diff --git a/drivers/sensor/sensor_shell.c b/drivers/sensor/sensor_shell.c index b8c828297318fd..b33098d31dc896 100644 --- a/drivers/sensor/sensor_shell.c +++ b/drivers/sensor/sensor_shell.c @@ -21,6 +21,11 @@ LOG_MODULE_REGISTER(sensor_shell); "when no channels are provided. Syntax:\n" \ " .. " +#define SENSOR_STREAM_HELP \ + "Start/stop streaming sensor data. Data ready trigger will be used if no triggers " \ + "are provided. Syntax:\n" \ + " on|off incl|drop|nop" + #define SENSOR_ATTR_GET_HELP \ "Get the sensor's channel attribute. Syntax:\n" \ " [ .. " \ @@ -36,7 +41,7 @@ LOG_MODULE_REGISTER(sensor_shell); "Get or set the trigger type on a sensor. Currently only supports `data_ready`.\n" \ " " -const char *sensor_channel_name[SENSOR_CHAN_ALL] = { +const char *sensor_channel_name[SENSOR_CHAN_COMMON_COUNT] = { [SENSOR_CHAN_ACCEL_X] = "accel_x", [SENSOR_CHAN_ACCEL_Y] = "accel_y", [SENSOR_CHAN_ACCEL_Z] = "accel_z", @@ -94,6 +99,7 @@ const char *sensor_channel_name[SENSOR_CHAN_ALL] = { [SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE] = "gauge_design_voltage", [SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE] = "gauge_desired_voltage", [SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT] = "gauge_desired_charging_current", + [SENSOR_CHAN_ALL] = "all", }; static const char *sensor_attribute_name[SENSOR_ATTR_COMMON_COUNT] = { @@ -112,6 +118,7 @@ static const char *sensor_attribute_name[SENSOR_ATTR_COMMON_COUNT] = { [SENSOR_ATTR_FEATURE_MASK] = "feature_mask", [SENSOR_ATTR_ALERT] = "alert", [SENSOR_ATTR_FF_DUR] = "ff_dur", + [SENSOR_ATTR_FIFO_WATERMARK] = "fifo_wm", }; /* Forward declaration */ @@ -144,12 +151,32 @@ static const struct { TRIGGER_DATA_ENTRY(SENSOR_TRIG_FREEFALL, freefall, NULL), TRIGGER_DATA_ENTRY(SENSOR_TRIG_MOTION, motion, NULL), TRIGGER_DATA_ENTRY(SENSOR_TRIG_STATIONARY, stationary, NULL), + TRIGGER_DATA_ENTRY(SENSOR_TRIG_FIFO_THRESHOLD, fifo_wm, NULL), + TRIGGER_DATA_ENTRY(SENSOR_TRIG_FIFO_FULL, fifo_full, NULL), }; +/** + * Lookup the sensor trigger data by name + * + * @param name The name of the trigger + * @return < 0 on error + * @return >= 0 if found + */ +static int sensor_trigger_name_lookup(const char *name) +{ + for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); ++i) { + if (strcmp(name, sensor_trigger_table[i].name) == 0) { + return i; + } + } + return -1; +} + enum dynamic_command_context { NONE, CTX_GET, CTX_ATTR_GET_SET, + CTX_STREAM_ON_OFF, }; static enum dynamic_command_context current_cmd_ctx = NONE; @@ -158,12 +185,25 @@ static enum dynamic_command_context current_cmd_ctx = NONE; static enum sensor_channel iodev_sensor_shell_channels[SENSOR_CHAN_ALL]; static struct sensor_read_config iodev_sensor_shell_read_config = { .sensor = NULL, + .is_streaming = false, .channels = iodev_sensor_shell_channels, .count = 0, .max = ARRAY_SIZE(iodev_sensor_shell_channels), }; RTIO_IODEV_DEFINE(iodev_sensor_shell_read, &__sensor_iodev_api, &iodev_sensor_shell_read_config); +/* Create a single common config for streaming */ +static struct sensor_stream_trigger iodev_sensor_shell_trigger; +static struct sensor_read_config iodev_sensor_shell_stream_config = { + .sensor = NULL, + .is_streaming = true, + .triggers = &iodev_sensor_shell_trigger, + .count = 0, + .max = 1, +}; +RTIO_IODEV_DEFINE(iodev_sensor_shell_stream, &__sensor_iodev_api, + &iodev_sensor_shell_stream_config); + /* Create the RTIO context to service the reading */ RTIO_DEFINE_WITH_MEMPOOL(sensor_read_rtio, 8, 8, 32, 64, 4); @@ -234,14 +274,44 @@ struct sensor_shell_processing_context { const struct shell *sh; }; +static void sensor_shell_print_q_value(const struct shell *sh, int channel, int64_t value, + int8_t shift) +{ + int64_t scaled_value = (shift < 0) ? (value >> -shift) : (value << shift); + bool is_negative = scaled_value < 0; + int numerator; + int denominator; + + scaled_value = llabs(scaled_value); + numerator = (int)FIELD_GET(GENMASK64(31 + shift, 31), scaled_value); + denominator = (int)((FIELD_GET(GENMASK64(30, 0), scaled_value) * 1000000) / INT32_MAX); + + if (channel >= ARRAY_SIZE(sensor_channel_name)) { + shell_print(sh, "channel idx=%d shift=%d value=%s%d.%06d", channel, shift, + is_negative ? "-" : "", numerator, denominator); + } else { + shell_print(sh, "channel idx=%d %s shift=%d value=%s%d.%06d", channel, + sensor_channel_name[channel], shift, is_negative ? "-" : "", numerator, + denominator); + } +} + static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len, void *userdata) { + static struct { + int64_t accumulator; + int8_t shift; + int count; + bool is_active; + } sample_stats[SENSOR_CHAN_COMMON_COUNT]; + struct sensor_shell_processing_context *ctx = userdata; const struct sensor_decoder_api *decoder; sensor_frame_iterator_t fit = {0}; sensor_channel_iterator_t cit = {0}; uint64_t timestamp; + uint16_t frame_count; enum sensor_channel channel; q31_t q; int rc; @@ -264,7 +334,24 @@ static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t shell_error(ctx->sh, "Failed to get fetch timestamp for '%s'", ctx->dev->name); return; } - shell_print(ctx->sh, "Got samples at %" PRIu64 " ns", timestamp); + rc = decoder->get_frame_count(buf, &frame_count); + if (rc != 0) { + shell_error(ctx->sh, "Failed to get frame count for '%s'", ctx->dev->name); + return; + } + shell_print(ctx->sh, "Got %" PRIu16 " frame(s) at %" PRIu64 " ns", frame_count, timestamp); + + for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); ++i) { + bool has_trigger = decoder->has_trigger(buf, sensor_trigger_table[i].trigger.type); + + if (has_trigger) { + shell_print(ctx->sh, "Trigger '%s' detected", sensor_trigger_table[i].name); + } + } + + if (frame_count > 1) { + memset(sample_stats, 0, sizeof(sample_stats)); + } while (decoder->decode(buf, &fit, &cit, &channel, &q, 1) > 0) { int8_t shift; @@ -275,29 +362,36 @@ static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t continue; } - int64_t scaled_value = (int64_t)q << shift; - bool is_negative = scaled_value < 0; - int numerator; - int denominator; - - scaled_value = llabs(scaled_value); - numerator = (int)FIELD_GET(GENMASK64(31 + shift, 31), scaled_value); - denominator = - (int)((FIELD_GET(GENMASK64(30, 0), scaled_value) * 1000000) / INT32_MAX); - - if (channel >= ARRAY_SIZE(sensor_channel_name)) { - shell_print(ctx->sh, "channel idx=%d value=%s%d.%06d", channel, - is_negative ? "-" : "", numerator, denominator); - } else { - shell_print(ctx->sh, "channel idx=%d %s value=%s%d.%06d", channel, - sensor_channel_name[channel], is_negative ? "-" : "", numerator, - denominator); + if (frame_count > 1) { + sample_stats[channel].shift = shift; + sample_stats[channel].accumulator += q; + sample_stats[channel].count++; + sample_stats[channel].is_active = true; + continue; } + + sensor_shell_print_q_value(ctx->sh, channel, q, shift); + } + + if (frame_count <= 1) { + return; + } + + shell_print(ctx->sh, "Averages:"); + for (int i = 0; i < ARRAY_SIZE(sample_stats); ++i) { + if (!sample_stats[i].is_active) { + continue; + } + + int64_t scaled_value = (sample_stats[i].accumulator / sample_stats[i].count); + + sensor_shell_print_q_value(ctx->sh, i, scaled_value, sample_stats[i].shift); } } static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) { + static struct sensor_shell_processing_context ctx; const struct device *dev; int err; @@ -329,8 +423,7 @@ static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) shell_error(sh, "Failed to read channel (%s)", argv[i]); continue; } - iodev_sensor_shell_channels[iodev_sensor_shell_read_config.count++] = - chan; + iodev_sensor_shell_channels[iodev_sensor_shell_read_config.count++] = chan; } } @@ -340,19 +433,30 @@ static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) } iodev_sensor_shell_read_config.sensor = dev; - struct sensor_shell_processing_context ctx = { - .dev = dev, - .sh = sh, - }; + ctx.dev = dev; + ctx.sh = sh; err = sensor_read(&iodev_sensor_shell_read, &sensor_read_rtio, &ctx); if (err < 0) { shell_error(sh, "Failed to read sensor: %d", err); } - sensor_processing_with_callback(&sensor_read_rtio, sensor_shell_processing_callback); return 0; } +static void sensor_shell_processing_entry_point(void *a, void *b, void *c) +{ + ARG_UNUSED(a); + ARG_UNUSED(b); + ARG_UNUSED(c); + + while (true) { + sensor_processing_with_callback(&sensor_read_rtio, + sensor_shell_processing_callback); + } +} +K_THREAD_DEFINE(sensor_shell_processing_tid, CONFIG_SENSOR_SHELL_THREAD_STACK_SIZE, + sensor_shell_processing_entry_point, NULL, NULL, NULL, 0, 0, 0); + static int cmd_sensor_attr_set(const struct shell *shell_ptr, size_t argc, char *argv[]) { const struct device *dev; @@ -462,10 +566,93 @@ static int cmd_sensor_attr_get(const struct shell *shell_ptr, size_t argc, char return 0; } -static void channel_name_get(size_t idx, struct shell_static_entry *entry); +static int cmd_sensor_stream(const struct shell *shell_ptr, size_t argc, char *argv[]) +{ + static struct rtio_sqe *current_streaming_handle; + static struct sensor_shell_processing_context ctx; + const struct device *dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(shell_ptr, "Device unknown (%s)", argv[1]); + return -ENODEV; + } + + if (current_streaming_handle != NULL) { + shell_print(shell_ptr, "Disabling existing stream"); + rtio_sqe_cancel(current_streaming_handle); + } + + if (strcmp("off", argv[2]) == 0) { + return 0; + } + + if (strcmp("on", argv[2]) != 0) { + shell_error(shell_ptr, "Unknown streaming operation (%s)", argv[2]); + return -EINVAL; + } + + int op = strcmp("incl", argv[3]) == 0 + ? SENSOR_STREAM_DATA_INCLUDE + : (strcmp("drop", argv[3]) == 0 + ? SENSOR_STREAM_DATA_DROP + : (strcmp("nop", argv[3]) ? SENSOR_STREAM_DATA_NOP : -1)); + + if (op < 0) { + shell_error(shell_ptr, "Unknown trigger op (%s)", argv[3]); + return -EINVAL; + } + + shell_print(shell_ptr, "Enabling stream..."); + iodev_sensor_shell_stream_config.sensor = dev; + + iodev_sensor_shell_stream_config.count = 1; + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_DATA_READY; + iodev_sensor_shell_trigger.opt = op; + + ctx.dev = dev; + ctx.sh = shell_ptr; + + int rc = sensor_stream(&iodev_sensor_shell_stream, &sensor_read_rtio, &ctx, + ¤t_streaming_handle); + + if (rc != 0) { + shell_error(shell_ptr, "Failed to start stream"); + } + return rc; +} + +static void channel_name_get(size_t idx, struct shell_static_entry *entry); SHELL_DYNAMIC_CMD_CREATE(dsub_channel_name, channel_name_get); +static void attribute_name_get(size_t idx, struct shell_static_entry *entry); +SHELL_DYNAMIC_CMD_CREATE(dsub_attribute_name, attribute_name_get); + +static void channel_name_get(size_t idx, struct shell_static_entry *entry) +{ + int cnt = 0; + + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + if (current_cmd_ctx == CTX_GET) { + entry->subcmd = &dsub_channel_name; + } else if (current_cmd_ctx == CTX_ATTR_GET_SET) { + entry->subcmd = &dsub_attribute_name; + } else { + entry->subcmd = NULL; + } + + for (int i = 0; i < ARRAY_SIZE(sensor_channel_name); i++) { + if (sensor_channel_name[i] != NULL) { + if (cnt == idx) { + entry->syntax = sensor_channel_name[i]; + break; + } + cnt++; + } + } +} + static void attribute_name_get(size_t idx, struct shell_static_entry *entry) { int cnt = 0; @@ -475,7 +662,7 @@ static void attribute_name_get(size_t idx, struct shell_static_entry *entry) entry->help = NULL; entry->subcmd = &dsub_channel_name; - for (int i = 0; i < SENSOR_ATTR_COMMON_COUNT; i++) { + for (int i = 0; i < ARRAY_SIZE(sensor_attribute_name); i++) { if (sensor_attribute_name[i] != NULL) { if (cnt == idx) { entry->syntax = sensor_attribute_name[i]; @@ -485,27 +672,46 @@ static void attribute_name_get(size_t idx, struct shell_static_entry *entry) } } } -SHELL_DYNAMIC_CMD_CREATE(dsub_attribute_name, attribute_name_get); -static void channel_name_get(size_t idx, struct shell_static_entry *entry) +static void trigger_opt_get_for_stream(size_t idx, struct shell_static_entry *entry); +SHELL_DYNAMIC_CMD_CREATE(dsub_trigger_opt_get_for_stream, trigger_opt_get_for_stream); + +static void trigger_opt_get_for_stream(size_t idx, struct shell_static_entry *entry) +{ + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; + + switch (idx) { + case SENSOR_STREAM_DATA_INCLUDE: + entry->syntax = "incl"; + break; + case SENSOR_STREAM_DATA_DROP: + entry->syntax = "drop"; + break; + case SENSOR_STREAM_DATA_NOP: + entry->syntax = "nop"; + break; + } +} + +static void trigger_name_get_for_stream(size_t idx, struct shell_static_entry *entry); +SHELL_DYNAMIC_CMD_CREATE(dsub_trigger_name_for_stream, trigger_name_get_for_stream); + +static void trigger_name_get_for_stream(size_t idx, struct shell_static_entry *entry) { int cnt = 0; entry->syntax = NULL; entry->handler = NULL; entry->help = NULL; - if (current_cmd_ctx == CTX_GET) { - entry->subcmd = &dsub_channel_name; - } else if (current_cmd_ctx == CTX_ATTR_GET_SET) { - entry->subcmd = &dsub_attribute_name; - } else { - entry->subcmd = NULL; - } + entry->subcmd = &dsub_trigger_opt_get_for_stream; - for (int i = 0; i < SENSOR_CHAN_ALL; i++) { - if (sensor_channel_name[i] != NULL) { + for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); i++) { + if (sensor_trigger_table[i].name != NULL) { if (cnt == idx) { - entry->syntax = sensor_channel_name[i]; + entry->syntax = sensor_trigger_table[i].name; break; } cnt++; @@ -513,6 +719,22 @@ static void channel_name_get(size_t idx, struct shell_static_entry *entry) } } +static void stream_on_off(size_t idx, struct shell_static_entry *entry) +{ + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + + if (idx == 0) { + entry->syntax = "on"; + entry->subcmd = &dsub_trigger_name_for_stream; + } else if (idx == 1) { + entry->syntax = "off"; + entry->subcmd = NULL; + } +} +SHELL_DYNAMIC_CMD_CREATE(dsub_stream_on_off, stream_on_off); + static void device_name_get(size_t idx, struct shell_static_entry *entry); SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get); @@ -549,7 +771,7 @@ static void trigger_name_get(size_t idx, struct shell_static_entry *entry) entry->help = NULL; entry->subcmd = NULL; - for (int i = 0; i < SENSOR_TRIG_COMMON_COUNT; i++) { + for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); i++) { if (sensor_trigger_table[i].name != NULL) { if (cnt == idx) { entry->syntax = sensor_trigger_table[i].name; @@ -595,6 +817,18 @@ static void device_name_get_for_trigger(size_t idx, struct shell_static_entry *e SHELL_DYNAMIC_CMD_CREATE(dsub_trigger, device_name_get_for_trigger); +static void device_name_get_for_stream(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_lookup(idx, NULL); + + current_cmd_ctx = CTX_STREAM_ON_OFF; + entry->syntax = (dev != NULL) ? dev->name : NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = &dsub_stream_on_off; +} +SHELL_DYNAMIC_CMD_CREATE(dsub_device_name_for_stream, device_name_get_for_stream); + static int cmd_get_sensor_info(const struct shell *sh, size_t argc, char **argv) { ARG_UNUSED(argc); @@ -603,8 +837,7 @@ static int cmd_get_sensor_info(const struct shell *sh, size_t argc, char **argv) #ifdef CONFIG_SENSOR_INFO const char *null_str = "(null)"; - STRUCT_SECTION_FOREACH(sensor_info, sensor) - { + STRUCT_SECTION_FOREACH(sensor_info, sensor) { shell_print(sh, "device name: %s, vendor: %s, model: %s, " "friendly name: %s", @@ -685,7 +918,7 @@ static void data_ready_trigger_handler(const struct device *sensor, static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; - enum sensor_trigger_type trigger; + int trigger; int err; if (argc < 4) { @@ -701,12 +934,8 @@ static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv) } /* Map the trigger string to an enum value */ - for (trigger = 0; trigger < ARRAY_SIZE(sensor_trigger_table); trigger++) { - if (strcmp(argv[3], sensor_trigger_table[trigger].name) == 0) { - break; - } - } - if (trigger >= SENSOR_TRIG_COMMON_COUNT || sensor_trigger_table[trigger].handler == NULL) { + trigger = sensor_trigger_name_lookup(argv[3]); + if (trigger < 0 || sensor_trigger_table[trigger].handler == NULL) { shell_error(sh, "Unsupported trigger type (%s)", argv[3]); return -ENOTSUP; } @@ -739,6 +968,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_sensor, cmd_sensor_attr_set, 2, 255), SHELL_CMD_ARG(attr_get, &dsub_device_name_for_attr, SENSOR_ATTR_GET_HELP, cmd_sensor_attr_get, 2, 255), + SHELL_COND_CMD(CONFIG_SENSOR_ASYNC_API, stream, &dsub_device_name_for_stream, + SENSOR_STREAM_HELP, cmd_sensor_stream), SHELL_COND_CMD(CONFIG_SENSOR_INFO, info, NULL, SENSOR_INFO_HELP, cmd_get_sensor_info), SHELL_CMD_ARG(trig, &dsub_trigger, SENSOR_TRIG_HELP, cmd_trig_sensor, diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index 9a74a536949963..1e3af7e92e3c7a 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -246,6 +246,9 @@ enum sensor_trigger_type { /** Trigger fires when no motion has been detected for a while. */ SENSOR_TRIG_STATIONARY, + + SENSOR_TRIG_FIFO_THRESHOLD, + SENSOR_TRIG_FIFO_FULL, /** * Number of all common sensor triggers. */ @@ -323,6 +326,8 @@ enum sensor_attribute { * to the new sampling frequency. */ SENSOR_ATTR_FF_DUR, + /** Watermark % for the hardware fifo interrupt */ + SENSOR_ATTR_FIFO_WATERMARK, /** * Number of all common sensor attributes. */ @@ -467,6 +472,15 @@ struct sensor_decoder_api { */ int (*get_timestamp)(const uint8_t *buffer, uint64_t *timestamp_ns); + /** + * @brief Check if the given trigger type is present + * + * @param[in] buffer The buffer provided on the :c:struct:`rtio` context. + * @param[in] trigger The trigger in question + * @return Whether the tigger is present in the buffer + */ + bool (*has_trigger)(const uint8_t *buffer, enum sensor_trigger_type trigger); + /** * @brief Get the shift count of a particular channel (multiplier) * @@ -511,13 +525,38 @@ struct sensor_decoder_api { typedef int (*sensor_get_decoder_t)(const struct device *dev, const struct sensor_decoder_api **api); +/** + * @brief Options for what to do with the associated data when a trigger is consumed + */ +enum sensor_stream_data_opt { + /** @brief Include whatever data is associated with the trigger */ + SENSOR_STREAM_DATA_INCLUDE = 0, + /** @brief Do nothing with the associated trigger data, it may be consumed later */ + SENSOR_STREAM_DATA_NOP = 1, + /** @brief Flush/clear whatever data is associated with the trigger */ + SENSOR_STREAM_DATA_DROP = 2, +}; + +struct sensor_stream_trigger { + enum sensor_trigger_type trigger; + enum sensor_stream_data_opt opt; +}; + +#define SENSOR_STREAM_TRIGGER_PREP(_trigger, _opt) \ + { \ + .trigger = (_trigger), .opt = (_opt), \ + } /* * Internal data structure used to store information about the IODevice for async reading and * streaming sensor data. */ struct sensor_read_config { const struct device *sensor; - enum sensor_channel *const channels; + const bool is_streaming; + union { + enum sensor_channel *const channels; + struct sensor_stream_trigger *const triggers; + }; size_t count; const size_t max; }; @@ -540,12 +579,24 @@ struct sensor_read_config { static enum sensor_channel __channel_array_##name[] = {__VA_ARGS__}; \ static struct sensor_read_config __sensor_read_config_##name = { \ .sensor = DEVICE_DT_GET(dt_node), \ + .is_streaming = false, \ .channels = __channel_array_##name, \ .count = ARRAY_SIZE(__channel_array_##name), \ .max = ARRAY_SIZE(__channel_array_##name), \ }; \ RTIO_IODEV_DEFINE(name, &__sensor_iodev_api, &__sensor_read_config_##name) +#define SENSOR_DT_STREAM_IODEV(name, dt_node, ...) \ + static enum sensor_trigger_type __trigger_array_##name[] = {__VA_ARGS__}; \ + static struct sensor_read_config __sensor_read_config_##name = { \ + .sensor = DEVICE_DT_GET(dt_node), \ + .is_streaming = true, \ + .triggers = __trigger_array_##name, \ + .count = ARRAY_SIZE(__trigger_array_##name), \ + .max = ARRAY_SIZE(__trigger_array_##name), \ + }; \ + RTIO_IODEV_DEFINE(name, &__sensor_iodev_api, &__sensor_read_config_##name) + /* Used to submit an RTIO sqe to the sensor's iodev */ typedef int (*sensor_submit_t)(const struct device *sensor, struct rtio_iodev_sqe *sqe); @@ -851,7 +902,7 @@ static inline int z_impl_sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, { struct sensor_read_config *cfg = (struct sensor_read_config *)iodev->data; - if (cfg->max < num_channels) { + if (cfg->max < num_channels || cfg->is_streaming) { return -ENOMEM; } @@ -859,6 +910,28 @@ static inline int z_impl_sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, memcpy(cfg->channels, channels, num_channels * sizeof(enum sensor_channel)); cfg->count = num_channels; return 0; +} + +static inline int sensor_stream(struct rtio_iodev *iodev, struct rtio *ctx, void *userdata, + struct rtio_sqe **handle) +{ + if (IS_ENABLED(CONFIG_USERSPACE)) { + struct rtio_sqe sqe; + + rtio_sqe_prep_read_multishot(&sqe, iodev, RTIO_PRIO_NORM, userdata); + rtio_sqe_copy_in_get_handles(ctx, &sqe, handle, 1); + } else { + struct rtio_sqe *sqe = rtio_sqe_acquire(ctx); + + if (sqe == NULL) { + return -ENOMEM; + } + if (handle != NULL) { + *handle = sqe; + } + rtio_sqe_prep_read_multishot(sqe, iodev, RTIO_PRIO_NORM, userdata); + } + rtio_submit(ctx, 0); return 0; } diff --git a/samples/sensor/sensor_shell/boards/tdk_robokit1.conf b/samples/sensor/sensor_shell/boards/tdk_robokit1.conf new file mode 100644 index 00000000000000..aee20b8b10049c --- /dev/null +++ b/samples/sensor/sensor_shell/boards/tdk_robokit1.conf @@ -0,0 +1,3 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 +CONFIG_SPI_RTIO=y From 1b4492daa46fb88eae810a1427656e82a6135776 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Wed, 5 Jul 2023 13:42:04 -0600 Subject: [PATCH 02/10] icm42688: Implement streaming APIs Add streaming implementation for icm42688 using both threshold and full FIFO triggers. Signed-off-by: Yuval Peress topic#sensor_stream --- drivers/sensor/icm42688/CMakeLists.txt | 1 + drivers/sensor/icm42688/Kconfig | 10 + drivers/sensor/icm42688/icm42688.c | 24 +- drivers/sensor/icm42688/icm42688.h | 12 + drivers/sensor/icm42688/icm42688_common.c | 9 +- drivers/sensor/icm42688/icm42688_decoder.c | 157 +++++++++- drivers/sensor/icm42688/icm42688_decoder.h | 9 + drivers/sensor/icm42688/icm42688_reg.h | 8 + drivers/sensor/icm42688/icm42688_rtio.c | 315 ++++++++++++++++++++- drivers/sensor/icm42688/icm42688_rtio.h | 2 + drivers/sensor/icm42688/icm42688_trigger.c | 24 +- drivers/sensor/icm42688/icm42688_trigger.h | 3 +- 12 files changed, 562 insertions(+), 12 deletions(-) diff --git a/drivers/sensor/icm42688/CMakeLists.txt b/drivers/sensor/icm42688/CMakeLists.txt index cf9308bb95c447..4bc7db3b617373 100644 --- a/drivers/sensor/icm42688/CMakeLists.txt +++ b/drivers/sensor/icm42688/CMakeLists.txt @@ -10,6 +10,7 @@ zephyr_library_sources( zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API icm42688_rtio.c) zephyr_library_sources_ifdef(CONFIG_ICM42688_DECODER icm42688_decoder.c) +zephyr_library_sources_ifdef(CONFIG_ICM42688_STREAM icm42688_rtio.c) zephyr_library_sources_ifdef(CONFIG_ICM42688_TRIGGER icm42688_trigger.c) zephyr_library_sources_ifdef(CONFIG_EMUL_ICM42688 icm42688_emul.c) zephyr_include_directories_ifdef(CONFIG_EMUL_ICM42688 .) diff --git a/drivers/sensor/icm42688/Kconfig b/drivers/sensor/icm42688/Kconfig index 19d0602cbd312f..8318ec7bd1b27e 100644 --- a/drivers/sensor/icm42688/Kconfig +++ b/drivers/sensor/icm42688/Kconfig @@ -32,6 +32,7 @@ if ICM42688 choice prompt "Trigger mode" + default ICM42688_TRIGGER_NONE if ICM42688_STREAM default ICM42688_TRIGGER_GLOBAL_THREAD help Specify the type of triggering to be used by the driver @@ -49,6 +50,15 @@ config ICM42688_TRIGGER_OWN_THREAD endchoice +config ICM42688_STREAM + bool "Use hardware FIFO to stream data" + select ICM42688_TRIGGER + default y + depends on SPI_RTIO + depends on SENSOR_ASYNC_API + help + Use this config option to enable streaming sensor data via RTIO subsystem. + config ICM42688_TRIGGER bool diff --git a/drivers/sensor/icm42688/icm42688.c b/drivers/sensor/icm42688/icm42688.c index b8ebef4f147eec..12af7038513484 100644 --- a/drivers/sensor/icm42688/icm42688.c +++ b/drivers/sensor/icm42688/icm42688.c @@ -156,6 +156,19 @@ static int icm42688_attr_set(const struct device *dev, enum sensor_channel chan, res = -EINVAL; } break; + case SENSOR_CHAN_ALL: + if (attr == SENSOR_ATTR_FIFO_WATERMARK) { + int64_t mval = sensor_value_to_micro(val); + + if (mval < 0 || mval > 1000000) { + return -EINVAL; + } + new_config.fifo_wm = CLAMP(mval * 2048 / 1000000, 0, 2048); + } else { + LOG_ERR("Unsupported attribute"); + res = -EINVAL; + } + break; default: LOG_ERR("Unsupported channel"); res = -EINVAL; @@ -258,7 +271,7 @@ int icm42688_init(const struct device *dev) data->cfg.gyro_fs = ICM42688_GYRO_FS_125; data->cfg.accel_odr = ICM42688_ACCEL_ODR_1000; data->cfg.gyro_odr = ICM42688_GYRO_ODR_1000; - data->cfg.fifo_en = false; + data->cfg.fifo_en = IS_ENABLED(CONFIG_ICM42688_STREAM); res = icm42688_configure(dev, &data->cfg); if (res != 0) { @@ -284,8 +297,15 @@ void icm42688_unlock(const struct device *dev) #define ICM42688_SPI_CFG \ SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_TRANSFER_MSB +#define ICM42688_RTIO_DEFINE(inst) \ + SPI_DT_IODEV_DEFINE(icm42688_spi_iodev_##inst, DT_DRV_INST(inst), ICM42688_SPI_CFG, 0U); \ + RTIO_DEFINE(icm42688_rtio_##inst, 8, 4); + #define ICM42688_DEFINE_DATA(inst) \ - static struct icm42688_dev_data icm42688_driver_##inst; + IF_ENABLED(CONFIG_ICM42688_STREAM, (ICM42688_RTIO_DEFINE(inst))); \ + static struct icm42688_dev_data icm42688_driver_##inst = { \ + IF_ENABLED(CONFIG_ICM42688_STREAM, (.r = &icm42688_rtio_##inst, \ + .spi_iodev = &icm42688_spi_iodev_##inst,))}; #define ICM42688_INIT(inst) \ ICM42688_DEFINE_DATA(inst); \ diff --git a/drivers/sensor/icm42688/icm42688.h b/drivers/sensor/icm42688/icm42688.h index 18ae4606e72593..c4167e6a3b9cf4 100644 --- a/drivers/sensor/icm42688/icm42688.h +++ b/drivers/sensor/icm42688/icm42688.h @@ -385,6 +385,9 @@ struct icm42688_cfg { /* TODO additional FIFO options */ /* TODO interrupt options */ + bool interrupt1_drdy; + bool interrupt1_fifo_ths; + bool interrupt1_fifo_full; }; struct icm42688_trigger_entry { @@ -405,6 +408,15 @@ struct icm42688_dev_data { #elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) struct k_work work; #endif +#ifdef CONFIG_ICM42688_STREAM + struct rtio_iodev_sqe *streaming_sqe; + struct rtio *r; + struct rtio_iodev *spi_iodev; + uint8_t int_status; + uint16_t fifo_count; + uint64_t timestamp; + atomic_t reading_fifo; +#endif /* CONFIG_ICM42688_STREAM */ const struct device *dev; struct gpio_callback gpio_cb; sensor_trigger_handler_t data_ready_handler; diff --git a/drivers/sensor/icm42688/icm42688_common.c b/drivers/sensor/icm42688/icm42688_common.c index 6e82f22678bd3e..b787ce5756fda2 100644 --- a/drivers/sensor/icm42688/icm42688_common.c +++ b/drivers/sensor/icm42688/icm42688_common.c @@ -12,6 +12,7 @@ #include "icm42688.h" #include "icm42688_reg.h" #include "icm42688_spi.h" +#include "icm42688_trigger.h" #include LOG_MODULE_REGISTER(ICM42688_LL, CONFIG_SENSOR_LOG_LEVEL); @@ -173,8 +174,12 @@ int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg) } /* Pulse mode with async reset (resets interrupt line on int status read) */ - res = icm42688_spi_single_write(&dev_cfg->spi, REG_INT_CONFIG, - BIT_INT1_DRIVE_CIRCUIT | BIT_INT1_POLARITY); + if (IS_ENABLED(CONFIG_ICM42688_TRIGGER)) { + res = icm42688_trigger_enable_interrupt(dev, cfg); + } else { + res = icm42688_spi_single_write(&dev_cfg->spi, REG_INT_CONFIG, + BIT_INT1_DRIVE_CIRCUIT | BIT_INT1_POLARITY); + } if (res) { LOG_ERR("Error writing to INT_CONFIG"); return res; diff --git a/drivers/sensor/icm42688/icm42688_decoder.c b/drivers/sensor/icm42688/icm42688_decoder.c index 16cb48dbcca05f..2d10220ecef5de 100644 --- a/drivers/sensor/icm42688/icm42688_decoder.c +++ b/drivers/sensor/icm42688/icm42688_decoder.c @@ -218,6 +218,98 @@ int icm42688_encode(const struct device *dev, const enum sensor_channel *const c return 0; } +static int icm42688_fifo_decode(const uint8_t *buffer, sensor_frame_iterator_t *fit, + sensor_channel_iterator_t *cit, enum sensor_channel *channels, + q31_t *values, uint8_t max_count) +{ + const struct icm42688_fifo_data *edata = (const struct icm42688_fifo_data *)buffer; + + if (edata->fifo_count <= *fit) { + return 0; + } + + /* Jump to the frame start */ + buffer += sizeof(struct icm42688_fifo_data) + *fit; + + const bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]); + const bool has_accel = FIELD_GET(FIFO_HEADER_ACCEL, buffer[0]); + const bool has_gyro = FIELD_GET(FIFO_HEADER_GYRO, buffer[0]); + const int channel_count = 1 + (has_accel ? 3 : 0) + (has_gyro ? 3 : 0); + const uint8_t *frame_end = buffer + /* header */ 1 + /* accel */ (has_accel ? 6 : 0) + + /* gyro */ (has_gyro ? 6 : 0) + + /* timestamp */ (has_accel && has_gyro ? 2 : 0) + + /* temperature */ (is_20b ? 2 : 1); + int header_channels[7]; + int count = 0; + + if (*cit >= channel_count) { + return -1; + } + + if (has_accel) { + header_channels[count++] = SENSOR_CHAN_ACCEL_X; + header_channels[count++] = SENSOR_CHAN_ACCEL_Y; + header_channels[count++] = SENSOR_CHAN_ACCEL_Z; + } + if (has_gyro) { + header_channels[count++] = SENSOR_CHAN_GYRO_X; + header_channels[count++] = SENSOR_CHAN_GYRO_Y; + header_channels[count++] = SENSOR_CHAN_GYRO_Z; + } + header_channels[count] = SENSOR_CHAN_DIE_TEMP; + count = 0; + + while (count < max_count && *cit < channel_count) { + /* + * [0]@0 - accel_x + * [1]@2 - accel_y + * [2]@4 - accel_z + * [3]@6 - gyro_x + * [4]@8 - gyro_y + * [5]@a - gyro_z + * [6]@c - temp + */ + int offset = 1 + *cit * 2; + + channels[count] = header_channels[*cit]; + int32_t value; + int32_t value_max = INT16_MAX; + + if (channels[count] == SENSOR_CHAN_DIE_TEMP) { + value = buffer[offset]; + if (is_20b) { + value |= (buffer[offset + 1] << 8); + } else { + value_max = INT8_MAX; + } + } else { + value = (buffer[offset] << 8) | buffer[offset + 1]; + if (is_20b) { + int mask = channels[count] < SENSOR_CHAN_ACCEL_XYZ ? GENMASK(7, 4) + : GENMASK(3, 0); + /* Get the offset after the end of the frame data */ + int ext_offset = + (channels[count] - (channels[count] < SENSOR_CHAN_ACCEL_XYZ + ? SENSOR_CHAN_ACCEL_X + : SENSOR_CHAN_GYRO_X)); + + value = (value << 4) | FIELD_GET(mask, frame_end[ext_offset]); + value_max = (1 << 19) - 1; + } + } + values[count] = (q31_t)((int64_t)value * INT32_MAX / value_max); + count++; + *cit += 1; + } + + if (*cit == channel_count) { + /* Reached the end of the frame */ + *fit += (uintptr_t)frame_end - (uintptr_t)buffer + (is_20b ? 3 : 0); + *cit = 0; + } + return count; +} + static int icm42688_one_shot_decode(const uint8_t *buffer, sensor_frame_iterator_t *fit, sensor_channel_iterator_t *cit, enum sensor_channel *channels, q31_t *values, uint8_t max_count) @@ -271,13 +363,53 @@ static int icm42688_decoder_decode(const uint8_t *buffer, sensor_frame_iterator_ sensor_channel_iterator_t *cit, enum sensor_channel *channels, q31_t *values, uint8_t max_count) { + const struct icm42688_decoder_header *header = + (const struct icm42688_decoder_header *)buffer; + + if (header->is_fifo) { + return icm42688_fifo_decode(buffer, fit, cit, channels, values, max_count); + } return icm42688_one_shot_decode(buffer, fit, cit, channels, values, max_count); } static int icm42688_decoder_get_frame_count(const uint8_t *buffer, uint16_t *frame_count) { - ARG_UNUSED(buffer); - *frame_count = 1; + const struct icm42688_fifo_data *data = (const struct icm42688_fifo_data *)buffer; + const struct icm42688_decoder_header *header = &data->header; + + if (!header->is_fifo) { + *frame_count = 1; + return 0; + } + + /* Skip the header */ + buffer += sizeof(struct icm42688_fifo_data); + + uint16_t count = 0; + const uint8_t *end = buffer + data->fifo_count; + + while (buffer < end) { + bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]); + int size = is_20b ? 3 : 2; + + if (FIELD_GET(FIFO_HEADER_ACCEL, buffer[0])) { + size += 6; + } + if (FIELD_GET(FIFO_HEADER_GYRO, buffer[0])) { + size += 6; + } + if (FIELD_GET(FIFO_HEADER_TIMESTAMP_FSYNC, buffer[0])) { + size += 2; + } + if (is_20b) { + size += 3; + } + + buffer += size; + ++count; + } + + *frame_count = count; return 0; } @@ -290,6 +422,26 @@ static int icm42688_decoder_get_timestamp(const uint8_t *buffer, uint64_t *times return 0; } +static bool icm24688_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) +{ + const struct icm42688_fifo_data *edata = (const struct icm42688_fifo_data *)buffer; + + if (!edata->header.is_fifo) { + return false; + } + + switch (trigger) { + case SENSOR_TRIG_DATA_READY: + return FIELD_GET(BIT_INT_STATUS_DATA_RDY, edata->int_status); + case SENSOR_TRIG_FIFO_THRESHOLD: + return FIELD_GET(BIT_INT_STATUS_FIFO_THS, edata->int_status); + case SENSOR_TRIG_FIFO_FULL: + return FIELD_GET(BIT_INT_STATUS_FIFO_FULL, edata->int_status); + default: + return false; + } +} + static int icm42688_decoder_get_shift(const uint8_t *buffer, enum sensor_channel channel_type, int8_t *shift) { @@ -303,6 +455,7 @@ SENSOR_DECODER_API_DT_DEFINE() = { .get_frame_count = icm42688_decoder_get_frame_count, .get_timestamp = icm42688_decoder_get_timestamp, .get_shift = icm42688_decoder_get_shift, + .has_trigger = icm24688_decoder_has_trigger, .decode = icm42688_decoder_decode, }; diff --git a/drivers/sensor/icm42688/icm42688_decoder.h b/drivers/sensor/icm42688/icm42688_decoder.h index 2ef806373c9402..499cf3d0801554 100644 --- a/drivers/sensor/icm42688/icm42688_decoder.h +++ b/drivers/sensor/icm42688/icm42688_decoder.h @@ -18,6 +18,15 @@ struct icm42688_decoder_header { uint8_t reserved: 2; } __attribute__((__packed__)); +struct icm42688_fifo_data { + struct icm42688_decoder_header header; + uint8_t int_status; + uint16_t gyro_odr: 4; + uint16_t accel_odr: 4; + uint16_t fifo_count: 11; + uint16_t reserved: 5; +} __attribute__((__packed__)); + struct icm42688_encoded_data { struct icm42688_decoder_header header; struct { diff --git a/drivers/sensor/icm42688/icm42688_reg.h b/drivers/sensor/icm42688/icm42688_reg.h index dfc348c072c8c7..5f3b58f0b3c074 100644 --- a/drivers/sensor/icm42688/icm42688_reg.h +++ b/drivers/sensor/icm42688/icm42688_reg.h @@ -286,4 +286,12 @@ #define MCLK_POLL_ATTEMPTS 100 #define SOFT_RESET_TIME_MS 2 /* 1ms + elbow room */ +/* FIFO header */ +#define FIFO_HEADER_ACCEL BIT(6) +#define FIFO_HEADER_GYRO BIT(5) +#define FIFO_HEADER_20 BIT(4) +#define FIFO_HEADER_TIMESTAMP_FSYNC GENMASK(3, 2) +#define FIFO_HEADER_ODR_ACCEL BIT(1) +#define FIFO_HEADER_ODR_GYRO BIT(0) + #endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_REG_H_ */ diff --git a/drivers/sensor/icm42688/icm42688_rtio.c b/drivers/sensor/icm42688/icm42688_rtio.c index c1b20689393d6c..1d70aadfd53413 100644 --- a/drivers/sensor/icm42688/icm42688_rtio.c +++ b/drivers/sensor/icm42688/icm42688_rtio.c @@ -42,7 +42,7 @@ static int icm42688_rtio_sample_fetch(const struct device *dev, int16_t readings return 0; } -int icm42688_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +static int icm42688_submit_one_shot(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) { const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; const enum sensor_channel *const channels = cfg->channels; @@ -78,4 +78,317 @@ int icm42688_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) return 0; } +int icm42688_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + struct icm42688_dev_data *data = dev->data; + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + int rc; + + if (!cfg->is_streaming) { + return icm42688_submit_one_shot(dev, iodev_sqe); + } + + /* Only support */ + struct icm42688_cfg new_config = data->cfg; + + new_config.interrupt1_drdy = false; + new_config.interrupt1_fifo_ths = false; + new_config.interrupt1_fifo_full = false; + for (int i = 0; i < cfg->count; ++i) { + switch (cfg->triggers[i].trigger) { + case SENSOR_TRIG_DATA_READY: + new_config.interrupt1_drdy = true; + break; + case SENSOR_TRIG_FIFO_THRESHOLD: + new_config.interrupt1_fifo_ths = true; + break; + case SENSOR_TRIG_FIFO_FULL: + new_config.interrupt1_fifo_full = true; + break; + default: + LOG_DBG("Trigger (%d) not supported", cfg->triggers[i].trigger); + break; + } + } + + if (new_config.interrupt1_drdy != data->cfg.interrupt1_drdy || + new_config.interrupt1_fifo_ths != data->cfg.interrupt1_fifo_ths || + new_config.interrupt1_fifo_full != data->cfg.interrupt1_fifo_full) { + rc = icm42688_safely_configure(dev, &new_config); + if (rc != 0) { + LOG_ERR("Failed to configure sensor"); + return rc; + } + } + + data->streaming_sqe = iodev_sqe; + return 0; +} + BUILD_ASSERT(sizeof(struct icm42688_decoder_header) == 9); + +static void icm42688_complete_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg) +{ + const struct device *dev = arg; + struct icm42688_dev_data *drv_data = dev->data; + const struct icm42688_dev_cfg *drv_cfg = dev->config; + struct rtio_iodev_sqe *iodev_sqe = sqe->userdata; + + rtio_iodev_sqe_ok(iodev_sqe, drv_data->fifo_count); + + gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); +} + +static void icm42688_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg) +{ + const struct device *dev = arg; + struct icm42688_dev_data *drv_data = dev->data; + const struct icm42688_dev_cfg *drv_cfg = dev->config; + struct rtio_iodev *spi_iodev = drv_data->spi_iodev; + uint8_t *fifo_count_buf = (uint8_t *)&drv_data->fifo_count; + uint16_t fifo_count = ((fifo_count_buf[0] << 8) | fifo_count_buf[1]); + + drv_data->fifo_count = fifo_count; + + /* Pull a operation from our device iodev queue, validated to only be reads */ + struct rtio_iodev_sqe *iodev_sqe = drv_data->streaming_sqe; + + drv_data->streaming_sqe = NULL; + + /* Not inherently an underrun/overrun as we may have a buffer to fill next time */ + if (iodev_sqe == NULL) { + LOG_DBG("No pending SQE"); + gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, + GPIO_INT_EDGE_TO_ACTIVE); + return; + } + + const size_t packet_size = drv_data->cfg.fifo_hires ? 20 : 16; + const size_t min_read_size = sizeof(struct icm42688_fifo_data) + packet_size; + const size_t ideal_read_size = sizeof(struct icm42688_fifo_data) + fifo_count; + uint8_t *buf; + uint32_t buf_len; + + if (rtio_sqe_rx_buf(iodev_sqe, min_read_size, ideal_read_size, &buf, &buf_len) != 0) { + LOG_ERR("Failed to get buffer"); + rtio_iodev_sqe_err(iodev_sqe, -ENOMEM); + return; + } + LOG_DBG("Requesting buffer [%u, %u] got %u", (unsigned int)min_read_size, + (unsigned int)ideal_read_size, buf_len); + + /* Read FIFO and call back to rtio with rtio_sqe completion */ + /* TODO is packet format even needed? the fifo has a header per packet + * already + */ + struct icm42688_fifo_data hdr = { + .header = { + .is_fifo = true, + .gyro_fs = drv_data->cfg.gyro_fs, + .accel_fs = drv_data->cfg.accel_fs, + .timestamp = drv_data->timestamp, + }, + .int_status = drv_data->int_status, + .gyro_odr = drv_data->cfg.gyro_odr, + .accel_odr = drv_data->cfg.accel_odr, + }; + uint32_t buf_avail = buf_len; + + memcpy(buf, &hdr, sizeof(hdr)); + buf_avail -= sizeof(hdr); + + uint32_t read_len = MIN(fifo_count, buf_avail); + uint32_t pkts = read_len / packet_size; + + read_len = pkts * packet_size; + ((struct icm42688_fifo_data *)buf)->fifo_count = read_len; + + __ASSERT_NO_MSG(read_len % pkt_size == 0); + + uint8_t *read_buf = buf + sizeof(hdr); + + /* Flush out completions */ + struct rtio_cqe *cqe; + + do { + cqe = rtio_cqe_consume(r); + if (cqe != NULL) { + rtio_cqe_release(r, cqe); + } + } while (cqe != NULL); + + /* Setup new rtio chain to read the fifo data and report then check the + * result + */ + struct rtio_sqe *write_fifo_addr = rtio_sqe_acquire(r); + struct rtio_sqe *read_fifo_data = rtio_sqe_acquire(r); + struct rtio_sqe *complete_op = rtio_sqe_acquire(r); + const uint8_t reg_addr = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_FIFO_DATA); + + rtio_sqe_prep_tiny_write(write_fifo_addr, spi_iodev, RTIO_PRIO_NORM, ®_addr, 1, NULL); + write_fifo_addr->flags = RTIO_SQE_TRANSACTION; + rtio_sqe_prep_read(read_fifo_data, spi_iodev, RTIO_PRIO_NORM, read_buf, read_len, + iodev_sqe); + + rtio_sqe_prep_callback(complete_op, icm42688_complete_cb, (void *)dev, iodev_sqe); + + rtio_submit(r, 0); +} + +static struct sensor_stream_trigger * +icm42688_get_read_config_trigger(const struct sensor_read_config *cfg, + enum sensor_trigger_type trig) +{ + for (int i = 0; i < cfg->count; ++i) { + if (cfg->triggers[i].trigger == trig) { + return &cfg->triggers[i]; + } + } + LOG_DBG("Unsupported trigger (%d)", trig); + return NULL; +} + +static void icm42688_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, void *arg) +{ + const struct device *dev = arg; + struct icm42688_dev_data *drv_data = dev->data; + const struct icm42688_dev_cfg *drv_cfg = dev->config; + struct rtio_iodev *spi_iodev = drv_data->spi_iodev; + struct rtio_iodev_sqe *streaming_sqe = drv_data->streaming_sqe; + struct sensor_read_config *read_config; + + if (streaming_sqe == NULL) { + return; + } + + read_config = (struct sensor_read_config *)streaming_sqe->sqe.iodev->data; + __ASSERT_NO_MSG(read_config != NULL); + + if (!read_config->is_streaming) { + /* Oops, not really configured for streaming data */ + return; + } + + struct sensor_stream_trigger *fifo_ths_cfg = + icm42688_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_THRESHOLD); + bool has_fifo_ths_trig = fifo_ths_cfg != NULL && + FIELD_GET(BIT_INT_STATUS_FIFO_THS, drv_data->int_status) != 0; + + struct sensor_stream_trigger *fifo_full_cfg = + icm42688_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_FULL); + bool has_fifo_full_trig = fifo_full_cfg != NULL && + FIELD_GET(BIT_INT_STATUS_FIFO_FULL, drv_data->int_status) != 0; + + if (!has_fifo_ths_trig && !has_fifo_full_trig) { + gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, + GPIO_INT_EDGE_TO_ACTIVE); + return; + } + + /* Flush completions */ + struct rtio_cqe *cqe; + + do { + cqe = rtio_cqe_consume(r); + if (cqe != NULL) { + rtio_cqe_release(r, cqe); + } + } while (cqe != NULL); + + enum sensor_stream_data_opt data_opt; + + if (has_fifo_ths_trig && !has_fifo_full_trig) { + /* Only care about fifo threshold */ + data_opt = fifo_ths_cfg->opt; + } else if (!has_fifo_ths_trig && has_fifo_full_trig) { + /* Only care about fifo full */ + data_opt = fifo_full_cfg->opt; + } else { + /* Both fifo threshold and full */ + data_opt = MIN(fifo_ths_cfg->opt, fifo_full_cfg->opt); + } + + if (data_opt == SENSOR_STREAM_DATA_NOP || data_opt == SENSOR_STREAM_DATA_DROP) { + uint8_t *buf; + uint32_t buf_len; + + /* Clear streaming_sqe since we're done with the call */ + drv_data->streaming_sqe = NULL; + if (rtio_sqe_rx_buf(streaming_sqe, sizeof(struct icm42688_fifo_data), + sizeof(struct icm42688_fifo_data), &buf, &buf_len) != 0) { + rtio_iodev_sqe_err(streaming_sqe, -ENOMEM); + return; + } + + struct icm42688_fifo_data *data = (struct icm42688_fifo_data *)buf; + + memset(buf, 0, buf_len); + data->header.timestamp = drv_data->timestamp; + data->int_status = drv_data->int_status; + data->fifo_count = 0; + rtio_iodev_sqe_ok(streaming_sqe, 0); + gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); + if (data_opt == SENSOR_STREAM_DATA_DROP) { + /* Flush the FIFO */ + struct rtio_sqe *write_signal_path_reset = rtio_sqe_acquire(r); + uint8_t write_buffer[] = { + FIELD_GET(REG_ADDRESS_MASK, REG_SIGNAL_PATH_RESET), + BIT_FIFO_FLUSH, + }; + + rtio_sqe_prep_tiny_write(write_signal_path_reset, spi_iodev, RTIO_PRIO_NORM, + write_buffer, ARRAY_SIZE(write_buffer), NULL); + /* TODO Add a new flag for fire-and-forget so we don't have to block here */ + rtio_submit(r, 1); + ARG_UNUSED(rtio_cqe_consume(r)); + } + return; + } + + /* We need the data, read the fifo length */ + struct rtio_sqe *write_fifo_count_reg = rtio_sqe_acquire(r); + struct rtio_sqe *read_fifo_count = rtio_sqe_acquire(r); + struct rtio_sqe *check_fifo_count = rtio_sqe_acquire(r); + uint8_t reg = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_FIFO_COUNTH); + uint8_t *read_buf = (uint8_t *)&drv_data->fifo_count; + + rtio_sqe_prep_tiny_write(write_fifo_count_reg, spi_iodev, RTIO_PRIO_NORM, ®, 1, NULL); + write_fifo_count_reg->flags = RTIO_SQE_TRANSACTION; + rtio_sqe_prep_read(read_fifo_count, spi_iodev, RTIO_PRIO_NORM, read_buf, 2, NULL); + rtio_sqe_prep_callback(check_fifo_count, icm42688_fifo_count_cb, arg, NULL); + + rtio_submit(r, 0); +} + +void icm42688_fifo_event(const struct device *dev) +{ + struct icm42688_dev_data *drv_data = dev->data; + struct rtio_iodev *spi_iodev = drv_data->spi_iodev; + struct rtio *r = drv_data->r; + + if (drv_data->streaming_sqe == NULL) { + return; + } + + drv_data->timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + + /* + * Setup rtio chain of ops with inline calls to make decisions + * 1. read int status + * 2. call to check int status and get pending RX operation + * 4. read fifo len + * 5. call to determine read len + * 6. read fifo + * 7. call to report completion + */ + struct rtio_sqe *write_int_reg = rtio_sqe_acquire(r); + struct rtio_sqe *read_int_reg = rtio_sqe_acquire(r); + struct rtio_sqe *check_int_status = rtio_sqe_acquire(r); + uint8_t reg = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_INT_STATUS); + + rtio_sqe_prep_tiny_write(write_int_reg, spi_iodev, RTIO_PRIO_NORM, ®, 1, NULL); + write_int_reg->flags = RTIO_SQE_TRANSACTION; + rtio_sqe_prep_read(read_int_reg, spi_iodev, RTIO_PRIO_NORM, &drv_data->int_status, 1, NULL); + rtio_sqe_prep_callback(check_int_status, icm42688_int_status_cb, (void *)dev, NULL); + rtio_submit(r, 0); +} diff --git a/drivers/sensor/icm42688/icm42688_rtio.h b/drivers/sensor/icm42688/icm42688_rtio.h index 748c8a022b0923..9b236aa41f73e2 100644 --- a/drivers/sensor/icm42688/icm42688_rtio.h +++ b/drivers/sensor/icm42688/icm42688_rtio.h @@ -9,4 +9,6 @@ int icm42688_submit(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe); +void icm42688_fifo_event(const struct device *dev); + #endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ */ diff --git a/drivers/sensor/icm42688/icm42688_trigger.c b/drivers/sensor/icm42688/icm42688_trigger.c index adaecf84baa656..b00df2596bcabd 100644 --- a/drivers/sensor/icm42688/icm42688_trigger.c +++ b/drivers/sensor/icm42688/icm42688_trigger.c @@ -12,6 +12,7 @@ #include "icm42688.h" #include "icm42688_reg.h" +#include "icm42688_rtio.h" #include "icm42688_spi.h" #include "icm42688_trigger.h" @@ -30,6 +31,9 @@ static void icm42688_gpio_callback(const struct device *dev, struct gpio_callbac #elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) k_work_submit(&data->work); #endif + if (IS_ENABLED(CONFIG_ICM42688_STREAM)) { + icm42688_fifo_event(data->dev); + } } #if defined(CONFIG_ICM42688_TRIGGER_OWN_THREAD) || defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) @@ -90,6 +94,8 @@ int icm42688_trigger_set(const struct device *dev, const struct sensor_trigger * switch (trig->type) { case SENSOR_TRIG_DATA_READY: + case SENSOR_TRIG_FIFO_THRESHOLD: + case SENSOR_TRIG_FIFO_FULL: data->data_ready_handler = handler; data->data_ready_trigger = trig; @@ -146,7 +152,7 @@ int icm42688_trigger_init(const struct device *dev) return gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); } -int icm42688_trigger_enable_interrupt(const struct device *dev) +int icm42688_trigger_enable_interrupt(const struct device *dev, struct icm42688_cfg *new_cfg) { int res; const struct icm42688_dev_cfg *cfg = dev->config; @@ -164,9 +170,19 @@ int icm42688_trigger_enable_interrupt(const struct device *dev) return res; } - /* enable data ready interrupt on INT1 pin */ - return icm42688_spi_single_write(&cfg->spi, REG_INT_SOURCE0, - FIELD_PREP(BIT_UI_DRDY_INT1_EN, 1)); + /* enable interrupts on INT1 pin */ + uint8_t value = 0; + + if (new_cfg->interrupt1_drdy) { + value |= FIELD_PREP(BIT_UI_DRDY_INT1_EN, 1); + } + if (new_cfg->interrupt1_fifo_ths) { + value |= FIELD_PREP(BIT_FIFO_THS_INT1_EN, 1); + } + if (new_cfg->interrupt1_fifo_full) { + value |= FIELD_PREP(BIT_FIFO_FULL_INT1_EN, 1); + } + return icm42688_spi_single_write(&cfg->spi, REG_INT_SOURCE0, value); } void icm42688_lock(const struct device *dev) diff --git a/drivers/sensor/icm42688/icm42688_trigger.h b/drivers/sensor/icm42688/icm42688_trigger.h index 5ed382eb0d403a..e0397591618120 100644 --- a/drivers/sensor/icm42688/icm42688_trigger.h +++ b/drivers/sensor/icm42688/icm42688_trigger.h @@ -26,9 +26,10 @@ int icm42688_trigger_init(const struct device *dev); * @brief enable the trigger gpio interrupt * * @param dev icm42688 device pointer + * @param new_cfg New configuration to use for the device * @return int 0 on success, negative error code otherwise */ -int icm42688_trigger_enable_interrupt(const struct device *dev); +int icm42688_trigger_enable_interrupt(const struct device *dev, struct icm42688_cfg *new_cfg); /** * @brief lock access to the icm42688 device driver From 6a6a2eb2c56a1f8956bda91babc25bf39cde7f3f Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Tue, 27 Jun 2023 01:15:17 -0600 Subject: [PATCH 03/10] Rework sensing subsystem Signed-off-by: Yuval Peress --- dts/bindings/sensing/zephyr,sensing-pipe.yaml | 43 ++ .../sensor/zephyr,sensing-phy-sensor.yaml | 13 - .../sensor/zephyr,sensing-sensor.yaml | 25 - dts/bindings/sensor/zephyr,sensing.yaml | 9 - .../sensor/zephyr,senss-phy-3d-sensor.yaml | 9 - include/zephyr/drivers/sensor.h | 11 +- .../{sensing_datatypes.h => datatypes.h} | 0 include/zephyr/sensing/sensing.h | 77 +-- include/zephyr/sensing/sensing_sensor.h | 594 ------------------ include/zephyr/sensing/sensor.h | 59 ++ ...{sensing_sensor_types.h => sensor_types.h} | 6 +- subsys/sensing/CMakeLists.txt | 9 +- subsys/sensing/Kconfig | 16 +- subsys/sensing/sensing.c | 145 ----- subsys/sensing/sensing_sensor.c | 28 - .../sensor/phy_3d_sensor/CMakeLists.txt | 3 - subsys/sensing/sensor/phy_3d_sensor/Kconfig | 9 - .../sensor/phy_3d_sensor/phy_3d_sensor.c | 100 --- .../sensor/phy_3d_sensor/phy_3d_sensor.h | 20 - subsys/sensing/sensor_mgmt.c | 323 ---------- subsys/sensing/sensor_mgmt.h | 166 ----- subsys/sensing/src/sensor_info.c | 14 + subsys/sensing/src/sensor_pipe.c | 29 + tests/subsys/sensing/list/CMakeLists.txt | 8 + .../sensing/list/boards/native_posix.overlay | 23 + tests/subsys/sensing/list/prj.conf | 15 + tests/subsys/sensing/list/src/main.c | 48 ++ tests/subsys/sensing/list/testcase.yaml | 9 + 28 files changed, 269 insertions(+), 1542 deletions(-) create mode 100644 dts/bindings/sensing/zephyr,sensing-pipe.yaml delete mode 100644 dts/bindings/sensor/zephyr,sensing-phy-sensor.yaml delete mode 100644 dts/bindings/sensor/zephyr,sensing-sensor.yaml delete mode 100644 dts/bindings/sensor/zephyr,sensing.yaml delete mode 100644 dts/bindings/sensor/zephyr,senss-phy-3d-sensor.yaml rename include/zephyr/sensing/{sensing_datatypes.h => datatypes.h} (100%) delete mode 100644 include/zephyr/sensing/sensing_sensor.h create mode 100644 include/zephyr/sensing/sensor.h rename include/zephyr/sensing/{sensing_sensor_types.h => sensor_types.h} (83%) delete mode 100644 subsys/sensing/sensing.c delete mode 100644 subsys/sensing/sensing_sensor.c delete mode 100644 subsys/sensing/sensor/phy_3d_sensor/CMakeLists.txt delete mode 100644 subsys/sensing/sensor/phy_3d_sensor/Kconfig delete mode 100644 subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c delete mode 100644 subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h delete mode 100644 subsys/sensing/sensor_mgmt.c delete mode 100644 subsys/sensing/sensor_mgmt.h create mode 100644 subsys/sensing/src/sensor_info.c create mode 100644 subsys/sensing/src/sensor_pipe.c create mode 100644 tests/subsys/sensing/list/CMakeLists.txt create mode 100644 tests/subsys/sensing/list/boards/native_posix.overlay create mode 100644 tests/subsys/sensing/list/prj.conf create mode 100644 tests/subsys/sensing/list/src/main.c create mode 100644 tests/subsys/sensing/list/testcase.yaml diff --git a/dts/bindings/sensing/zephyr,sensing-pipe.yaml b/dts/bindings/sensing/zephyr,sensing-pipe.yaml new file mode 100644 index 00000000000000..c5a91d0725f406 --- /dev/null +++ b/dts/bindings/sensing/zephyr,sensing-pipe.yaml @@ -0,0 +1,43 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: Passthrough sensor type which enables the sensing subsystem to communicate with physical devices + +compatible: "zephyr,sensing-pipe" + +include: [sensor-device.yaml, base.yaml] + +properties: + dev: + type: phandle + required: true + description: Physical device which provides the data + + sensor-types: + type: array + required: true + description: | + One or more sensor data types that are provided by this device. For + example, a 'dev' pointing to a bmi160 may report accel/gyro/die_temp or + any subset of those types. + + rotation-matrix: + type: array + description: | + 3x3 matrix to rotation x, y, and z axes. + In order to make application logic agnostic to how the device was placed + on the board, it's possible to enter the rotation matrix which will be + applied to every sample produced by this sensor. The final orientation + will be: + * X-axis is horizontal and positive toward the right + * Y-axis is vertical and positive toward the top + * Z-axis is depth and positive toward the user + + If not provided, the rotation matrix will be the identity matrix. + Otherwise, the following will be used: + + +- -+ +- -+ +- -+ + | v1 v2 v3 | | sensor_X | = | X | + | v4 v5 v6 | * | sensor_Y | = | Y | + | v7 v8 v9 | | sensor_Z | = | Z | + +- -+ +- -+ +- -+ diff --git a/dts/bindings/sensor/zephyr,sensing-phy-sensor.yaml b/dts/bindings/sensor/zephyr,sensing-phy-sensor.yaml deleted file mode 100644 index 8219f77a210392..00000000000000 --- a/dts/bindings/sensor/zephyr,sensing-phy-sensor.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2023, Intel Corporation -# SPDX-License-Identifier: Apache-2.0 -# - -description: Sensing subsystem physical sensor properties bindings. - -include: zephyr,sensing-sensor.yaml - -properties: - underlying-device: - type: phandle - required: true - description: underlying sensor device for physical sensor diff --git a/dts/bindings/sensor/zephyr,sensing-sensor.yaml b/dts/bindings/sensor/zephyr,sensing-sensor.yaml deleted file mode 100644 index 5bcaa39f2570e0..00000000000000 --- a/dts/bindings/sensor/zephyr,sensing-sensor.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2023, Intel Corporation -# SPDX-License-Identifier: Apache-2.0 -# - -description: Sensing subsystem sensor common properties bindings. - -include: sensor-device.yaml - -properties: - sensor-type: - type: int - required: true - description: sensor type id (follow HID spec definition) - - friendly-name: - required: true - - minimal-interval: - type: int - required: true - description: sensor minimal report interval - - reporters: - type: phandles - description: sensor reporters diff --git a/dts/bindings/sensor/zephyr,sensing.yaml b/dts/bindings/sensor/zephyr,sensing.yaml deleted file mode 100644 index 00b5452a8471a4..00000000000000 --- a/dts/bindings/sensor/zephyr,sensing.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2023, Intel Corporation -# SPDX-License-Identifier: Apache-2.0 -# - -description: Sensing Subsystem - -compatible: "zephyr,sensing" - -# To add sensor subsystem related common feature diff --git a/dts/bindings/sensor/zephyr,senss-phy-3d-sensor.yaml b/dts/bindings/sensor/zephyr,senss-phy-3d-sensor.yaml deleted file mode 100644 index ed8cb8af19495c..00000000000000 --- a/dts/bindings/sensor/zephyr,senss-phy-3d-sensor.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2023, Intel Corporation -# SPDX-License-Identifier: Apache-2.0 -# - -description: Sensing subsystem physical 3d sensors(accel, gyro, mag) bindings. - -compatible: "zephyr,sensing-phy-3d-sensor" - -include: zephyr,sensing-phy-sensor.yaml diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index 1e3af7e92e3c7a..bf8bde5da5cf38 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -1210,7 +1210,7 @@ struct sensor_info { } #define SENSOR_INFO_DEFINE(name, ...) \ - static const STRUCT_SECTION_ITERABLE(sensor_info, name) = \ + const STRUCT_SECTION_ITERABLE(sensor_info, name) = \ SENSOR_INFO_INITIALIZER(__VA_ARGS__) #define SENSOR_INFO_DT_NAME(node_id) \ @@ -1221,7 +1221,14 @@ struct sensor_info { DEVICE_DT_GET(node_id), \ DT_NODE_VENDOR_OR(node_id, NULL), \ DT_NODE_MODEL_OR(node_id, NULL), \ - DT_PROP_OR(node_id, friendly_name, NULL)) \ + DT_PROP_OR(node_id, friendly_name, NULL)) + +#if defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__) +#define Z_MAYBE_SENSOR_INFO_DECLARE_INTERNAL(node_id) \ + extern const struct sensor_info SENSOR_INFO_DT_NAME(node_id); + +DT_FOREACH_STATUS_OKAY_NODE(Z_MAYBE_SENSOR_INFO_DECLARE_INTERNAL); +#endif /* CONFIG_HAS_DTS || __DOXYGEN__ */ #else diff --git a/include/zephyr/sensing/sensing_datatypes.h b/include/zephyr/sensing/datatypes.h similarity index 100% rename from include/zephyr/sensing/sensing_datatypes.h rename to include/zephyr/sensing/datatypes.h diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index 3b11d1b410ca4a..c80afe59936a02 100644 --- a/include/zephyr/sensing/sensing.h +++ b/include/zephyr/sensing/sensing.h @@ -17,9 +17,10 @@ * @ingroup sensing */ -#include -#include #include +#include +#include +#include /** * @brief Sensing Subsystem API @@ -82,17 +83,6 @@ enum sensing_sensor_state { SENSING_SENSOR_STATE_OFFLINE = 1, }; -/** - * @brief Sensing subsystem sensor config attribute - * - */ -enum sensing_sensor_attribute { - SENSING_SENSOR_ATTRIBUTE_INTERVAL = 0, - SENSING_SENSOR_ATTRIBUTE_SENSITIVITY = 1, - SENSING_SENSOR_ATTRIBUTE_LATENCY = 2, - SENSING_SENSOR_ATTRIBUTE_MAX, -}; - /** * @brief Define Sensing subsystem sensor handle @@ -118,23 +108,10 @@ typedef void (*sensing_data_event_t)( * */ struct sensing_sensor_info { - /** Name of the sensor instance */ - const char *name; - - /** Friendly name of the sensor instance */ - const char *friendly_name; - - /** Vendor name of the sensor instance */ - const char *vendor; - - /** Model name of the sensor instance */ - const char *model; + const struct sensor_info * info; /** Sensor type */ - const int32_t type; - - /** Minimal report interval in micro seconds */ - const uint32_t minimal_interval; + int32_t type; }; /** @@ -145,20 +122,6 @@ struct sensing_sensor_info { struct sensing_callback_list { sensing_data_event_t on_data_event; }; -/** - * @struct sensing_sensor_config - * @brief Sensing subsystem sensor configure, including interval, sensitivity, latency - * - */ -struct sensing_sensor_config { - enum sensing_sensor_attribute attri; - int8_t data_field; - union { - uint32_t interval; - uint32_t sensitivity; - uint64_t latency; - }; -}; /** @@ -227,36 +190,6 @@ int sensing_open_sensor_by_dt( int sensing_close_sensor( sensing_sensor_handle_t *handle); -/** - * @brief Set current config items to Sensing subsystem. - * - * @param handle The sensor instance handle. - * - * @param configs The configs to be set according to config attribute. - * - * @param count count of configs. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -int sensing_set_config( - sensing_sensor_handle_t handle, - struct sensing_sensor_config *configs, int count); - -/** - * @brief Get current config items from Sensing subsystem. - * - * @param handle The sensor instance handle. - * - * @param configs The configs to be get according to config attribute. - * - * @param count count of configs. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -int sensing_get_config( - sensing_sensor_handle_t handle, - struct sensing_sensor_config *configs, int count); - /** * @brief Get sensor information from sensor instance handle. * diff --git a/include/zephyr/sensing/sensing_sensor.h b/include/zephyr/sensing/sensing_sensor.h deleted file mode 100644 index e7716a317d8e81..00000000000000 --- a/include/zephyr/sensing/sensing_sensor.h +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Copyright (c) 2022-2023 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_SENSING_SENSOR_H_ -#define ZEPHYR_INCLUDE_SENSING_SENSOR_H_ - -#include -#include -#include -#include - -/** - * @defgroup sensing_sensor Sensing Sensor API - * @ingroup sensing - * @defgroup sensing_sensor_callbacks Sensor Callbacks - * @ingroup sensing_sensor - */ - -/** - * @brief Sensing Sensor API - * @addtogroup sensing_sensor - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Sensor registration information - * - */ -struct sensing_sensor_register_info { - - /** - * Sensor flags - */ - uint16_t flags; - - /** - * Sample size in bytes for a single sample of the registered sensor. - * sensing runtime need this information for internal buffer allocation. - */ - uint16_t sample_size; - - /** - * The number of sensor sensitivities - */ - uint8_t sensitivity_count; - - /** - * Sensor version. - * Version can be used to identify different versions of sensor implementation. - */ - struct sensing_sensor_version version; -}; - -/** - * @brief Sensor context data structure - * - */ -struct sensing_sensor_ctx { - - /** - * For sensing runtime internal private data, sensor should not see and touch - */ - void *priv_ptr; - - /** - * Pointer to the sensor register information. - */ - const struct sensing_sensor_register_info *register_info; - - /** - * For sensor private context data, registered by sensor with \ref SENSING_SENSOR_DT_DEFINE. - * Sensor could use \ref sensing_sensor_get_ctx_data to fetch out this filed with - * struct device. - */ - void *const sensor_ctx_ptr; -}; - -static inline int sensing_sensor_dev_init( - const struct device *dev) -{ - /** - * Nothing need to do in system auto initialization. - * Sensor subsystem runtime will call each sensor instance's initialization - * function via API callback according sensor reporting dependency sequences. - * Sensor subsystem can make sure the depends sensor instances always initialized before - * client sensors. - */ - return 0; -} - -/** - * @brief Macro for define a sensor instance from device tree node id - * - * This macro also defined a struct device for this sensor instance, and registered sensors' - * private context data, configuration data structure and API. - * - * sensing_init will enumerate all sensor instances from device tree, and initialize each sensor - * instance defined by this macro. - * - */ - -#define SENSING_SENSOR_DT_DEFINE(node_id, reg_ptr, ctx_ptr, api_ptr) \ - static struct sensing_sensor_ctx \ - _CONCAT(__sensing_sensor_ctx_, Z_DEVICE_DT_DEV_ID(node_id)) = { \ - .register_info = reg_ptr, \ - .sensor_ctx_ptr = ctx_ptr, \ - }; \ - DEVICE_DT_DEFINE(node_id, sensing_sensor_dev_init, NULL, \ - &_CONCAT(__sensing_sensor_ctx_, Z_DEVICE_DT_DEV_ID(node_id)), \ - NULL, APPLICATION, 10, api_ptr) - -/** - * @brief Get registered context data pointer for a sensor instance. - * - * Used by a sensor instance to get its registered context data pointer with its struct device. - * - * @param dev The sensor instance device structure. - */ -static inline void *sensing_sensor_get_ctx_data( - const struct device *dev) -{ - struct sensing_sensor_ctx *data = dev->data; - - return data->sensor_ctx_ptr; -} - -/** - * @brief Post sensor data, sensor subsystem runtime will deliver to it's - * clients. - * - * Unblocked function, returned immediately. - * - * Used by a virtual sensor to post data to it's clients. - * - * A reporter sensor can use this API to post data to it's clients. - * For example, when a virtual sensor computed a data, then can use this API - * to deliver the data to it's clients. - * Please note, this API just for reporter post data to the sensor subsystem - * runtime, the runtime will help delivered the data to it's all clients - * according clients' configurations such as reporter interval, data change sensitivity. - * - * @param dev The sensor instance device structure. - * - * @param buf The data buffer. - * - * @param size The buffer size in bytes. - * - * @return 0 on success or negative error value on failure. - */ -int sensing_sensor_post_data( - const struct device *dev, - void *buf, int size); - -/** - * @brief Get reporter handles of a given sensor instance by sensor type. - * - * @param dev The sensor instance device structure. - * - * @param type The given type, \ref SENSING_SENSOR_TYPE_ALL to get reporters - * with all types. - * - * @param max_handles The max count of the \p reporter_handles array input. Can - * get real count number via \ref sensing_sensor_get_reporters_count - * - * @param *reporter_handles Input handles array for receiving found reporter - * sensor instances - * - * @return number of reporters found, 0 returned if not found. - */ -int sensing_sensor_get_reporters( - const struct device *dev, int type, - const int *reporter_handles, int max_handles); - -/** - * @brief Get reporters count of a given sensor instance by sensor type. - * - * @param dev The sensor instance device structure. - * - * @param type The sensor type for checking, \ref SENSING_SENSOR_TYPE_ALL - * - * @return Count of reporters by \p type, 0 returned if no reporters by \p type. - */ -int sensing_sensor_get_reporters_count( - const struct device *dev, int type); - -/** - * @brief Get this sensor's state - * - * @param dev The sensor instance device structure. - * - * @param state Returned sensor state value - * - * @return 0 on success or negative error value on failure. - */ -int sensing_sensor_get_state( - const struct device *dev, - enum sensing_sensor_state *state); - -/** - * @brief Trigger the data ready event to sensing - * - * @param dev Pointer to the sensor device - * - * @return 0 on success or negative error value on failure. - */ -int sensing_sensor_notify_data_ready( - const struct device *dev); - -/** - * @brief Set the data ready mode of the sensor - * - * @param dev Pointer to the sensor device - * - * @param data_ready Enable/disable the data ready mode. Default:disabled - * - * @return 0 on success or negative error value on failure. - */ -int sensing_sensor_set_data_ready( - const struct device *dev, bool data_ready); - -/** - * @} - */ - -/** - * @brief Sensor Callbacks - * @addtogroup sensing_sensor_callbacks - * \{ - */ - -/** - * @brief Sensor initialize. - * - * Sensor can initialize it's runtime context in this callback. - * - * @param dev The sensor instance device structure. - * - * @param info The sensor instance's constant information. - * - * @param reporter_handles The reporters handles for this sensor, NULL for physical sensors. - * - * @param reporters_count The number of reporters, zero for physical sensors. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_init_t)( - const struct device *dev, const struct sensing_sensor_info *info, - const sensing_sensor_handle_t *reporter_handles, int reporters_count); - -/** - * @brief Sensor's de-initialize. - * - * Sensor can release it's runtime context in this callback. - * - * @param dev The sensor instance device structure. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_deinit_t)( - const struct device *dev); - -/** - * @brief Sensor reset. - * - * Sensor can reset its runtime context in this callback to default values without resources - * release and re-allocation. - * - * Its very useful for a virtual sensor to quickly reset its runtime context to a default state. - * - * @param dev The sensor instance device structure. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_reset_t)( - const struct device *dev); - -/** - * @brief Sensor read sample. - * - * Only physical sensor need implement this callback. - * Physical sensor can fetch sample data from sensor device in this callback - * - * @param dev The sensor instance device structure. - * - * @param buf Sensor subsystem runtime allocated buffer, and passed its pointer - * to this sensor for store fetched sample. - * - * @param size The size of the buffer in bytes. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_read_sample_t)( - const struct device *dev, - void *buf, int size); - -/** - * @brief Sensor process data. - * - * Only virtual sensor need implement this callback. - * Virtual sensor can receive reporter's data and do fusion computing - * in this callback. - * - * @param dev The sensor instance device structure. - * - * @param reporter The reporter handle who delivered this sensor data - * - * @param buf The buffer stored the reporter's sensor data. - * - * @param size The size of the buffer in bytes. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_process_t)( - const struct device *dev, - int reporter, - void *buf, int size); - -/** - * @brief Trigger a sensor to do self calibration - * - * If not support self calibration, can not implement this callback. - * - * @param dev The sensor instance device structure. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_self_calibration_t)( - const struct device *dev); - -/** - * @brief Sensitivity arbitration. - * - * This callback API provides a chance for sensor to do customized arbitration on data change - * sensitivity. - * The sensor can check two sequential samples with client's sensitivity value (passed with - * parameters in this callback) and decide if can pass the sensor sample to its client. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param sensitivity The sensitivity value. - * - * @param last_sample_buf The buffer stored last sample data. - * - * @param last_sample_size The size of last sample's data buffer in bytes - * - * @param current_sample_buf The buffer stored current sample data. - * - * @param current_sample_size The size of current sample's data buffer in bytes - * - * @return 0 on test passed or negative error value on failure. - * - */ -typedef int (*sensing_sensor_sensitivity_test_t)( - const struct device *dev, - int index, uint32_t sensitivity, - void *last_sample_buf, int last_sample_size, - void *current_sample_buf, int current_sample_size); - -/** - * @brief Set current report interval. - * - * @param dev The sensor instance device structure. - * - * @param value The value to be set. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_set_interval_t)( - const struct device *dev, - uint32_t value); - -/** - * @brief Get current report interval. - * - * @param dev The sensor instance device structure. - * - * @param value The data buffer to receive value. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_get_interval_t)( - const struct device *dev, - uint32_t *value); - -/** - * @brief Set data change sensitivity. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support set separated sensitivity for each data field, or global - * sensitivity for all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The value to be set. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_set_sensitivity_t)( - const struct device *dev, - int index, uint32_t value); - -/** - * @brief Get current data change sensitivity. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support get separated sensitivity for each data field, or global - * sensitivity for all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The data buffer to receive value. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_get_sensitivity_t)( - const struct device *dev, - int index, uint32_t *value); - -/** - * @brief Set data range. - * - * Some sensors especially for physical sensors, support data range - * configuration, this may change data resolution. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support set separated range for each data field, or global range for - * all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The value to be set. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_set_range_t)( - const struct device *dev, - int index, uint32_t value); - -/** - * @brief Get current data range. - * - * Some sensors especially for physical sensors, support data range - * configuration, this may change data resolution. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support get separated range for each data field, or global range for - * all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The data buffer to receive value. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_get_range_t)( - const struct device *dev, - int index, uint32_t *value); - -/** - * @brief Set current sensor's hardware fifo size - * - * Some sensors especially for physical sensors, support hardware fifo, this API can - * configure the current fifo size. - * - * @param dev The sensor instance device structure. - * - * @param samples The sample number to set for fifo. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_set_fifo_t)( - const struct device *dev, - uint32_t samples); - -/** - * @brief Get current sensor's hardware fifo size - * - * Some sensors especially for physical sensors, support fifo, this API can - * get the current fifo size. - * - * @param dev The sensor instance device structure. - * - * @param samples The data buffer to receive the fifo sample number. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_get_fifo_t)( - const struct device *dev, - uint32_t *samples); - -/** - * @brief Set current sensor data offset - * - * Some sensors especially for physical sensors, such as accelerometer senors, - * as data drift, need configure offset calibration. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support set separated offset for each data field, or global offset for - * all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The offset value to be set. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_set_offset_t)( - const struct device *dev, - int index, int32_t value); - -/** - * @brief Get current sensor data offset - * - * Some sensors especially for physical sensors, such as accelerometer senors, - * as data drift, need configure offset calibration. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support get separated offset for each data field, or global offset for - * all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The data buffer to receive the offset value. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_get_offset_t)( - const struct device *dev, - int index, int32_t *value); -/** - * @struct sensing_sensor_api - * @brief Sensor callback api - * - * A sensor must register this callback API during sensor registration. - */ -struct sensing_sensor_api { - sensing_sensor_init_t init; - sensing_sensor_reset_t reset; - sensing_sensor_deinit_t deinit; - sensing_sensor_set_interval_t set_interval; - sensing_sensor_get_interval_t get_interval; - sensing_sensor_set_range_t set_range; - sensing_sensor_get_range_t get_range; - sensing_sensor_set_offset_t set_offset; - sensing_sensor_get_offset_t get_offset; - sensing_sensor_get_fifo_t get_fifo; - sensing_sensor_set_fifo_t set_fifo; - sensing_sensor_set_sensitivity_t set_sensitivity; - sensing_sensor_get_sensitivity_t get_sensitivity; - sensing_sensor_read_sample_t read_sample; - sensing_sensor_process_t process; - sensing_sensor_sensitivity_test_t sensitivity_test; - sensing_sensor_self_calibration_t self_calibration; -}; - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /*ZEPHYR_INCLUDE_SENSING_SENSOR_H_*/ diff --git a/include/zephyr/sensing/sensor.h b/include/zephyr/sensing/sensor.h new file mode 100644 index 00000000000000..434f9b7357403b --- /dev/null +++ b/include/zephyr/sensing/sensor.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022-2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SENSING_SENSOR_H_ +#define ZEPHYR_INCLUDE_SENSING_SENSOR_H_ + +#include +#include +#include + +#define SENSING_SENSOR_INFO_DT_NAME(node_id, type) \ + _CONCAT(_CONCAT(__sensing_sensor_info_, DEVICE_DT_NAME_GET(node_id)), type) + +#define SENSING_SENSOR_INFO_INST_DEFINE(node_id, prop, idx) \ + const STRUCT_SECTION_ITERABLE( \ + sensing_sensor_info, \ + SENSING_SENSOR_INFO_DT_NAME(node_id, DT_PROP_BY_IDX(node_id, prop, idx))) = { \ + .info = &SENSOR_INFO_DT_NAME(DT_PHANDLE(node_id, dev)), \ + .type = DT_PROP_BY_IDX(node_id, prop, idx), \ + }; + +#define SENSING_SENSOR_INFO_DT_DEFINE(node_id) \ + DT_FOREACH_PROP_ELEM(node_id, sensor_types, SENSING_SENSOR_INFO_INST_DEFINE) + +#define SENSING_SENSOR_DT_DEFINE(node_id, init_fn, pm_device, data_ptr, cfg_ptr, level, prio, \ + api_ptr, ...) \ + SENSING_SENSOR_INFO_DT_DEFINE(node_id); \ + DEVICE_DT_DEFINE(node_id, init_fn, pm_device, data_ptr, cfg_ptr, level, prio, api_ptr, \ + __VA_ARGS__) + +#define SENSING_SENSOR_DT_INST_DEFINE(inst, ...) \ + SENSING_SENSOR_DT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__) + +#define SENSING_SENSOR_INFO_GET(node_id, type) &SENSING_SENSOR_INFO_DT_NAME(node_id, type) + +STRUCT_SECTION_START_EXTERN(sensing_sensor_info); + +#if defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__) +#define Z_MAYBE_SENSING_SENSOR_INFO_DECLARE_INTERNAL_DEFINE(node_id, prop, idx) \ + extern const struct sensing_sensor_info SENSING_SENSOR_INFO_DT_NAME( \ + node_id, DT_PROP_BY_IDX(node_id, prop, idx)); + +#define Z_MAYBE_SENSING_SENSOR_INFO_DECLARE_INTERNAL(node_id) \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, sensor_types), \ + (DT_FOREACH_PROP_ELEM(node_id, sensor_types, \ + Z_MAYBE_SENSING_SENSOR_INFO_DECLARE_INTERNAL_DEFINE)), \ + ()) + +DT_FOREACH_STATUS_OKAY_NODE(Z_MAYBE_SENSING_SENSOR_INFO_DECLARE_INTERNAL); +#endif /* CONFIG_HAS_DTS || __DOXYGEN__ */ + +#ifdef __cplusplus +} +#endif + +#endif /*ZEPHYR_INCLUDE_SENSING_SENSOR_H_*/ diff --git a/include/zephyr/sensing/sensing_sensor_types.h b/include/zephyr/sensing/sensor_types.h similarity index 83% rename from include/zephyr/sensing/sensing_sensor_types.h rename to include/zephyr/sensing/sensor_types.h index db15af1e279f7a..03b7b9730c79cc 100644 --- a/include/zephyr/sensing/sensing_sensor_types.h +++ b/include/zephyr/sensing/sensor_types.h @@ -27,9 +27,9 @@ /** * sensor category motion */ -#define SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D 0x73 -#define SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D 0x76 -#define SENSING_SENSOR_TYPE_MOTION_MOTION_DETECTOR 0x77 +#define SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D 115 +#define SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D 118 +#define SENSING_SENSOR_TYPE_MOTION_MOTION_DETECTOR 119 /** diff --git a/subsys/sensing/CMakeLists.txt b/subsys/sensing/CMakeLists.txt index 59aa28514b03fe..a401e0a8372c04 100644 --- a/subsys/sensing/CMakeLists.txt +++ b/subsys/sensing/CMakeLists.txt @@ -1,12 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library() -zephyr_library_include_directories(include) - zephyr_library_sources( - sensor_mgmt.c - sensing.c - sensing_sensor.c + src/sensor_info.c + src/sensor_pipe.c ) - -add_subdirectory_ifdef(CONFIG_SENSING_SENSOR_PHY_3D_SENSOR sensor/phy_3d_sensor) diff --git a/subsys/sensing/Kconfig b/subsys/sensing/Kconfig index 9101db074457a5..dff3b430b69bb2 100644 --- a/subsys/sensing/Kconfig +++ b/subsys/sensing/Kconfig @@ -3,8 +3,8 @@ config SENSING bool "Sensing Subsystem" - default y - depends on DT_HAS_ZEPHYR_SENSING_ENABLED + select DSP + select SENSOR_INFO help Enable Sensing Subsystem. @@ -14,16 +14,4 @@ module = SENSING module-str = sensing source "subsys/logging/Kconfig.template.log_config" -config SENSING_MAX_SENSITIVITY_COUNT - int "maximum sensitivity count one sensor could support" - depends on SENSING - default 6 - help - This is the maximum sensitivity count one sensor could support, - some sensors such as ALS sensor could define different sensitivity for each data filed, - So, maximum sensitivity count is needed for sensors - Typical values are 6 - -source "subsys/sensing/sensor/phy_3d_sensor/Kconfig" - endif # SENSING diff --git a/subsys/sensing/sensing.c b/subsys/sensing/sensing.c deleted file mode 100644 index 6074925437923c..00000000000000 --- a/subsys/sensing/sensing.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2023 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include "sensor_mgmt.h" - -#include -LOG_MODULE_DECLARE(sensing, CONFIG_SENSING_LOG_LEVEL); - -/* sensing_open_sensor is normally called by applications: hid, chre, zephyr main, etc */ -int sensing_open_sensor(const struct sensing_sensor_info *sensor_info, - const struct sensing_callback_list *cb_list, - sensing_sensor_handle_t *handle) -{ - int ret = 0; - - if (handle == NULL) { - return -ENODEV; - } - - STRUCT_SECTION_FOREACH(sensing_sensor, sensor) { - if (sensor_info == sensor->info) { - ret = open_sensor(sensor, (struct sensing_connection **)handle); - if (ret) { - return -EINVAL; - } - break; - } - } - - return sensing_register_callback(*handle, cb_list); -} - -int sensing_open_sensor_by_dt(const struct device *dev, - const struct sensing_callback_list *cb_list, - sensing_sensor_handle_t *handle) -{ - int ret = 0; - struct sensing_sensor *sensor; - - if (handle == NULL) { - return -ENODEV; - } - - sensor = get_sensor_by_dev(dev); - if (sensor == NULL) { - LOG_ERR("cannot get sensor from dev:%p", dev); - return -ENODEV; - } - - ret = open_sensor(sensor, (struct sensing_connection **)handle); - if (ret) { - return -EINVAL; - } - - return sensing_register_callback(*handle, cb_list); -} - -/* sensing_close_sensor is normally called by applications: hid, chre, zephyr main, etc */ -int sensing_close_sensor(sensing_sensor_handle_t *handle) -{ - return close_sensor((struct sensing_connection **)handle); -} - -int sensing_set_config(sensing_sensor_handle_t handle, - struct sensing_sensor_config *configs, - int count) -{ - struct sensing_sensor_config *cfg; - int i, ret = 0; - - if (count <= 0 || count > SENSING_SENSOR_ATTRIBUTE_MAX) { - LOG_ERR("invalid config count:%d", count); - return -EINVAL; - } - - for (i = 0; i < count; i++) { - cfg = &configs[i]; - switch (cfg->attri) { - case SENSING_SENSOR_ATTRIBUTE_INTERVAL: - ret |= set_interval(handle, cfg->interval); - break; - - case SENSING_SENSOR_ATTRIBUTE_SENSITIVITY: - ret |= set_sensitivity(handle, cfg->data_field, cfg->sensitivity); - break; - - case SENSING_SENSOR_ATTRIBUTE_LATENCY: - break; - - default: - ret = -EINVAL; - LOG_ERR("invalid config attribute:%d\n", cfg->attri); - break; - } - } - - return ret; -} - -int sensing_get_config(sensing_sensor_handle_t handle, - struct sensing_sensor_config *configs, - int count) -{ - struct sensing_sensor_config *cfg; - int i, ret = 0; - - if (count <= 0 || count > SENSING_SENSOR_ATTRIBUTE_MAX) { - LOG_ERR("invalid config count:%d", count); - return -EINVAL; - } - - for (i = 0; i < count; i++) { - cfg = &configs[i]; - switch (cfg->attri) { - case SENSING_SENSOR_ATTRIBUTE_INTERVAL: - ret |= get_interval(handle, &cfg->interval); - break; - - case SENSING_SENSOR_ATTRIBUTE_SENSITIVITY: - ret |= get_sensitivity(handle, cfg->data_field, &cfg->sensitivity); - break; - - case SENSING_SENSOR_ATTRIBUTE_LATENCY: - break; - - default: - ret = -EINVAL; - LOG_ERR("invalid config attribute:%d\n", cfg->attri); - break; - } - } - - return ret; -} - -const struct sensing_sensor_info *sensing_get_sensor_info(sensing_sensor_handle_t handle) -{ - return get_sensor_info(handle); -} diff --git a/subsys/sensing/sensing_sensor.c b/subsys/sensing/sensing_sensor.c deleted file mode 100644 index c305cbb35c4fac..00000000000000 --- a/subsys/sensing/sensing_sensor.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2023 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include - -#include -LOG_MODULE_DECLARE(sensing, CONFIG_SENSING_LOG_LEVEL); - -int sensing_sensor_notify_data_ready(const struct device *dev) -{ - return -ENOTSUP; -} - -int sensing_sensor_set_data_ready(const struct device *dev, bool data_ready) -{ - return -ENOTSUP; -} - -int sensing_sensor_post_data(const struct device *dev, void *buf, int size) -{ - return -ENOTSUP; -} diff --git a/subsys/sensing/sensor/phy_3d_sensor/CMakeLists.txt b/subsys/sensing/sensor/phy_3d_sensor/CMakeLists.txt deleted file mode 100644 index 69f0b70637c7c3..00000000000000 --- a/subsys/sensing/sensor/phy_3d_sensor/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library_sources(phy_3d_sensor.c) diff --git a/subsys/sensing/sensor/phy_3d_sensor/Kconfig b/subsys/sensing/sensor/phy_3d_sensor/Kconfig deleted file mode 100644 index 3e8ca66bcb0ef4..00000000000000 --- a/subsys/sensing/sensor/phy_3d_sensor/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2023 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -config SENSING_SENSOR_PHY_3D_SENSOR - bool "sensing subsystem physical 3d sensors(accel, gyro, mag)" - default y - depends on DT_HAS_ZEPHYR_SENSING_PHY_3D_SENSOR_ENABLED - help - Enable sensing subsystem physical 3d sensors(accel, gyro, mag). diff --git a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c deleted file mode 100644 index 6ee2131bc3bdb0..00000000000000 --- a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2023 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT zephyr_sensing_phy_3d_sensor - -#include -#include -#include -#include -#include -#include -#include - -#include "phy_3d_sensor.h" - -LOG_MODULE_REGISTER(phy_3d_sensor, CONFIG_SENSING_LOG_LEVEL); - -static int phy_3d_sensor_init(const struct device *dev, - const struct sensing_sensor_info *info, - const sensing_sensor_handle_t *reporter_handles, - int reporters_count) -{ - return 0; -} - -static int phy_3d_sensor_deinit(const struct device *dev) -{ - return 0; -} - -static int phy_3d_sensor_read_sample(const struct device *dev, - void *buf, int size) -{ - return 0; -} - -static int phy_3d_sensor_sensitivity_test(const struct device *dev, - int index, uint32_t sensitivity, - void *last_sample_buf, int last_sample_size, - void *current_sample_buf, int current_sample_size) -{ - return 0; -} - -static int phy_3d_sensor_set_interval(const struct device *dev, uint32_t value) -{ - return 0; -} - -static int phy_3d_sensor_get_interval(const struct device *dev, - uint32_t *value) -{ - return 0; -} - -static int phy_3d_sensor_set_sensitivity(const struct device *dev, - int index, uint32_t value) -{ - return 0; -} - -static int phy_3d_sensor_get_sensitivity(const struct device *dev, - int index, uint32_t *value) -{ - return 0; -} - -static const struct sensing_sensor_api phy_3d_sensor_api = { - .init = phy_3d_sensor_init, - .deinit = phy_3d_sensor_deinit, - .set_interval = phy_3d_sensor_set_interval, - .get_interval = phy_3d_sensor_get_interval, - .set_sensitivity = phy_3d_sensor_set_sensitivity, - .get_sensitivity = phy_3d_sensor_get_sensitivity, - .read_sample = phy_3d_sensor_read_sample, - .sensitivity_test = phy_3d_sensor_sensitivity_test, -}; - -static const struct sensing_sensor_register_info phy_3d_sensor_reg = { - .flags = SENSING_SENSOR_FLAG_REPORT_ON_CHANGE, - .sample_size = sizeof(struct sensing_sensor_value_3d_q31), - .sensitivity_count = PHY_3D_SENSOR_CHANNEL_NUM, - .version.value = SENSING_SENSOR_VERSION(0, 8, 0, 0), -}; - -#define SENSING_PHY_3D_SENSOR_DT_DEFINE(_inst) \ - static struct phy_3d_sensor_context _CONCAT(ctx, _inst) = { \ - .hw_dev = DEVICE_DT_GET( \ - DT_PHANDLE(DT_DRV_INST(_inst), \ - underlying_device)), \ - .sensor_type = DT_PROP(DT_DRV_INST(_inst), sensor_type),\ - }; \ - SENSING_SENSOR_DT_DEFINE(DT_DRV_INST(_inst), \ - &phy_3d_sensor_reg, &_CONCAT(ctx, _inst), \ - &phy_3d_sensor_api); - -DT_INST_FOREACH_STATUS_OKAY(SENSING_PHY_3D_SENSOR_DT_DEFINE); diff --git a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h deleted file mode 100644 index 966a6f088c33b9..00000000000000 --- a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_SPHY_3D_SENSOR_H_ -#define ZEPHYR_INCLUDE_SPHY_3D_SENSOR_H_ - -#include - -#define PHY_3D_SENSOR_CHANNEL_NUM 3 - -struct phy_3d_sensor_context { - const struct device *dev; - const struct device *hw_dev; - const int32_t sensor_type; -}; - -#endif diff --git a/subsys/sensing/sensor_mgmt.c b/subsys/sensing/sensor_mgmt.c deleted file mode 100644 index 9ecde551a02a5c..00000000000000 --- a/subsys/sensing/sensor_mgmt.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (c) 2023 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "sensor_mgmt.h" - -#define DT_DRV_COMPAT zephyr_sensing - -#define SENSING_SENSOR_NUM (sizeof((int []){ DT_FOREACH_CHILD_STATUS_OKAY_SEP( \ - DT_DRV_INST(0), DT_NODE_EXISTS, (,))}) / sizeof(int)) - -BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, - "only one 'zephyr_sensing' compatible node may be present"); - -LOG_MODULE_REGISTER(sensing, CONFIG_SENSING_LOG_LEVEL); - -DT_FOREACH_CHILD_STATUS_OKAY(DT_DRV_INST(0), SENSING_SENSOR_INFO_DEFINE) -DT_FOREACH_CHILD_STATUS_OKAY(DT_DRV_INST(0), SENSING_SENSOR_DEFINE) - - -/** - * @struct sensing_context - * @brief sensing subsystem context to include global variables - */ -struct sensing_context { - bool sensing_initialized; - int sensor_num; - struct sensing_sensor *sensors[SENSING_SENSOR_NUM]; -}; - -static struct sensing_context sensing_ctx = { - .sensor_num = SENSING_SENSOR_NUM, -}; - - -static int set_sensor_state(struct sensing_sensor *sensor, enum sensing_sensor_state state) -{ - __ASSERT(sensor, "set sensor state, sensing_sensor is NULL"); - - sensor->state = state; - - return 0; -} - -static void init_connection(struct sensing_connection *conn, - struct sensing_sensor *source, - struct sensing_sensor *sink) -{ - __ASSERT(conn, "init each connection, invalid connection"); - - conn->source = source; - conn->sink = sink; - conn->interval = 0; - memset(conn->sensitivity, 0x00, sizeof(conn->sensitivity)); - /* link connection to its reporter's client_list */ - sys_slist_append(&source->client_list, &conn->snode); -} - -static int init_sensor(struct sensing_sensor *sensor, int conns_num) -{ - const struct sensing_sensor_api *sensor_api; - struct sensing_sensor *reporter; - struct sensing_connection *conn; - void *tmp_conns[conns_num]; - int i; - - __ASSERT(sensor && sensor->dev, "init sensor, sensor or sensor device is NULL"); - sensor_api = sensor->dev->api; - __ASSERT(sensor_api, "init sensor, sensor device sensor_api is NULL"); - - if (sensor->data_buf == NULL) { - LOG_ERR("sensor:%s memory alloc failed", sensor->dev->name); - return -ENOMEM; - } - /* physical sensor has no reporters, conns_num is 0 */ - if (conns_num == 0) { - sensor->conns = NULL; - } - - for (i = 0; i < conns_num; i++) { - conn = &sensor->conns[i]; - reporter = get_reporter_sensor(sensor, i); - __ASSERT(reporter, "sensor's reporter should not be NULL"); - - init_connection(conn, reporter, sensor); - - LOG_DBG("init sensor, reporter:%s, client:%s, connection:%d", - reporter->dev->name, sensor->dev->name, i); - - tmp_conns[i] = conn; - } - - /* physical sensor is working at polling mode by default, - * virtual sensor working mode is inherited from its reporter - */ - if (is_phy_sensor(sensor)) { - sensor->mode = SENSOR_TRIGGER_MODE_POLLING; - } - - return sensor_api->init(sensor->dev, sensor->info, tmp_conns, conns_num); -} - -/* create struct sensing_sensor *sensor according to sensor device tree */ -static int pre_init_sensor(struct sensing_sensor *sensor) -{ - struct sensing_sensor_ctx *sensor_ctx; - uint16_t sample_size, total_size; - uint16_t conn_sample_size = 0; - int i = 0; - void *tmp_data; - - __ASSERT(sensor && sensor->dev, "sensor or sensor dev is invalid"); - sensor_ctx = sensor->dev->data; - __ASSERT(sensor_ctx, "sensing sensor context is invalid"); - - sample_size = sensor_ctx->register_info->sample_size; - for (i = 0; i < sensor->reporter_num; i++) { - conn_sample_size += get_reporter_sample_size(sensor, i); - } - - /* total memory to be allocated for a sensor according to sensor device tree: - * 1) sample data point to struct sensing_sensor->data_buf - * 2) size of struct sensing_connection* for sensor connection to its reporter - * 3) reporter sample size to be stored in connection data - */ - total_size = sample_size + sensor->reporter_num * sizeof(*sensor->conns) + - conn_sample_size; - - /* total size for different sensor maybe different, for example: - * there's no reporter for physical sensor, so no connection memory is needed - * reporter num of each virtual sensor may also different, so connection memory is also - * varied, so here malloc is a must for different sensor. - */ - tmp_data = malloc(total_size); - if (!tmp_data) { - LOG_ERR("malloc memory for sensing_sensor error"); - return -ENOMEM; - } - sensor->sample_size = sample_size; - sensor->data_buf = tmp_data; - sensor->conns = (struct sensing_connection *)((uint8_t *)sensor->data_buf + sample_size); - - tmp_data = sensor->conns + sensor->reporter_num; - for (i = 0; i < sensor->reporter_num; i++) { - sensor->conns[i].data = tmp_data; - tmp_data = (uint8_t *)tmp_data + get_reporter_sample_size(sensor, i); - } - - if (tmp_data != ((uint8_t *)sensor->data_buf + total_size)) { - LOG_ERR("sensor memory assign error, data_buf:%p, tmp_data:%p, size:%d", - sensor->data_buf, tmp_data, total_size); - free(sensor->data_buf); - sensor->data_buf = NULL; - return -EINVAL; - } - - LOG_INF("pre init sensor, sensor:%s, min_ri:%d(us)", - sensor->dev->name, sensor->info->minimal_interval); - - sensor->interval = 0; - sensor->sensitivity_count = sensor_ctx->register_info->sensitivity_count; - __ASSERT(sensor->sensitivity_count <= CONFIG_SENSING_MAX_SENSITIVITY_COUNT, - "sensitivity count:%d should not exceed MAX_SENSITIVITY_COUNT", - sensor->sensitivity_count); - memset(sensor->sensitivity, 0x00, sizeof(sensor->sensitivity)); - - sys_slist_init(&sensor->client_list); - - sensor_ctx->priv_ptr = sensor; - - return 0; -} - -static int sensing_init(void) -{ - struct sensing_context *ctx = &sensing_ctx; - struct sensing_sensor *sensor; - enum sensing_sensor_state state; - int ret = 0; - int i = 0; - - LOG_INF("sensing init begin..."); - - if (ctx->sensing_initialized) { - LOG_INF("sensing is already initialized"); - return 0; - } - - if (ctx->sensor_num == 0) { - LOG_WRN("no sensor created by device tree yet"); - return 0; - } - - STRUCT_SECTION_FOREACH(sensing_sensor, tmp_sensor) { - ret = pre_init_sensor(tmp_sensor); - if (ret) { - LOG_ERR("sensing init, pre init sensor error"); - } - ctx->sensors[i++] = tmp_sensor; - } - - for_each_sensor(ctx, i, sensor) { - ret = init_sensor(sensor, sensor->reporter_num); - if (ret) { - LOG_ERR("sensor:%s initial error", sensor->dev->name); - } - state = (ret ? SENSING_SENSOR_STATE_OFFLINE : SENSING_SENSOR_STATE_READY); - ret = set_sensor_state(sensor, state); - if (ret) { - LOG_ERR("set sensor:%s state:%d error", sensor->dev->name, state); - } - LOG_INF("sensing init, sensor:%s state:%d", sensor->dev->name, sensor->state); - } - - return ret; -} - -int open_sensor(struct sensing_sensor *sensor, struct sensing_connection **conn) -{ - struct sensing_connection *tmp_conn; - - if (sensor->state != SENSING_SENSOR_STATE_READY) - return -EINVAL; - - /* allocate struct sensing_connection *conn and conn data for application client */ - tmp_conn = malloc(sizeof(*tmp_conn) + sensor->sample_size); - if (!tmp_conn) { - LOG_ERR("malloc memory for struct sensing_connection error"); - return -ENOMEM; - } - tmp_conn->data = (uint8_t *)tmp_conn + sizeof(*tmp_conn); - - /* create connection from sensor to application(client = NULL) */ - init_connection(tmp_conn, sensor, NULL); - - *conn = tmp_conn; - - return 0; -} - -int close_sensor(struct sensing_connection **conn) -{ - struct sensing_connection *tmp_conn = *conn; - - if (tmp_conn == NULL) { - LOG_ERR("connection should not be NULL"); - return -EINVAL; - } - - __ASSERT(!tmp_conn->sink, "sensor derived from device tree cannot be closed"); - - sys_slist_find_and_remove(&tmp_conn->source->client_list, &tmp_conn->snode); - - *conn = NULL; - free(*conn); - - return 0; -} - -int sensing_register_callback(struct sensing_connection *conn, - const struct sensing_callback_list *cb_list) -{ - if (conn == NULL) { - LOG_ERR("register sensing callback list, connection not be NULL"); - return -ENODEV; - } - - __ASSERT(!conn->sink, "only connection to application could register sensing callback"); - - if (cb_list == NULL) { - LOG_ERR("callback should not be NULL"); - return -ENODEV; - } - conn->data_evt_cb = cb_list->on_data_event; - - return 0; -} - -int set_interval(struct sensing_connection *conn, uint32_t interval) -{ - return -ENOTSUP; -} - -int get_interval(struct sensing_connection *conn, uint32_t *interval) -{ - return -ENOTSUP; -} - -int set_sensitivity(struct sensing_connection *conn, int8_t index, uint32_t sensitivity) -{ - return -ENOTSUP; -} - -int get_sensitivity(struct sensing_connection *conn, int8_t index, uint32_t *sensitivity) -{ - return -ENOTSUP; -} - -int sensing_get_sensors(int *sensor_nums, const struct sensing_sensor_info **info) -{ - if (info == NULL) { - LOG_ERR("sensing_sensor_info should not be NULL"); - return -ENODEV; - } - - STRUCT_SECTION_COUNT(sensing_sensor_info, sensor_nums); - - STRUCT_SECTION_GET(sensing_sensor_info, 0, info); - - return 0; -} - - -SYS_INIT(sensing_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/subsys/sensing/sensor_mgmt.h b/subsys/sensing/sensor_mgmt.h deleted file mode 100644 index 38219305304d6e..00000000000000 --- a/subsys/sensing/sensor_mgmt.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2023 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef SENSOR_MGMT_H_ -#define SENSOR_MGMT_H_ - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define PHANDLE_DEVICE_BY_IDX(idx, node, prop) \ - DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node, prop, idx)) - -#define PHANDLE_DEVICE_LIST(node, prop) \ -{ \ - LISTIFY(DT_PROP_LEN_OR(node, prop, 0), \ - PHANDLE_DEVICE_BY_IDX, \ - (,), \ - node, \ - prop) \ -} - -#define SENSING_SENSOR_INFO_NAME(node) \ - _CONCAT(__sensing_sensor_info_, DEVICE_DT_NAME_GET(node)) - -#define SENSING_SENSOR_INFO_DEFINE(node) \ - const static STRUCT_SECTION_ITERABLE(sensing_sensor_info, \ - SENSING_SENSOR_INFO_NAME(node)) = { \ - .type = DT_PROP(node, sensor_type), \ - .name = DT_NODE_FULL_NAME(node), \ - .friendly_name = DT_PROP(node, friendly_name), \ - .vendor = DT_NODE_VENDOR_OR(node, NULL), \ - .model = DT_NODE_MODEL_OR(node, NULL), \ - .minimal_interval = DT_PROP(node, minimal_interval), \ - }; - -#define SENSING_SENSOR_NAME(node) \ - _CONCAT(__sensing_sensor_, DEVICE_DT_NAME_GET(node)) - -#define SENSING_SENSOR_DEFINE(node) \ - static STRUCT_SECTION_ITERABLE(sensing_sensor, \ - SENSING_SENSOR_NAME(node)) = { \ - .dev = DEVICE_DT_GET(node), \ - .info = &SENSING_SENSOR_INFO_NAME(node), \ - .reporter_num = DT_PROP_LEN_OR(node, reporters, 0), \ - .reporters = PHANDLE_DEVICE_LIST(node, reporters), \ - }; - -#define for_each_sensor(ctx, i, sensor) \ - for (i = 0; i < ctx->sensor_num && (sensor = ctx->sensors[i]) != NULL; i++) - -enum sensor_trigger_mode { - SENSOR_TRIGGER_MODE_POLLING = 1, - SENSOR_TRIGGER_MODE_DATA_READY = 2, -}; - -/** - * @struct sensing_connection information - * @brief sensing_connection indicates connection from reporter(source) to client(sink) - */ -struct sensing_connection { - struct sensing_sensor *source; - struct sensing_sensor *sink; - /* interval and sensitivity set from client(sink) to reporter(source) */ - uint32_t interval; - int sensitivity[CONFIG_SENSING_MAX_SENSITIVITY_COUNT]; - /* copy sensor data to connection data buf from reporter */ - void *data; - /* client(sink) next consume time */ - sys_snode_t snode; - /* post data to application */ - sensing_data_event_t data_evt_cb; -}; - -/** - * @struct sensing_sensor - * @brief Internal sensor instance data structure. - * - * Each sensor instance will have its unique data structure for storing all - * it's related information. - * - * Sensor management will enumerate all these instance data structures, - * build report relationship model base on them, etc. - */ -struct sensing_sensor { - const struct device *dev; - const struct sensing_sensor_info *info; - const uint16_t reporter_num; - sys_slist_t client_list; - uint32_t interval; - uint8_t sensitivity_count; - int sensitivity[CONFIG_SENSING_MAX_SENSITIVITY_COUNT]; - enum sensing_sensor_state state; - enum sensor_trigger_mode mode; - /* runtime info */ - uint16_t sample_size; - void *data_buf; - struct sensing_connection *conns; - const struct device *reporters[]; -}; - -int open_sensor(struct sensing_sensor *sensor, struct sensing_connection **conn); -int close_sensor(struct sensing_connection **conn); -int sensing_register_callback(struct sensing_connection *conn, - const struct sensing_callback_list *cb_list); -int set_interval(struct sensing_connection *conn, uint32_t interval); -int get_interval(struct sensing_connection *con, uint32_t *sensitivity); -int set_sensitivity(struct sensing_connection *conn, int8_t index, uint32_t interval); -int get_sensitivity(struct sensing_connection *con, int8_t index, uint32_t *sensitivity); - - -static inline bool is_phy_sensor(struct sensing_sensor *sensor) -{ - return sensor->reporter_num == 0; -} - -static inline uint16_t get_reporter_sample_size(const struct sensing_sensor *sensor, int i) -{ - __ASSERT(i < sensor->reporter_num, "dt index should less than reporter num"); - - return ((struct sensing_sensor_ctx *) - sensor->reporters[i]->data)->register_info->sample_size; -} - -static inline struct sensing_sensor *get_sensor_by_dev(const struct device *dev) -{ - return dev ? - (struct sensing_sensor *)((struct sensing_sensor_ctx *)dev->data)->priv_ptr : NULL; -} - -static inline struct sensing_sensor *get_reporter_sensor(struct sensing_sensor *sensor, int index) -{ - if (!sensor || index >= sensor->reporter_num) { - return NULL; - } - - return get_sensor_by_dev(sensor->reporters[index]); -} - -static inline const struct sensing_sensor_info *get_sensor_info(struct sensing_connection *conn) -{ - __ASSERT(conn, "get sensor info, connection not be NULL"); - - __ASSERT(conn->source, "get sensor info, sensing_sensor is NULL"); - - return conn->source->info; -} - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - - -#endif /* SENSOR_MGMT_H_ */ diff --git a/subsys/sensing/src/sensor_info.c b/subsys/sensing/src/sensor_info.c new file mode 100644 index 00000000000000..3af62d40dbdcba --- /dev/null +++ b/subsys/sensing/src/sensor_info.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **info) +{ + STRUCT_SECTION_COUNT(sensing_sensor_info, num_sensors); + *info = STRUCT_SECTION_START(sensing_sensor_info); + return 0; +} diff --git a/subsys/sensing/src/sensor_pipe.c b/subsys/sensing/src/sensor_pipe.c new file mode 100644 index 00000000000000..fb1a1b9e797063 --- /dev/null +++ b/subsys/sensing/src/sensor_pipe.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define DT_DRV_COMPAT zephyr_sensing_pipe + +static const struct sensor_driver_api sensor_pipe_api = { + .attr_set = NULL, + .attr_get = NULL, + .get_decoder = NULL, + .submit = NULL, +}; + +static int sensing_sensor_pipe_init(const struct device *dev) +{ + return 0; +} + +#define SENSING_PIPE_INIT(inst) \ + SENSING_SENSOR_DT_INST_DEFINE(inst, sensing_sensor_pipe_init, NULL, NULL, NULL, \ + APPLICATION, 10, &sensor_pipe_api); + +DT_INST_FOREACH_STATUS_OKAY(SENSING_PIPE_INIT) diff --git a/tests/subsys/sensing/list/CMakeLists.txt b/tests/subsys/sensing/list/CMakeLists.txt new file mode 100644 index 00000000000000..1b34e474c14b0c --- /dev/null +++ b/tests/subsys/sensing/list/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(device) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/sensing/list/boards/native_posix.overlay b/tests/subsys/sensing/list/boards/native_posix.overlay new file mode 100644 index 00000000000000..6884708a8e0311 --- /dev/null +++ b/tests/subsys/sensing/list/boards/native_posix.overlay @@ -0,0 +1,23 @@ +/* Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + + #include + +/ { + accelgyro: accelgyro { + compatible = "zephyr,sensing-pipe"; + status = "okay"; + dev = <&icm42688>; + sensor-types = ; + }; +}; + +&spi0 { + icm42688: icm42688@3 { + compatible = "invensense,icm42688"; + int-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + spi-max-frequency = <50000000>; + reg = <3>; + }; +}; diff --git a/tests/subsys/sensing/list/prj.conf b/tests/subsys/sensing/list/prj.conf new file mode 100644 index 00000000000000..0e0e881d69886a --- /dev/null +++ b/tests/subsys/sensing/list/prj.conf @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y + +# Enable GPIO +CONFIG_GPIO=y + +# Enable sensors +CONFIG_SENSOR=y +CONFIG_SENSING=y + +# Enable emulation +CONFIG_EMUL=y diff --git a/tests/subsys/sensing/list/src/main.c b/tests/subsys/sensing/list/src/main.c new file mode 100644 index 00000000000000..0d2c1bbb810839 --- /dev/null +++ b/tests/subsys/sensing/list/src/main.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include + +ZTEST_SUITE(sensing, NULL, NULL, NULL, NULL, NULL); + +ZTEST(sensing, test_list_sensors) +{ + int num_sensors; + const struct sensing_sensor_info *sensors; + const struct sensor_info *expected_info = &SENSOR_INFO_DT_NAME(DT_NODELABEL(icm42688)); + + zassert_ok(sensing_get_sensors(&num_sensors, &sensors)); + zassert_equal(2, num_sensors, "num_sensors=%d", num_sensors); + + zassert_equal_ptr(expected_info, sensors[0].info); + zassert_equal_ptr(expected_info, sensors[1].info); + + zassert_true(sensors[0].type == SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D || + sensors[0].type == SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D); + zassert_true(sensors[1].type == SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D || + sensors[1].type == SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D); + zassert_not_equal(sensors[0].type, sensors[1].type); +} + +ZTEST(sensing, test_get_single_node) +{ + const struct sensor_info *expected_info = &SENSOR_INFO_DT_NAME(DT_NODELABEL(icm42688)); + const struct sensing_sensor_info *info = SENSING_SENSOR_INFO_GET( + DT_NODELABEL(accelgyro), SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D); + + zassert_equal_ptr(expected_info, info->info); + zassert_equal(SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D, info->type); + + info = SENSING_SENSOR_INFO_GET(DT_NODELABEL(accelgyro), + SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D); + + zassert_equal_ptr(expected_info, info->info); + zassert_equal(SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D, info->type); +} diff --git a/tests/subsys/sensing/list/testcase.yaml b/tests/subsys/sensing/list/testcase.yaml new file mode 100644 index 00000000000000..2f9d013e2a2f4e --- /dev/null +++ b/tests/subsys/sensing/list/testcase.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +tests: + subsys.sensing.list: + tags: + - sensor + - subsys + platform_allow: native_posix From 87209f31a6ddd34c4a28dec0ac1a813f94b78cb4 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Tue, 27 Jun 2023 13:20:56 -0600 Subject: [PATCH 04/10] Add open/close support --- include/zephyr/sensing/sensing.h | 24 ++------- include/zephyr/sys/util.h | 18 +++++++ subsys/sensing/CMakeLists.txt | 1 + subsys/sensing/Kconfig | 11 +++++ subsys/sensing/src/sensor_connections.c | 49 +++++++++++++++++++ .../subsys/sensing/{list => }/CMakeLists.txt | 0 .../{list => }/boards/native_posix.overlay | 0 tests/subsys/sensing/{list => }/prj.conf | 0 tests/subsys/sensing/src/main.c | 16 ++++++ tests/subsys/sensing/src/test_connections.c | 34 +++++++++++++ .../src/main.c => src/test_list_sensors.c} | 4 -- tests/subsys/sensing/{list => }/testcase.yaml | 0 12 files changed, 132 insertions(+), 25 deletions(-) create mode 100644 subsys/sensing/src/sensor_connections.c rename tests/subsys/sensing/{list => }/CMakeLists.txt (100%) rename tests/subsys/sensing/{list => }/boards/native_posix.overlay (100%) rename tests/subsys/sensing/{list => }/prj.conf (100%) create mode 100644 tests/subsys/sensing/src/main.c create mode 100644 tests/subsys/sensing/src/test_connections.c rename tests/subsys/sensing/{list/src/main.c => src/test_list_sensors.c} (95%) rename tests/subsys/sensing/{list => }/testcase.yaml (100%) diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index c80afe59936a02..502575611f519e 100644 --- a/include/zephyr/sensing/sensing.h +++ b/include/zephyr/sensing/sensing.h @@ -160,26 +160,6 @@ int sensing_open_sensor( const struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle); -/** - * @brief Open sensor instance by device. - * - * Application clients use it to open a sensor instance and get its handle. - * Support multiple Application clients for open same sensor instance, - * in this case, the returned handle will different for different clients. - * meanwhile, also register sensing callback list. - * - * @param dev pointer device get from device tree. - * - * @param cb_list callback list to be registered to sensing. - * - * @param *handle The opened instance handle, if failed will be set to NULL. - * - * @return 0 on success or negative error value on failure. - */ -int sensing_open_sensor_by_dt( - const struct device *dev, const struct sensing_callback_list *cb_list, - sensing_sensor_handle_t *handle); - /** * @brief Close sensor instance. * @@ -188,7 +168,7 @@ int sensing_open_sensor_by_dt( * @return 0 on success or negative error value on failure. */ int sensing_close_sensor( - sensing_sensor_handle_t *handle); + sensing_sensor_handle_t handle); /** * @brief Get sensor information from sensor instance handle. @@ -200,6 +180,8 @@ int sensing_close_sensor( const struct sensing_sensor_info *sensing_get_sensor_info( sensing_sensor_handle_t handle); +__test_only void sensing_reset_connections(void); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/sys/util.h b/include/zephyr/sys/util.h index 9cd47079820294..0a05e2a3e6d08f 100644 --- a/include/zephyr/sys/util.h +++ b/include/zephyr/sys/util.h @@ -58,6 +58,24 @@ extern "C" { /** Number of bits in a long long int. */ #define BITS_PER_LONG_LONG (__CHAR_BIT__ * __SIZEOF_LONG_LONG__) +/* + * Attribute for generating an error if a function is used. + * + * Clang does not have a function attribute to do this. Rely on linker + * errors. :( + */ +#ifdef __clang__ +#define __error(msg) __attribute__((section("/DISCARD/"))) +#else +#define __error(msg) __attribute__((error(msg))) +#endif + +#ifdef CONFIG_TEST +#define __test_only +#else +#define __test_only __error("This function should only be used by tests") +#endif + /** * @brief Create a contiguous bitmask starting at bit position @p l * and ending at position @p h. diff --git a/subsys/sensing/CMakeLists.txt b/subsys/sensing/CMakeLists.txt index a401e0a8372c04..1cf869cff59634 100644 --- a/subsys/sensing/CMakeLists.txt +++ b/subsys/sensing/CMakeLists.txt @@ -4,4 +4,5 @@ zephyr_library() zephyr_library_sources( src/sensor_info.c src/sensor_pipe.c + src/sensor_connections.c ) diff --git a/subsys/sensing/Kconfig b/subsys/sensing/Kconfig index dff3b430b69bb2..4476555c5d115f 100644 --- a/subsys/sensing/Kconfig +++ b/subsys/sensing/Kconfig @@ -5,6 +5,7 @@ config SENSING bool "Sensing Subsystem" select DSP select SENSOR_INFO + select SYS_MEM_BLOCKS help Enable Sensing Subsystem. @@ -14,4 +15,14 @@ module = SENSING module-str = sensing source "subsys/logging/Kconfig.template.log_config" +config SENSING_MAX_CONNECTIONS + int "Maximum number of simultaneous open connections" + default 10 + help + Every client of the subsystem is required to open a connection to each + sensor that they want to get data for. This value controls the maximum + number of concurrent connections (note that a connection can be to the + same sensor by different clients or the same client to different + sensors). + endif # SENSING diff --git a/subsys/sensing/src/sensor_connections.c b/subsys/sensing/src/sensor_connections.c new file mode 100644 index 00000000000000..2bc9f7eb12f773 --- /dev/null +++ b/subsys/sensing/src/sensor_connections.c @@ -0,0 +1,49 @@ + +#include +#include + +struct sensing_connection { + const struct sensing_callback_list *cb_list; +} __packed __aligned(4); + +static uint8_t __aligned(4) + connection_pool[sizeof(struct sensing_connection) * CONFIG_SENSING_MAX_CONNECTIONS]; +SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(connection_allocator, sizeof(struct sensing_connection), + CONFIG_SENSING_MAX_CONNECTIONS, connection_pool); + +int sensing_open_sensor(const struct sensing_sensor_info *info, + const struct sensing_callback_list *cb_list, + sensing_sensor_handle_t *handle) +{ + struct sensing_connection *connection; + int rc; + + __ASSERT_NO_MSG(info != NULL); + __ASSERT_NO_MSG(cb_list != NULL); + __ASSERT_NO_MSG(handle != NULL); + + rc = sys_mem_blocks_alloc(&connection_allocator, 1, (void**)&connection); + + if (rc != 0) { + return rc; + } + + connection->cb_list = cb_list; + *handle = connection; + return 0; +} + +int sensing_close_sensor(sensing_sensor_handle_t handle) +{ + return sys_mem_blocks_free(&connection_allocator, 1, &handle); +} + +void sensing_reset_connections(void) +{ + uint8_t *ptr = connection_pool; + + while (ptr < connection_pool + sizeof(connection_pool)) { + sys_mem_blocks_free(&connection_allocator, 1, (void**)&ptr); + ptr += sizeof(struct sensing_connection); + } +} diff --git a/tests/subsys/sensing/list/CMakeLists.txt b/tests/subsys/sensing/CMakeLists.txt similarity index 100% rename from tests/subsys/sensing/list/CMakeLists.txt rename to tests/subsys/sensing/CMakeLists.txt diff --git a/tests/subsys/sensing/list/boards/native_posix.overlay b/tests/subsys/sensing/boards/native_posix.overlay similarity index 100% rename from tests/subsys/sensing/list/boards/native_posix.overlay rename to tests/subsys/sensing/boards/native_posix.overlay diff --git a/tests/subsys/sensing/list/prj.conf b/tests/subsys/sensing/prj.conf similarity index 100% rename from tests/subsys/sensing/list/prj.conf rename to tests/subsys/sensing/prj.conf diff --git a/tests/subsys/sensing/src/main.c b/tests/subsys/sensing/src/main.c new file mode 100644 index 00000000000000..f37fd2432f8b59 --- /dev/null +++ b/tests/subsys/sensing/src/main.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +static void sensing_after(void *f) +{ + ARG_UNUSED(f); + + sensing_reset_connections(); +} + +ZTEST_SUITE(sensing, NULL, NULL, NULL, sensing_after, NULL); diff --git a/tests/subsys/sensing/src/test_connections.c b/tests/subsys/sensing/src/test_connections.c new file mode 100644 index 00000000000000..264280f050b41d --- /dev/null +++ b/tests/subsys/sensing/src/test_connections.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +ZTEST(sensing, test_open_connections_limit) +{ + const struct sensing_sensor_info *sensor = SENSING_SENSOR_INFO_GET( + DT_NODELABEL(accelgyro), SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D); + const struct sensing_callback_list cb_list; + sensing_sensor_handle_t handles[CONFIG_SENSING_MAX_CONNECTIONS + 1]; + + zassert_not_null(sensor); + + /* Allocate all the connection */ + for (int i = 0; i < CONFIG_SENSING_MAX_CONNECTIONS; ++i) { + zassert_ok(sensing_open_sensor(sensor, &cb_list, &handles[i])); + } + + /* Try to over allocate */ + zassert_equal(-ENOMEM, sensing_open_sensor(sensor, &cb_list, + &handles[CONFIG_SENSING_MAX_CONNECTIONS])); + + /* Free one connection */ + zassert_ok(sensing_close_sensor(handles[0])); + + /* Allocate one */ + zassert_ok(sensing_open_sensor(sensor, &cb_list, &handles[CONFIG_SENSING_MAX_CONNECTIONS])); +} diff --git a/tests/subsys/sensing/list/src/main.c b/tests/subsys/sensing/src/test_list_sensors.c similarity index 95% rename from tests/subsys/sensing/list/src/main.c rename to tests/subsys/sensing/src/test_list_sensors.c index 0d2c1bbb810839..345971df56e68b 100644 --- a/tests/subsys/sensing/list/src/main.c +++ b/tests/subsys/sensing/src/test_list_sensors.c @@ -8,10 +8,6 @@ #include #include -#include - -ZTEST_SUITE(sensing, NULL, NULL, NULL, NULL, NULL); - ZTEST(sensing, test_list_sensors) { int num_sensors; diff --git a/tests/subsys/sensing/list/testcase.yaml b/tests/subsys/sensing/testcase.yaml similarity index 100% rename from tests/subsys/sensing/list/testcase.yaml rename to tests/subsys/sensing/testcase.yaml From c4de37d3a6ad75f93354a09a3347619d0db7d013 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Wed, 28 Jun 2023 00:15:27 -0600 Subject: [PATCH 05/10] Implement arbitration --- .gitignore | 1 + drivers/sensor/icm42688/icm42688_emul.c | 3 + include/zephyr/sensing/sensing.h | 75 ++++++------- include/zephyr/sensing/sensor.h | 1 + subsys/sensing/CMakeLists.txt | 2 + .../include/sensing/internal/sensing.h | 36 ++++++ subsys/sensing/src/sensor_arbitrate.c | 96 ++++++++++++++++ subsys/sensing/src/sensor_connections.c | 105 +++++++++++++++--- subsys/sensing/src/sensor_info.c | 3 + subsys/sensing/src/sensor_pipe.c | 26 ++++- tests/subsys/sensing/CMakeLists.txt | 8 +- tests/subsys/sensing/prj.conf | 2 + tests/subsys/sensing/src/test_arbitration.c | 71 ++++++++++++ tests/subsys/sensing/src/test_connections.c | 16 ++- 14 files changed, 387 insertions(+), 58 deletions(-) create mode 100644 subsys/sensing/include/sensing/internal/sensing.h create mode 100644 subsys/sensing/src/sensor_arbitrate.c create mode 100644 tests/subsys/sensing/src/test_arbitration.c diff --git a/.gitignore b/.gitignore index 16e54c466283d7..5944f735f791a8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ .\#* \#*\# build*/ +/build* !doc/build/ !scripts/build !tests/drivers/build_all diff --git a/drivers/sensor/icm42688/icm42688_emul.c b/drivers/sensor/icm42688/icm42688_emul.c index 5ac652c29d719a..0216e2ee84d0c4 100644 --- a/drivers/sensor/icm42688/icm42688_emul.c +++ b/drivers/sensor/icm42688/icm42688_emul.c @@ -56,6 +56,9 @@ static void icm42688_emul_handle_write(const struct emul *target, uint8_t regn, data->reg[REG_INT_STATUS] |= BIT_INT_STATUS_RESET_DONE; } break; + default: + data->reg[regn] = value; + break; } } diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index 502575611f519e..7892b9f602f46f 100644 --- a/include/zephyr/sensing/sensing.h +++ b/include/zephyr/sensing/sensing.h @@ -32,7 +32,6 @@ extern "C" { #endif - /** * @struct sensing_sensor_version * @brief Sensor Version @@ -49,12 +48,9 @@ struct sensing_sensor_version { }; }; -#define SENSING_SENSOR_VERSION(_major, _minor, _hotfix, _build) \ - (FIELD_PREP(GENMASK(31, 24), _major) | \ - FIELD_PREP(GENMASK(23, 16), _minor) | \ - FIELD_PREP(GENMASK(15, 8), _hotfix) | \ - FIELD_PREP(GENMASK(7, 0), _build)) - +#define SENSING_SENSOR_VERSION(_major, _minor, _hotfix, _build) \ + (FIELD_PREP(GENMASK(31, 24), _major) | FIELD_PREP(GENMASK(23, 16), _minor) | \ + FIELD_PREP(GENMASK(15, 8), _hotfix) | FIELD_PREP(GENMASK(7, 0), _build)) /** * @brief Sensor flag indicating if this sensor is on event reporting data. @@ -62,7 +58,7 @@ struct sensing_sensor_version { * Reporting sensor data when the sensor event occurs, such as a motion detect sensor reporting * a motion or motionless detected event. */ -#define SENSING_SENSOR_FLAG_REPORT_ON_EVENT BIT(0) +#define SENSING_SENSOR_FLAG_REPORT_ON_EVENT BIT(0) /** * @brief Sensor flag indicating if this sensor is on change reporting data. @@ -71,8 +67,7 @@ struct sensing_sensor_version { * * Exclusive with \ref SENSING_SENSOR_FLAG_REPORT_ON_EVENT */ -#define SENSING_SENSOR_FLAG_REPORT_ON_CHANGE BIT(1) - +#define SENSING_SENSOR_FLAG_REPORT_ON_CHANGE BIT(1) /** * @brief Sensing subsystem sensor state. @@ -83,14 +78,12 @@ enum sensing_sensor_state { SENSING_SENSOR_STATE_OFFLINE = 1, }; - /** * @brief Define Sensing subsystem sensor handle * */ typedef void *sensing_sensor_handle_t; - /** * @brief Sensor data event receive callback. * @@ -98,9 +91,7 @@ typedef void *sensing_sensor_handle_t; * * @param buf The data buffer with sensor data. */ -typedef void (*sensing_data_event_t)( - sensing_sensor_handle_t handle, - const void *buf); +typedef void (*sensing_data_event_t)(sensing_sensor_handle_t handle, const void *buf); /** * @struct sensing_sensor_info @@ -108,7 +99,9 @@ typedef void (*sensing_data_event_t)( * */ struct sensing_sensor_info { - const struct sensor_info * info; + const struct sensor_info *info; + + const struct device *dev; /** Sensor type */ int32_t type; @@ -123,20 +116,19 @@ struct sensing_callback_list { sensing_data_event_t on_data_event; }; - - /** - * @brief Get all supported sensor instances' information. - * - * This API just returns read only information of sensor instances, pointer info will - * directly point to internal buffer, no need for caller to allocate buffer, - * no side effect to sensor instances. - * - * @param num_sensors Get number of sensor instances. - * - * @param info For receiving sensor instances' information array pointer. - * - * @return 0 on success or negative error value on failure. - */ +/** + * @brief Get all supported sensor instances' information. + * + * This API just returns read only information of sensor instances, pointer info will + * directly point to internal buffer, no need for caller to allocate buffer, + * no side effect to sensor instances. + * + * @param num_sensors Get number of sensor instances. + * + * @param info For receiving sensor instances' information array pointer. + * + * @return 0 on success or negative error value on failure. + */ int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **info); /** @@ -155,10 +147,9 @@ int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **inf * * @return 0 on success or negative error value on failure. */ -int sensing_open_sensor( - const struct sensing_sensor_info *info, - const struct sensing_callback_list *cb_list, - sensing_sensor_handle_t *handle); +int sensing_open_sensor(const struct sensing_sensor_info *info, + const struct sensing_callback_list *cb_list, + sensing_sensor_handle_t *handle); /** * @brief Close sensor instance. @@ -167,8 +158,16 @@ int sensing_open_sensor( * * @return 0 on success or negative error value on failure. */ -int sensing_close_sensor( - sensing_sensor_handle_t handle); +int sensing_close_sensor(sensing_sensor_handle_t handle); + +struct sensing_sensor_attribute { + enum sensor_attribute attribute; + q31_t value; + int8_t shift; +}; + +int sensing_set_attributes(sensing_sensor_handle_t handle, + struct sensing_sensor_attribute *attributes, size_t count); /** * @brief Get sensor information from sensor instance handle. @@ -177,8 +176,7 @@ int sensing_close_sensor( * * @return a const pointer to \ref sensing_sensor_info on success or NULL on failure. */ -const struct sensing_sensor_info *sensing_get_sensor_info( - sensing_sensor_handle_t handle); +const struct sensing_sensor_info *sensing_get_sensor_info(sensing_sensor_handle_t handle); __test_only void sensing_reset_connections(void); @@ -190,5 +188,4 @@ __test_only void sensing_reset_connections(void); * @} */ - #endif /*ZEPHYR_INCLUDE_SENSING_H_*/ diff --git a/include/zephyr/sensing/sensor.h b/include/zephyr/sensing/sensor.h index 434f9b7357403b..cd4614a8187d7d 100644 --- a/include/zephyr/sensing/sensor.h +++ b/include/zephyr/sensing/sensor.h @@ -19,6 +19,7 @@ sensing_sensor_info, \ SENSING_SENSOR_INFO_DT_NAME(node_id, DT_PROP_BY_IDX(node_id, prop, idx))) = { \ .info = &SENSOR_INFO_DT_NAME(DT_PHANDLE(node_id, dev)), \ + .dev = DEVICE_DT_GET(node_id), \ .type = DT_PROP_BY_IDX(node_id, prop, idx), \ }; diff --git a/subsys/sensing/CMakeLists.txt b/subsys/sensing/CMakeLists.txt index 1cf869cff59634..bd47b62c6a11b5 100644 --- a/subsys/sensing/CMakeLists.txt +++ b/subsys/sensing/CMakeLists.txt @@ -2,7 +2,9 @@ zephyr_library() zephyr_library_sources( + src/sensor_arbitrate.c src/sensor_info.c src/sensor_pipe.c src/sensor_connections.c ) +zephyr_library_include_directories(include) diff --git a/subsys/sensing/include/sensing/internal/sensing.h b/subsys/sensing/include/sensing/internal/sensing.h new file mode 100644 index 00000000000000..4db844cab09480 --- /dev/null +++ b/subsys/sensing/include/sensing/internal/sensing.h @@ -0,0 +1,36 @@ +// +// Created by peress on 27/06/23. +// + +#ifndef ZEPHYR_SUBSYS_SENSING_INCLUDE_SENSING_INTERNAL_SENSING_H +#define ZEPHYR_SUBSYS_SENSING_INCLUDE_SENSING_INTERNAL_SENSING_H + +#include +#include +#include + +#define __SENSING_POOL_MASK_BUNDLE_COUNT \ + (DIV_ROUND_UP(DIV_ROUND_UP(CONFIG_SENSING_MAX_CONNECTIONS, 8), sizeof(uint32_t))) + +struct sensing_connection { + const struct sensing_sensor_info *info; + const struct sensing_callback_list *cb_list; + q31_t attributes[SENSOR_ATTR_COMMON_COUNT]; + uint32_t attribute_mask; + struct { + uint8_t in_use: 1; + uint8_t reserved: 7; + } flags; +} __packed __aligned(4); + +extern struct sensing_connection_pool { + struct sensing_connection pool[CONFIG_SENSING_MAX_CONNECTIONS]; + sys_bitarray_t *bitarray; + struct k_mutex *lock; +} __sensing_connection_pool; + +BUILD_ASSERT(SENSOR_ATTR_COMMON_COUNT <= 32, "Too many sensor attributes"); + +void __sensing_arbitrate(); + +#endif // ZEPHYR_SUBSYS_SENSING_INCLUDE_SENSING_INTERNAL_SENSING_H diff --git a/subsys/sensing/src/sensor_arbitrate.c b/subsys/sensing/src/sensor_arbitrate.c new file mode 100644 index 00000000000000..feaf3c77eb201d --- /dev/null +++ b/subsys/sensing/src/sensor_arbitrate.c @@ -0,0 +1,96 @@ +// +// Created by peress on 27/06/23. +// + +#include +#include +#include + +#include "sensing/internal/sensing.h" + +LOG_MODULE_REGISTER(sensing_arbitrate, CONFIG_SENSING_LOG_LEVEL); + +static q31_t arbitrate_attribute_value(enum sensor_attribute attribute, q31_t current_value, + q31_t new_value) +{ + switch (attribute) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return MAX(current_value, new_value); + default: + return current_value; + } +} + +static void set_arbitrated_value(const struct device *dev, int32_t type, + enum sensor_attribute attribute, q31_t value) +{ + enum sensor_channel chan; + switch (type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + chan = SENSOR_CHAN_ACCEL_XYZ; + break; + case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: + chan = SENSOR_CHAN_GYRO_XYZ; + break; + default: + return; + } + + struct sensor_value val = { + .val1 = FIELD_GET(GENMASK(31, 16), value), + .val2 = (FIELD_GET(GENMASK(15, 0), value) * 1000000) / INT16_MAX, + }; + LOG_DBG("Updating attribute chan=%d, value=%d/%d", chan, val.val1, val.val2); + ((const struct sensor_driver_api *)(dev->api))->attr_set(dev, chan, attribute, &val); +} + +static int arbitrate_sensor_attribute(const struct sensing_sensor_info *info, + enum sensor_attribute attribute) +{ + const struct sensing_connection *connections = __sensing_connection_pool.pool; + int connection_count = 0; + q31_t value; + + for (int i = 0; i < CONFIG_SENSING_MAX_CONNECTIONS; ++i) { + if (connections[i].info != info || !connections[i].flags.in_use) { +// LOG_DBG("Skipping connection %p, info mismatch", (void*)&connections[i]); + continue; + } + if (FIELD_GET(BIT(attribute), connections[i].attribute_mask) == 0) { +// LOG_DBG("Skipping connection %p, attribute not set", (void*)&connections[i]); + continue; + } + if (connection_count == 0) { + /* First connection */ + value = connections[i].attributes[attribute]; + LOG_DBG("Arbitrating '%s'@%p type=%d attribute=%d", info->info->dev->name, + info->info->dev, info->type, attribute); + LOG_DBG(" First connection %p, value=0x%08x", (void*)&connections[i], value); + } else { + value = arbitrate_attribute_value(attribute, value, + connections[i].attributes[attribute]); + LOG_DBG(" Updating %p, value=0x%08x", (void*)&connections[i], value); + } + connection_count++; + } + + if (connection_count != 0) { + set_arbitrated_value(info->dev, info->type, attribute, value); + } + + return connection_count; +} + +static void arbitrate_sensor_instance(const struct sensing_sensor_info *info) +{ + for (int i = 0; i < SENSOR_ATTR_COMMON_COUNT; ++i) { + arbitrate_sensor_attribute(info, i); + } +} + +void __sensing_arbitrate(void) +{ + STRUCT_SECTION_FOREACH(sensing_sensor_info, info) { + arbitrate_sensor_instance(info); + } +} diff --git a/subsys/sensing/src/sensor_connections.c b/subsys/sensing/src/sensor_connections.c index 2bc9f7eb12f773..9d199b7891a676 100644 --- a/subsys/sensing/src/sensor_connections.c +++ b/subsys/sensing/src/sensor_connections.c @@ -1,49 +1,124 @@ +#include #include #include +#include +#include -struct sensing_connection { - const struct sensing_callback_list *cb_list; -} __packed __aligned(4); +#include "sensing/internal/sensing.h" -static uint8_t __aligned(4) - connection_pool[sizeof(struct sensing_connection) * CONFIG_SENSING_MAX_CONNECTIONS]; -SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(connection_allocator, sizeof(struct sensing_connection), - CONFIG_SENSING_MAX_CONNECTIONS, connection_pool); +LOG_MODULE_REGISTER(sensing_connect, CONFIG_SENSING_LOG_LEVEL); + +#define __HANDLE_TO_CONNECTION(name, handle) \ + struct sensing_connection *name = handle; \ + __ASSERT_NO_MSG((uintptr_t)name >= (uintptr_t)__sensing_connection_pool.pool); \ + __ASSERT_NO_MSG((uintptr_t)name < (uintptr_t)__sensing_connection_pool.pool + \ + sizeof(__sensing_connection_pool.pool)); + +K_MUTEX_DEFINE(connection_lock); + +static uint32_t bitarray_bundles[__SENSING_POOL_MASK_BUNDLE_COUNT]; +static sys_bitarray_t bitarray = { + .num_bits = CONFIG_SENSING_MAX_CONNECTIONS, + .num_bundles = __SENSING_POOL_MASK_BUNDLE_COUNT, + .bundles = bitarray_bundles, +}; + +struct sensing_connection_pool __sensing_connection_pool = { + .bitarray = &bitarray, + .lock = &connection_lock, +}; + +#define __lock k_mutex_lock(__sensing_connection_pool.lock, K_FOREVER) +#define __unlock k_mutex_unlock(__sensing_connection_pool.lock) int sensing_open_sensor(const struct sensing_sensor_info *info, const struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle) { struct sensing_connection *connection; + size_t offset; int rc; __ASSERT_NO_MSG(info != NULL); __ASSERT_NO_MSG(cb_list != NULL); __ASSERT_NO_MSG(handle != NULL); - rc = sys_mem_blocks_alloc(&connection_allocator, 1, (void**)&connection); - + __lock; + rc = sys_bitarray_alloc(__sensing_connection_pool.bitarray, 1, &offset); if (rc != 0) { + __unlock; return rc; } + connection = &__sensing_connection_pool.pool[offset]; + + __ASSERT_NO_MSG(!connection->flags.in_use); + LOG_DBG("Connection opened @ %p (size=%d) for info @ %p", connection, + (int)sizeof(struct sensing_connection), info); + connection->flags.in_use = true; + connection->info = info; connection->cb_list = cb_list; *handle = connection; + __unlock; return 0; } int sensing_close_sensor(sensing_sensor_handle_t handle) { - return sys_mem_blocks_free(&connection_allocator, 1, &handle); + __HANDLE_TO_CONNECTION(connection, handle); + + if (!connection->flags.in_use) { + return -EINVAL; + } + connection->flags.in_use = false; + + __lock; + LOG_DBG("Releasing connection at %p", handle); + int rc = sys_bitarray_free(__sensing_connection_pool.bitarray, 1, + connection - __sensing_connection_pool.pool); + + if (rc != 0) { + connection->flags.in_use = true; + } + __unlock; + return rc; } -void sensing_reset_connections(void) +int sensing_set_attributes(sensing_sensor_handle_t handle, + struct sensing_sensor_attribute *attributes, size_t count) { - uint8_t *ptr = connection_pool; + __HANDLE_TO_CONNECTION(connection, handle); + + __lock; + for (size_t i = 0; i < count; ++i) { + const int8_t shift = 16 - attributes[i].shift; + const q31_t value = shift >= 0 ? (attributes[i].value >> shift) + : (attributes[i].value << -shift); - while (ptr < connection_pool + sizeof(connection_pool)) { - sys_mem_blocks_free(&connection_allocator, 1, (void**)&ptr); - ptr += sizeof(struct sensing_connection); + __ASSERT_NO_MSG(attributes[i].attribute < 32); + connection->attributes[attributes[i].attribute] = value; + connection->attribute_mask |= BIT(attributes[i].attribute); + LOG_DBG("Updated attribute (%d) to 0x%08x->0x%08x", attributes[i].attribute, + attributes[i].value, value); } + __sensing_arbitrate(); + __unlock; + return 0; +} + +const struct sensing_sensor_info *sensing_get_sensor_info(sensing_sensor_handle_t handle) +{ + __HANDLE_TO_CONNECTION(connection, handle); + + return connection->info; +} + +void sensing_reset_connections(void) +{ + __lock; + sys_bitarray_clear_region(__sensing_connection_pool.bitarray, + __sensing_connection_pool.bitarray->num_bits, 0); + memset(__sensing_connection_pool.pool, 0, sizeof(__sensing_connection_pool.pool)); + __unlock; } diff --git a/subsys/sensing/src/sensor_info.c b/subsys/sensing/src/sensor_info.c index 3af62d40dbdcba..03dd8e3aade80c 100644 --- a/subsys/sensing/src/sensor_info.c +++ b/subsys/sensing/src/sensor_info.c @@ -5,6 +5,9 @@ #include #include +#include + +LOG_MODULE_REGISTER(sensing, CONFIG_SENSING_LOG_LEVEL); int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **info) { diff --git a/subsys/sensing/src/sensor_pipe.c b/subsys/sensing/src/sensor_pipe.c index fb1a1b9e797063..09def4b6136894 100644 --- a/subsys/sensing/src/sensor_pipe.c +++ b/subsys/sensing/src/sensor_pipe.c @@ -7,11 +7,27 @@ #include #include #include +#include + +LOG_MODULE_REGISTER(sensing_pipe, CONFIG_SENSING_LOG_LEVEL); #define DT_DRV_COMPAT zephyr_sensing_pipe +struct sensor_pipe_config { + const struct sensor_info *parent_info; +}; + +static int attribute_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + const struct sensor_pipe_config *cfg = dev->config; + + LOG_DBG("Updating '%s' @%p", cfg->parent_info->dev->name, cfg->parent_info->dev); + return sensor_attr_set(cfg->parent_info->dev, chan, attr, val); +} + static const struct sensor_driver_api sensor_pipe_api = { - .attr_set = NULL, + .attr_set = attribute_set, .attr_get = NULL, .get_decoder = NULL, .submit = NULL, @@ -19,11 +35,17 @@ static const struct sensor_driver_api sensor_pipe_api = { static int sensing_sensor_pipe_init(const struct device *dev) { + const struct sensor_pipe_config *cfg = dev->config; + + LOG_DBG("Initializing %p with underlying device %p", dev, cfg->parent_info->dev); return 0; } #define SENSING_PIPE_INIT(inst) \ - SENSING_SENSOR_DT_INST_DEFINE(inst, sensing_sensor_pipe_init, NULL, NULL, NULL, \ + static const struct sensor_pipe_config cfg_##inst = { \ + .parent_info = &SENSOR_INFO_DT_NAME(DT_INST_PHANDLE(inst, dev)), \ + }; \ + SENSING_SENSOR_DT_INST_DEFINE(inst, sensing_sensor_pipe_init, NULL, NULL, &cfg_##inst, \ APPLICATION, 10, &sensor_pipe_api); DT_INST_FOREACH_STATUS_OKAY(SENSING_PIPE_INIT) diff --git a/tests/subsys/sensing/CMakeLists.txt b/tests/subsys/sensing/CMakeLists.txt index 1b34e474c14b0c..422c7fccb4a9e8 100644 --- a/tests/subsys/sensing/CMakeLists.txt +++ b/tests/subsys/sensing/CMakeLists.txt @@ -5,4 +5,10 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(device) -target_sources(app PRIVATE src/main.c) +target_sources(app + PRIVATE + src/main.c + src/test_arbitration.c + src/test_connections.c + src/test_list_sensors.c +) diff --git a/tests/subsys/sensing/prj.conf b/tests/subsys/sensing/prj.conf index 0e0e881d69886a..67d380c98175c5 100644 --- a/tests/subsys/sensing/prj.conf +++ b/tests/subsys/sensing/prj.conf @@ -10,6 +10,8 @@ CONFIG_GPIO=y # Enable sensors CONFIG_SENSOR=y CONFIG_SENSING=y +CONFIG_SENSING_LOG_LEVEL_DBG=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y # Enable emulation CONFIG_EMUL=y diff --git a/tests/subsys/sensing/src/test_arbitration.c b/tests/subsys/sensing/src/test_arbitration.c new file mode 100644 index 00000000000000..84d912fec2db3a --- /dev/null +++ b/tests/subsys/sensing/src/test_arbitration.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "icm42688_emul.h" +#include "icm42688_reg.h" + +ZTEST(sensing, test_single_connection_arbitration) +{ + const struct emul *icm42688 = EMUL_DT_GET(DT_NODELABEL(icm42688)); + const struct sensing_sensor_info *sensor = SENSING_SENSOR_INFO_GET( + DT_NODELABEL(accelgyro), SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D); + const struct sensing_callback_list cb_list; + sensing_sensor_handle_t handle; + + zassert_not_null(sensor); + + /* Open connection */ + zassert_ok(sensing_open_sensor(sensor, &cb_list, &handle)); + + struct sensing_sensor_attribute attribute = { + .attribute = SENSOR_ATTR_SAMPLING_FREQUENCY, + .value = FIELD_PREP(GENMASK(31, 24), 100), + .shift = 8, + }; + zassert_ok(sensing_set_attributes(handle, &attribute, 1)); + + uint8_t reg_val; + icm42688_emul_get_reg(icm42688, REG_ACCEL_CONFIG0, ®_val, 1); + + zassert_equal(0b1000, FIELD_GET(MASK_ACCEL_ODR, reg_val), "ACCEL_CONFIG0=0x%02x", + FIELD_GET(MASK_ACCEL_ODR, reg_val)); +} + +ZTEST(sensing, test_double_connection_arbitration) +{ + const struct emul *icm42688 = EMUL_DT_GET(DT_NODELABEL(icm42688)); + const struct sensing_sensor_info *sensor = SENSING_SENSOR_INFO_GET( + DT_NODELABEL(accelgyro), SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D); + const struct sensing_callback_list cb_list; + sensing_sensor_handle_t handles[2]; + + zassert_not_null(sensor); + + /* Open connection */ + zassert_ok(sensing_open_sensor(sensor, &cb_list, &handles[0])); + zassert_ok(sensing_open_sensor(sensor, &cb_list, &handles[1])); + + struct sensing_sensor_attribute attribute = { + .attribute = SENSOR_ATTR_SAMPLING_FREQUENCY, + .value = FIELD_PREP(GENMASK(31, 23), 100), + .shift = 9, + }; + zassert_ok(sensing_set_attributes(handles[0], &attribute, 1)); + + attribute.value = FIELD_PREP(GENMASK(31, 23), 200); + zassert_ok(sensing_set_attributes(handles[1], &attribute, 1)); + + uint8_t reg_val; + icm42688_emul_get_reg(icm42688, REG_ACCEL_CONFIG0, ®_val, 1); + + zassert_equal(0b0111, FIELD_GET(MASK_ACCEL_ODR, reg_val), "ACCEL_CONFIG0=0x%02x", + FIELD_GET(MASK_ACCEL_ODR, reg_val)); +} diff --git a/tests/subsys/sensing/src/test_connections.c b/tests/subsys/sensing/src/test_connections.c index 264280f050b41d..f79c309bc7cf20 100644 --- a/tests/subsys/sensing/src/test_connections.c +++ b/tests/subsys/sensing/src/test_connections.c @@ -23,7 +23,7 @@ ZTEST(sensing, test_open_connections_limit) } /* Try to over allocate */ - zassert_equal(-ENOMEM, sensing_open_sensor(sensor, &cb_list, + zassert_equal(-ENOSPC, sensing_open_sensor(sensor, &cb_list, &handles[CONFIG_SENSING_MAX_CONNECTIONS])); /* Free one connection */ @@ -32,3 +32,17 @@ ZTEST(sensing, test_open_connections_limit) /* Allocate one */ zassert_ok(sensing_open_sensor(sensor, &cb_list, &handles[CONFIG_SENSING_MAX_CONNECTIONS])); } + +ZTEST(sensing, test_connection_get_info) +{ + const struct sensing_sensor_info *sensor = SENSING_SENSOR_INFO_GET( + DT_NODELABEL(accelgyro), SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D); + const struct sensing_callback_list cb_list; + sensing_sensor_handle_t handle; + + zassert_not_null(sensor); + zassert_ok(sensing_open_sensor(sensor, &cb_list, &handle)); + + const struct sensing_sensor_info *info = sensing_get_sensor_info(handle); + zassert_equal_ptr(sensor, info); +} From 3a9fb5ba40297937ef5212b3b8d7f8ce51b4f7f5 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Thu, 29 Jun 2023 00:50:01 -0600 Subject: [PATCH 06/10] Add sensing shell --- include/zephyr/sensing/sensing.h | 8 + .../sensor_shell/boards/tdk_robokit1.overlay | 14 + samples/sensor/sensor_shell/prj.conf | 5 + subsys/sensing/CMakeLists.txt | 2 + subsys/sensing/Kconfig | 3 + subsys/sensing/src/sensor_connections.c | 3 + subsys/sensing/src/shell.c | 258 ++++++++++++++++++ tests/subsys/sensing/src/test_arbitration.c | 9 +- tests/subsys/sensing/testcase.yaml | 2 +- 9 files changed, 301 insertions(+), 3 deletions(-) create mode 100644 samples/sensor/sensor_shell/boards/tdk_robokit1.overlay create mode 100644 subsys/sensing/src/shell.c diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index 7892b9f602f46f..7c8549f525dabf 100644 --- a/include/zephyr/sensing/sensing.h +++ b/include/zephyr/sensing/sensing.h @@ -32,6 +32,14 @@ extern "C" { #endif +#ifdef CONFIG_USERSPACE +#define SENSING_DMEM K_APP_DMEM(sensing_mem_partition) +#define SENSING_BMEM K_APP_BMEM(sensing_mem_partition) +#else +#define SENSING_DMEM +#define SENSING_BMEM +#endif + /** * @struct sensing_sensor_version * @brief Sensor Version diff --git a/samples/sensor/sensor_shell/boards/tdk_robokit1.overlay b/samples/sensor/sensor_shell/boards/tdk_robokit1.overlay new file mode 100644 index 00000000000000..45841a4c1fc40d --- /dev/null +++ b/samples/sensor/sensor_shell/boards/tdk_robokit1.overlay @@ -0,0 +1,14 @@ +/* Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + + #include + +/ { + accelgyro: accelgyro { + compatible = "zephyr,sensing-pipe"; + status = "okay"; + dev = <&icm42688>; + sensor-types = ; + }; +}; diff --git a/samples/sensor/sensor_shell/prj.conf b/samples/sensor/sensor_shell/prj.conf index d3189e39aeac76..3753f4f2f5b6b3 100644 --- a/samples/sensor/sensor_shell/prj.conf +++ b/samples/sensor/sensor_shell/prj.conf @@ -6,3 +6,8 @@ CONFIG_SENSOR_INFO=y CONFIG_LOG=y CONFIG_RTIO_CONSUME_SEM=y + +CONFIG_SENSING=y +CONFIG_SENSING_SHELL=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y +CONFIG_SENSING_LOG_LEVEL_DBG=y diff --git a/subsys/sensing/CMakeLists.txt b/subsys/sensing/CMakeLists.txt index bd47b62c6a11b5..ec9e4c2fca91b7 100644 --- a/subsys/sensing/CMakeLists.txt +++ b/subsys/sensing/CMakeLists.txt @@ -7,4 +7,6 @@ zephyr_library_sources( src/sensor_pipe.c src/sensor_connections.c ) +zephyr_library_sources_ifdef(CONFIG_SENSING_SHELL src/shell.c) + zephyr_library_include_directories(include) diff --git a/subsys/sensing/Kconfig b/subsys/sensing/Kconfig index 4476555c5d115f..c7d10fb9436276 100644 --- a/subsys/sensing/Kconfig +++ b/subsys/sensing/Kconfig @@ -25,4 +25,7 @@ config SENSING_MAX_CONNECTIONS same sensor by different clients or the same client to different sensors). +config SENSING_SHELL + bool "Shell commands for sensing subsystem" + endif # SENSING diff --git a/subsys/sensing/src/sensor_connections.c b/subsys/sensing/src/sensor_connections.c index 9d199b7891a676..2d1a2fd908bbdc 100644 --- a/subsys/sensing/src/sensor_connections.c +++ b/subsys/sensing/src/sensor_connections.c @@ -80,6 +80,8 @@ int sensing_close_sensor(sensing_sensor_handle_t handle) if (rc != 0) { connection->flags.in_use = true; + } else { + __sensing_arbitrate(); } __unlock; return rc; @@ -120,5 +122,6 @@ void sensing_reset_connections(void) sys_bitarray_clear_region(__sensing_connection_pool.bitarray, __sensing_connection_pool.bitarray->num_bits, 0); memset(__sensing_connection_pool.pool, 0, sizeof(__sensing_connection_pool.pool)); + __sensing_arbitrate(); __unlock; } diff --git a/subsys/sensing/src/shell.c b/subsys/sensing/src/shell.c new file mode 100644 index 00000000000000..149a0035e23092 --- /dev/null +++ b/subsys/sensing/src/shell.c @@ -0,0 +1,258 @@ +#include +#include +#include + +#define SENSING_INFO_HELP "Get sensor info, such as vendor and model name, for all sensors." + +#define SENSING_OPEN_HELP \ + "Open a new connection or list current open connections if no argument" \ + " is provided:\n" \ + "[sensor_index]" + +#define SENSING_CLOSE_HELP "Close an existing connection:\n" + +#define SENSING_CONFIG_HELP \ + "Configure an existing connection:\n" \ + " " + +#define SENSOR_TYPE_TO_STRING(type) \ + case type: \ + return #type + +static const char *get_sensor_type_string(int32_t type) +{ + switch (type) { + SENSOR_TYPE_TO_STRING(SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D); + SENSOR_TYPE_TO_STRING(SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D); + default: + return "UNKNOWN"; + } +} + +static inline void print_sensor_info(const struct shell *sh, int index, + const struct sensing_sensor_info *sensor) +{ + const char *null_str = "(null)"; + + shell_print(sh, + "[%d] %s\n device name: %s, vendor: %s, model: %s, " + "friendly name: %s", + index, get_sensor_type_string(sensor->type), + sensor->info->dev ? sensor->info->dev->name : "VIRTUAL", + sensor->info->vendor ? sensor->info->vendor : null_str, + sensor->info->model ? sensor->info->model : null_str, + sensor->info->friendly_name ? sensor->info->friendly_name : null_str); +} + +static int cmd_get_sensor_info(const struct shell *sh, size_t argc, char **argv) +{ + const struct sensing_sensor_info *sensors; + int num_sensors; + + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + int rc = sensing_get_sensors(&num_sensors, &sensors); + if (rc != 0) { + shell_error(sh, "Failed to get sensor list"); + return rc; + } + + if (num_sensors == 0) { + shell_warn(sh, "No sensors found"); + return 0; + } + + for (int i = 0; i < num_sensors; ++i) { + print_sensor_info(sh, i, &sensors[i]); + } + return 0; +} + +struct shell_cmd_connection { + sensing_sensor_handle_t handle; + bool is_used; +}; +static struct shell_cmd_connection open_connections[CONFIG_SENSING_MAX_CONNECTIONS]; + +static const struct sensing_callback_list callback_list = { + .on_data_event = NULL, +}; + +static int cmd_open_connection(const struct shell *sh, size_t argc, char **argv) +{ + if (argc == 1) { + /* List open connections */ + bool has_connections = false; + for (int i = 0; i < ARRAY_SIZE(open_connections); ++i) { + if (open_connections[i].is_used) { + print_sensor_info( + sh, i, sensing_get_sensor_info(open_connections[i].handle)); + has_connections = true; + } + } + if (!has_connections) { + shell_print(sh, "No open connections"); + } + return 0; + } + + const struct sensing_sensor_info *sensors; + int num_sensors; + char *endptr; + long sensor_index = strtol(argv[1], &endptr, 0); + int rc = sensing_get_sensors(&num_sensors, &sensors); + + if (rc != 0) { + shell_error(sh, "Failed to get sensor list"); + return rc; + } + + if (sensor_index < 0 || sensor_index >= num_sensors) { + shell_error(sh, "Sensor index (%ld) out of bounds, valid range is 0-%d", + sensor_index, num_sensors - 1); + return -EINVAL; + } + + int connection_idx = -1; + for (int i = 0; i < ARRAY_SIZE(open_connections); ++i) { + if (!open_connections[i].is_used) { + connection_idx = i; + break; + } + } + + if (connection_idx < 0) { + shell_error(sh, + "No more memory for connections, close a connection then try again"); + return -ENOMEM; + } + + rc = sensing_open_sensor(&sensors[sensor_index], &callback_list, + &open_connections[connection_idx].handle); + + if (rc != 0) { + shell_error(sh, "Failed to open connection"); + return rc; + } + + open_connections[connection_idx].is_used = true; + shell_print(sh, "New connection [%d] to sensor [%ld] created", connection_idx, sensor_index); + + return 0; +} + +static int cmd_close_connection(const struct shell *sh, size_t argc, char **argv) +{ + char *endptr; + long connection_index = strtol(argv[1], &endptr, 0); + + if (!open_connections[connection_index].is_used) { + shell_error( + sh, + "Invalid connection number, run 'sensing open' to see current connections"); + return -EINVAL; + } + + int rc = sensing_close_sensor(open_connections[connection_index].handle); + if (rc != 0) { + shell_error(sh, "Failed to close connection (%ld)", connection_index); + return rc; + } + open_connections[connection_index].is_used = false; + return 0; +} + +static int parse_sensor_value(const struct shell *sh, const char *val_str, q31_t *q, int8_t *shift) +{ + const bool is_negative = val_str[0] == '-'; + const char *decimal_pos = strchr(val_str, '.'); + long value; + int64_t micro_value; + char *endptr; + + /* Parse int portion */ + value = strtol(val_str, &endptr, 0); + + if (*endptr != '\0' && *endptr != '.') { + return -EINVAL; + } + if (value > INT32_MAX || value < INT32_MIN) { + return -EINVAL; + } + + *shift = ilog2(labs(value) - 1) + 1; + micro_value = value * 1000000; + + if (decimal_pos == NULL) { + goto end; + } + + /* Parse the decimal portion */ + value = strtoul(decimal_pos + 1, &endptr, 0); + if (*endptr != '\0') { + return -EINVAL; + } + while (value < 100000) { + value *= 10; + } + if (value > INT32_C(999999)) { + return -EINVAL; + } + if (is_negative) { + value *= -1; + } + micro_value += value; +end: + *q = ((micro_value * (INT64_C(1) << 31)) / 1000000) >> *shift; + shell_info(sh, "micro_value=%" PRIi64, micro_value); + *shift += 1; + return 0; +} + +static int cmd_config(const struct shell *sh, size_t argc, char **argv) +{ + char *endptr; + long connection_index = strtol(argv[1], &endptr, 0); + + if (!open_connections[connection_index].is_used) { + shell_error( + sh, + "Invalid connection number, run 'sensing open' to see current connections"); + return -EINVAL; + } + + enum sensor_attribute attribute; + if (strcmp("sampling_frequency", argv[2]) == 0) { + attribute = SENSOR_ATTR_SAMPLING_FREQUENCY; + } else { + shell_error(sh, "Invalid attribute '%s'", argv[2]); + return -EINVAL; + } + + struct sensing_sensor_attribute config = { + .attribute = attribute, + }; + int rc = parse_sensor_value(sh, argv[3], &config.value, &config.shift); + + if (rc != 0) { + shell_error(sh, "Invalid value '%s'", argv[3]); + return -EINVAL; + } + + shell_info(sh, "Configuring q=0x%08x, shift=%d", config.value, config.shift); + rc = sensing_set_attributes(open_connections[connection_index].handle, &config, 1); + if (rc != 0) { + shell_error(sh, "Failed to set attribute '%s' to '%s'", argv[2], argv[3]); + return rc; + } + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE( + sub_sensing, SHELL_CMD_ARG(info, NULL, SENSING_INFO_HELP, cmd_get_sensor_info, 1, 0), + SHELL_CMD_ARG(open, NULL, SENSING_OPEN_HELP, cmd_open_connection, 1, 1), + SHELL_CMD_ARG(close, NULL, SENSING_CLOSE_HELP, cmd_close_connection, 2, 0), + SHELL_CMD_ARG(config, NULL, SENSING_CONFIG_HELP, cmd_config, 4, 0), SHELL_SUBCMD_SET_END); + +SHELL_CMD_REGISTER(sensing, &sub_sensing, "Sensing subsystem commands", NULL); diff --git a/tests/subsys/sensing/src/test_arbitration.c b/tests/subsys/sensing/src/test_arbitration.c index 84d912fec2db3a..b7ca5fd5587cea 100644 --- a/tests/subsys/sensing/src/test_arbitration.c +++ b/tests/subsys/sensing/src/test_arbitration.c @@ -46,6 +46,7 @@ ZTEST(sensing, test_double_connection_arbitration) DT_NODELABEL(accelgyro), SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D); const struct sensing_callback_list cb_list; sensing_sensor_handle_t handles[2]; + uint8_t reg_val; zassert_not_null(sensor); @@ -63,9 +64,13 @@ ZTEST(sensing, test_double_connection_arbitration) attribute.value = FIELD_PREP(GENMASK(31, 23), 200); zassert_ok(sensing_set_attributes(handles[1], &attribute, 1)); - uint8_t reg_val; icm42688_emul_get_reg(icm42688, REG_ACCEL_CONFIG0, ®_val, 1); - zassert_equal(0b0111, FIELD_GET(MASK_ACCEL_ODR, reg_val), "ACCEL_CONFIG0=0x%02x", FIELD_GET(MASK_ACCEL_ODR, reg_val)); + + /* Close the second connection and check that we're back to 100Hz */ + zassert_ok(sensing_close_sensor(handles[1])); + icm42688_emul_get_reg(icm42688, REG_ACCEL_CONFIG0, ®_val, 1); + zassert_equal(0b1000, FIELD_GET(MASK_ACCEL_ODR, reg_val), "ACCEL_CONFIG0=0x%02x", + FIELD_GET(MASK_ACCEL_ODR, reg_val)); } diff --git a/tests/subsys/sensing/testcase.yaml b/tests/subsys/sensing/testcase.yaml index 2f9d013e2a2f4e..b1cf9f14ee29bc 100644 --- a/tests/subsys/sensing/testcase.yaml +++ b/tests/subsys/sensing/testcase.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 tests: - subsys.sensing.list: + subsys.sensing: tags: - sensor - subsys From 1462d8a38d20ee2657a3445f8e25d33f2bdabf22 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Thu, 29 Jun 2023 12:59:41 -0600 Subject: [PATCH 07/10] add support for userspace --- include/zephyr/sensing/sensing.h | 67 +++++++++++++++++++ include/zephyr/sensing/sensor_types.h | 17 +++-- samples/sensor/sensor_shell/prj.conf | 1 + subsys/sensing/CMakeLists.txt | 1 + .../include/sensing/internal/sensing.h | 18 +++-- subsys/sensing/src/sensor_arbitrate.c | 13 ++-- subsys/sensing/src/sensor_connections.c | 39 +++++------ subsys/sensing/src/shell.c | 2 - subsys/sensing/src/userspace.c | 22 ++++++ 9 files changed, 137 insertions(+), 43 deletions(-) create mode 100644 subsys/sensing/src/userspace.c diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index 7c8549f525dabf..3fc6df3c25ac7a 100644 --- a/include/zephyr/sensing/sensing.h +++ b/include/zephyr/sensing/sensing.h @@ -40,6 +40,73 @@ extern "C" { #define SENSING_BMEM #endif +/** + * @addtogroup sensiong_sensor_modes + * @{ + */ + +enum sensing_sensor_mode { + /** + * @brief Get events from the sensor. + * + * Power: Turn on if not already on. + * Reporting: Continuous. Send each new event as it comes (subject to batching and latency). + */ + SENSING_SENSOR_MODE_CONTINUOUS, + + /** + * @brief Get a single event from the sensor and then become DONE. + * + * Once the event is sent, the sensor automatically changes to + * :c:enum:`SENSING_SENSOR_MODE_DONE`. + * + * Power: Turn on if not already on. + * Reporting: One shot. Send the next event and then be DONE. + */ + SENSING_SENSOR_MODE_ONE_SHOT, + + /** + * @brief Get events from a sensor that are generated for any client in the system. + * + * This is considered passive because the sensor will not be powered on for the sake of the + * client. If and only if another client in the system has requested this sensor power on + * will we get events. + * + * This can be useful for something which is interested in seeing data, but not interested + * enough to be responsible for powering on the sensor. + * + * Power: Do not power the sensor on our behalf. + * Reporting: Continuous. Send each event as it comes. + */ + SENSING_SENSOR_MODE_PASSIVE_CONTINUOUS, + + /** + * @brief Get a single event from a sensor that is generated for any client in the system. + * + * See :c:enum:`SENSING_SENSOR_MODE_PASSIVE_CONTINUOUS` for more details on what the + * "passive" means. + * + * Power: Do not power the sensor on our behalf. + * Reporting: One shot. Send only the next event and then be DONE. + */ + SENSING_SENSOR_MODE_PASSIVE_ONE_SHOT, + + /** + * @brief Indicate we are done using this sensor and no longer interested in it. + * + * See :c:func:`sensing_configure` for more details on expressing interest or lack of + * interest in a sensor. + * + * Power: Do not power the sensor on our behalf. + * Reporting: None. + */ + SENSING_SENSOR_MODE_DONE, +}; + +/** + * @} + */ + /** * @struct sensing_sensor_version * @brief Sensor Version diff --git a/include/zephyr/sensing/sensor_types.h b/include/zephyr/sensing/sensor_types.h index 03b7b9730c79cc..a6b6fcb94f2fea 100644 --- a/include/zephyr/sensing/sensor_types.h +++ b/include/zephyr/sensing/sensor_types.h @@ -22,26 +22,25 @@ /** * sensor category light */ -#define SENSING_SENSOR_TYPE_LIGHT_AMBIENTLIGHT 0x41 +#define SENSING_SENSOR_TYPE_LIGHT_AMBIENTLIGHT 0x41 /** * sensor category motion */ -#define SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D 115 -#define SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D 118 -#define SENSING_SENSOR_TYPE_MOTION_MOTION_DETECTOR 119 - +#define SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D 115 +#define SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D 118 +#define SENSING_SENSOR_TYPE_MOTION_MOTION_DETECTOR 119 /** * sensor category other */ -#define SENSING_SENSOR_TYPE_OTHER_CUSTOM 0xE1 +#define SENSING_SENSOR_TYPE_OTHER_CUSTOM 0xE1 -#define SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D 0x240 +#define SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D 0x240 -#define SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE 0x20B +#define SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE 0x20B -#define SENSING_SENSOR_TYPE_ALL 0xFFFF +#define SENSING_SENSOR_TYPE_ALL 0xFFFF /** * @} diff --git a/samples/sensor/sensor_shell/prj.conf b/samples/sensor/sensor_shell/prj.conf index 3753f4f2f5b6b3..6605bdf9f1e0da 100644 --- a/samples/sensor/sensor_shell/prj.conf +++ b/samples/sensor/sensor_shell/prj.conf @@ -7,6 +7,7 @@ CONFIG_SENSOR_INFO=y CONFIG_LOG=y CONFIG_RTIO_CONSUME_SEM=y +CONFIG_USERSPACE=y CONFIG_SENSING=y CONFIG_SENSING_SHELL=y CONFIG_SENSOR_LOG_LEVEL_DBG=y diff --git a/subsys/sensing/CMakeLists.txt b/subsys/sensing/CMakeLists.txt index ec9e4c2fca91b7..0ca14419e76a1c 100644 --- a/subsys/sensing/CMakeLists.txt +++ b/subsys/sensing/CMakeLists.txt @@ -8,5 +8,6 @@ zephyr_library_sources( src/sensor_connections.c ) zephyr_library_sources_ifdef(CONFIG_SENSING_SHELL src/shell.c) +zephyr_library_sources_ifdef(CONFIG_USERSPACE src/userspace.c) zephyr_library_include_directories(include) diff --git a/subsys/sensing/include/sensing/internal/sensing.h b/subsys/sensing/include/sensing/internal/sensing.h index 4db844cab09480..bfa1cfc652f02a 100644 --- a/subsys/sensing/include/sensing/internal/sensing.h +++ b/subsys/sensing/include/sensing/internal/sensing.h @@ -8,6 +8,7 @@ #include #include #include +#include #define __SENSING_POOL_MASK_BUNDLE_COUNT \ (DIV_ROUND_UP(DIV_ROUND_UP(CONFIG_SENSING_MAX_CONNECTIONS, 8), sizeof(uint32_t))) @@ -17,20 +18,27 @@ struct sensing_connection { const struct sensing_callback_list *cb_list; q31_t attributes[SENSOR_ATTR_COMMON_COUNT]; uint32_t attribute_mask; - struct { - uint8_t in_use: 1; - uint8_t reserved: 7; - } flags; } __packed __aligned(4); extern struct sensing_connection_pool { struct sensing_connection pool[CONFIG_SENSING_MAX_CONNECTIONS]; sys_bitarray_t *bitarray; - struct k_mutex *lock; + struct sys_mutex *lock; } __sensing_connection_pool; BUILD_ASSERT(SENSOR_ATTR_COMMON_COUNT <= 32, "Too many sensor attributes"); +static inline bool __sensing_is_connected(const struct sensing_sensor_info *info, + const struct sensing_connection *connection) +{ + int is_set; + int connection_index = connection - __sensing_connection_pool.pool; + int rc = sys_bitarray_test_bit(__sensing_connection_pool.bitarray, connection_index, + &is_set); + + return rc == 0 && is_set != 0 && (info == NULL || connection->info == info); +} + void __sensing_arbitrate(); #endif // ZEPHYR_SUBSYS_SENSING_INCLUDE_SENSING_INTERNAL_SENSING_H diff --git a/subsys/sensing/src/sensor_arbitrate.c b/subsys/sensing/src/sensor_arbitrate.c index feaf3c77eb201d..fae5276bef1e66 100644 --- a/subsys/sensing/src/sensor_arbitrate.c +++ b/subsys/sensing/src/sensor_arbitrate.c @@ -52,12 +52,10 @@ static int arbitrate_sensor_attribute(const struct sensing_sensor_info *info, q31_t value; for (int i = 0; i < CONFIG_SENSING_MAX_CONNECTIONS; ++i) { - if (connections[i].info != info || !connections[i].flags.in_use) { -// LOG_DBG("Skipping connection %p, info mismatch", (void*)&connections[i]); + if (!__sensing_is_connected(info, &connections[i])) { continue; } if (FIELD_GET(BIT(attribute), connections[i].attribute_mask) == 0) { -// LOG_DBG("Skipping connection %p, attribute not set", (void*)&connections[i]); continue; } if (connection_count == 0) { @@ -65,11 +63,11 @@ static int arbitrate_sensor_attribute(const struct sensing_sensor_info *info, value = connections[i].attributes[attribute]; LOG_DBG("Arbitrating '%s'@%p type=%d attribute=%d", info->info->dev->name, info->info->dev, info->type, attribute); - LOG_DBG(" First connection %p, value=0x%08x", (void*)&connections[i], value); + LOG_DBG(" First connection %d/%p, value=0x%08x", i, (void*)&connections[i], value); } else { value = arbitrate_attribute_value(attribute, value, connections[i].attributes[attribute]); - LOG_DBG(" Updating %p, value=0x%08x", (void*)&connections[i], value); + LOG_DBG(" Updating %d/%p, value=0x%08x", i, (void*)&connections[i], value); } connection_count++; } @@ -83,9 +81,12 @@ static int arbitrate_sensor_attribute(const struct sensing_sensor_info *info, static void arbitrate_sensor_instance(const struct sensing_sensor_info *info) { + int count = 0; + for (int i = 0; i < SENSOR_ATTR_COMMON_COUNT; ++i) { - arbitrate_sensor_attribute(info, i); + count += arbitrate_sensor_attribute(info, i); } + LOG_DBG("Arbitrated %p with %d connections", (void*)info, count); } void __sensing_arbitrate(void) diff --git a/subsys/sensing/src/sensor_connections.c b/subsys/sensing/src/sensor_connections.c index 2d1a2fd908bbdc..7079d49c71f669 100644 --- a/subsys/sensing/src/sensor_connections.c +++ b/subsys/sensing/src/sensor_connections.c @@ -15,22 +15,22 @@ LOG_MODULE_REGISTER(sensing_connect, CONFIG_SENSING_LOG_LEVEL); __ASSERT_NO_MSG((uintptr_t)name < (uintptr_t)__sensing_connection_pool.pool + \ sizeof(__sensing_connection_pool.pool)); -K_MUTEX_DEFINE(connection_lock); +SENSING_DMEM SYS_MUTEX_DEFINE(connection_lock); -static uint32_t bitarray_bundles[__SENSING_POOL_MASK_BUNDLE_COUNT]; -static sys_bitarray_t bitarray = { +SENSING_DMEM static uint32_t bitarray_bundles[__SENSING_POOL_MASK_BUNDLE_COUNT] = {0}; +SENSING_DMEM static sys_bitarray_t bitarray = { .num_bits = CONFIG_SENSING_MAX_CONNECTIONS, .num_bundles = __SENSING_POOL_MASK_BUNDLE_COUNT, .bundles = bitarray_bundles, }; -struct sensing_connection_pool __sensing_connection_pool = { +SENSING_DMEM struct sensing_connection_pool __sensing_connection_pool = { .bitarray = &bitarray, .lock = &connection_lock, }; -#define __lock k_mutex_lock(__sensing_connection_pool.lock, K_FOREVER) -#define __unlock k_mutex_unlock(__sensing_connection_pool.lock) +#define __lock sys_mutex_lock(__sensing_connection_pool.lock, K_FOREVER) +#define __unlock sys_mutex_unlock(__sensing_connection_pool.lock) int sensing_open_sensor(const struct sensing_sensor_info *info, const struct sensing_callback_list *cb_list, @@ -53,10 +53,9 @@ int sensing_open_sensor(const struct sensing_sensor_info *info, connection = &__sensing_connection_pool.pool[offset]; - __ASSERT_NO_MSG(!connection->flags.in_use); LOG_DBG("Connection opened @ %p (size=%d) for info @ %p", connection, (int)sizeof(struct sensing_connection), info); - connection->flags.in_use = true; + memset(connection, 0, sizeof(struct sensing_connection)); connection->info = info; connection->cb_list = cb_list; *handle = connection; @@ -67,21 +66,19 @@ int sensing_open_sensor(const struct sensing_sensor_info *info, int sensing_close_sensor(sensing_sensor_handle_t handle) { __HANDLE_TO_CONNECTION(connection, handle); - - if (!connection->flags.in_use) { - return -EINVAL; - } - connection->flags.in_use = false; + int rc = -EINVAL; __lock; - LOG_DBG("Releasing connection at %p", handle); - int rc = sys_bitarray_free(__sensing_connection_pool.bitarray, 1, - connection - __sensing_connection_pool.pool); - - if (rc != 0) { - connection->flags.in_use = true; - } else { - __sensing_arbitrate(); + if (__sensing_is_connected(NULL, connection)) { + LOG_DBG("Releasing connection at %p/%d", handle, + connection - __sensing_connection_pool.pool); + rc = sys_bitarray_free(__sensing_connection_pool.bitarray, 1, + connection - __sensing_connection_pool.pool); + if (rc == 0) { + __sensing_arbitrate(); + } else { + LOG_WRN("Failed to release connection"); + } } __unlock; return rc; diff --git a/subsys/sensing/src/shell.c b/subsys/sensing/src/shell.c index 149a0035e23092..eea8b2773f912e 100644 --- a/subsys/sensing/src/shell.c +++ b/subsys/sensing/src/shell.c @@ -205,7 +205,6 @@ static int parse_sensor_value(const struct shell *sh, const char *val_str, q31_t micro_value += value; end: *q = ((micro_value * (INT64_C(1) << 31)) / 1000000) >> *shift; - shell_info(sh, "micro_value=%" PRIi64, micro_value); *shift += 1; return 0; } @@ -240,7 +239,6 @@ static int cmd_config(const struct shell *sh, size_t argc, char **argv) return -EINVAL; } - shell_info(sh, "Configuring q=0x%08x, shift=%d", config.value, config.shift); rc = sensing_set_attributes(open_connections[connection_index].handle, &config, 1); if (rc != 0) { shell_error(sh, "Failed to set attribute '%s' to '%s'", argv[2], argv[3]); diff --git a/subsys/sensing/src/userspace.c b/subsys/sensing/src/userspace.c new file mode 100644 index 00000000000000..f24550bd915467 --- /dev/null +++ b/subsys/sensing/src/userspace.c @@ -0,0 +1,22 @@ +// +// Created by peress on 29/06/23. +// + +#include +#include +#include + +K_APPMEM_PARTITION_DEFINE(sensing_mem_partition); + +static int sensing_mem_init(void) +{ + int rc; + + rc = k_mem_domain_add_partition(&k_mem_domain_default, &sensing_mem_partition); + if (rc != 0) { + return rc; + } + return k_mem_domain_add_partition(&k_mem_domain_default, &rtio_partition); +} + +SYS_INIT(sensing_mem_init, POST_KERNEL, 99); From 87906333e9aaa089ba94aa38cf26b066be88a141 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Wed, 5 Jul 2023 13:33:28 -0600 Subject: [PATCH 08/10] Implement pipe --- drivers/sensor/default_rtio_sensor.c | 5 +- include/zephyr/sensing/sensing.h | 10 +- include/zephyr/sensing/sensor.h | 19 +- samples/sensor/sensor_shell/prj.conf | 1 + subsys/sensing/CMakeLists.txt | 1 + subsys/sensing/Kconfig | 23 ++ .../include/sensing/internal/sensing.h | 3 + subsys/sensing/src/processing.c | 78 +++++++ subsys/sensing/src/sensor_connections.c | 24 ++- subsys/sensing/src/sensor_pipe.c | 38 +++- subsys/sensing/src/shell.c | 199 ++++++++++++++++-- subsys/sensing/src/userspace.c | 13 +- 12 files changed, 377 insertions(+), 37 deletions(-) create mode 100644 subsys/sensing/src/processing.c diff --git a/drivers/sensor/default_rtio_sensor.c b/drivers/sensor/default_rtio_sensor.c index a86bd81ec1d48f..bc95c1d777aa6a 100644 --- a/drivers/sensor/default_rtio_sensor.c +++ b/drivers/sensor/default_rtio_sensor.c @@ -316,9 +316,8 @@ static int decode(const uint8_t *buffer, sensor_frame_iterator_t *fit, { const struct sensor_data_generic_header *header = (const struct sensor_data_generic_header *)buffer; - const q31_t *q = - (const q31_t *)(buffer + sizeof(struct sensor_data_generic_header) + - header->num_channels * sizeof(enum sensor_channel)); + const q31_t *q = (const q31_t *)(buffer + sizeof(struct sensor_data_generic_header) + + header->num_channels * sizeof(enum sensor_channel)); int count = 0; if (*fit != 0 || *cit >= header->num_channels) { diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index 3fc6df3c25ac7a..f1791edb250c26 100644 --- a/include/zephyr/sensing/sensing.h +++ b/include/zephyr/sensing/sensing.h @@ -168,6 +168,7 @@ typedef void *sensing_sensor_handle_t; */ typedef void (*sensing_data_event_t)(sensing_sensor_handle_t handle, const void *buf); +#include /** * @struct sensing_sensor_info * @brief Sensor basic constant information @@ -180,6 +181,13 @@ struct sensing_sensor_info { /** Sensor type */ int32_t type; + + /****** TODO hide these (private members) ******/ + struct rtio_iodev *iodev; + +#ifdef CONFIG_SENSING_SHELL + char *shell_name; +#endif }; /** @@ -241,7 +249,7 @@ struct sensing_sensor_attribute { int8_t shift; }; -int sensing_set_attributes(sensing_sensor_handle_t handle, +int sensing_set_attributes(sensing_sensor_handle_t handle, enum sensing_sensor_mode mode, struct sensing_sensor_attribute *attributes, size_t count); /** diff --git a/include/zephyr/sensing/sensor.h b/include/zephyr/sensing/sensor.h index cd4614a8187d7d..f9403961fcf3a9 100644 --- a/include/zephyr/sensing/sensor.h +++ b/include/zephyr/sensing/sensor.h @@ -14,17 +14,25 @@ #define SENSING_SENSOR_INFO_DT_NAME(node_id, type) \ _CONCAT(_CONCAT(__sensing_sensor_info_, DEVICE_DT_NAME_GET(node_id)), type) -#define SENSING_SENSOR_INFO_INST_DEFINE(node_id, prop, idx) \ - const STRUCT_SECTION_ITERABLE( \ - sensing_sensor_info, \ - SENSING_SENSOR_INFO_DT_NAME(node_id, DT_PROP_BY_IDX(node_id, prop, idx))) = { \ +#define SENSING_SENSOR_INFO_INST_DEFINE_NAMED(node_id, name, prop, idx, _iodev) \ + IF_ENABLED(CONFIG_SENSING_SHELL, (static char node_id##_##idx##_name_buffer[5];)) \ + const STRUCT_SECTION_ITERABLE(sensing_sensor_info, name) = { \ .info = &SENSOR_INFO_DT_NAME(DT_PHANDLE(node_id, dev)), \ .dev = DEVICE_DT_GET(node_id), \ .type = DT_PROP_BY_IDX(node_id, prop, idx), \ + .iodev = &(_iodev), \ + IF_ENABLED(CONFIG_SENSING_SHELL, (.shell_name = node_id##_##idx##_name_buffer, )) \ }; +#define SENSING_SENSOR_INFO_INST_DEFINE(node_id, prop, idx, _iodev) \ + SENSING_SENSOR_INFO_INST_DEFINE_NAMED( \ + node_id, SENSING_SENSOR_INFO_DT_NAME(node_id, DT_PROP_BY_IDX(node_id, prop, idx)), \ + prop, idx, _iodev) + #define SENSING_SENSOR_INFO_DT_DEFINE(node_id) \ - DT_FOREACH_PROP_ELEM(node_id, sensor_types, SENSING_SENSOR_INFO_INST_DEFINE) + SENSOR_DT_READ_IODEV(node_id##_read_iodev, node_id, SENSOR_CHAN_ALL); \ + DT_FOREACH_PROP_ELEM_VARGS(node_id, sensor_types, SENSING_SENSOR_INFO_INST_DEFINE, \ + node_id##_read_iodev) #define SENSING_SENSOR_DT_DEFINE(node_id, init_fn, pm_device, data_ptr, cfg_ptr, level, prio, \ api_ptr, ...) \ @@ -38,6 +46,7 @@ #define SENSING_SENSOR_INFO_GET(node_id, type) &SENSING_SENSOR_INFO_DT_NAME(node_id, type) STRUCT_SECTION_START_EXTERN(sensing_sensor_info); +STRUCT_SECTION_END_EXTERN(sensing_sensor_info); #if defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__) #define Z_MAYBE_SENSING_SENSOR_INFO_DECLARE_INTERNAL_DEFINE(node_id, prop, idx) \ diff --git a/samples/sensor/sensor_shell/prj.conf b/samples/sensor/sensor_shell/prj.conf index 6605bdf9f1e0da..0e6ac047463ce6 100644 --- a/samples/sensor/sensor_shell/prj.conf +++ b/samples/sensor/sensor_shell/prj.conf @@ -10,5 +10,6 @@ CONFIG_RTIO_CONSUME_SEM=y CONFIG_USERSPACE=y CONFIG_SENSING=y CONFIG_SENSING_SHELL=y +CONFIG_RTIO_LOG_LEVEL_DBG=y CONFIG_SENSOR_LOG_LEVEL_DBG=y CONFIG_SENSING_LOG_LEVEL_DBG=y diff --git a/subsys/sensing/CMakeLists.txt b/subsys/sensing/CMakeLists.txt index 0ca14419e76a1c..1d19a3c49e4185 100644 --- a/subsys/sensing/CMakeLists.txt +++ b/subsys/sensing/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library_sources( src/sensor_info.c src/sensor_pipe.c src/sensor_connections.c + src/processing.c ) zephyr_library_sources_ifdef(CONFIG_SENSING_SHELL src/shell.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE src/userspace.c) diff --git a/subsys/sensing/Kconfig b/subsys/sensing/Kconfig index c7d10fb9436276..c73ac89183e014 100644 --- a/subsys/sensing/Kconfig +++ b/subsys/sensing/Kconfig @@ -6,6 +6,7 @@ config SENSING select DSP select SENSOR_INFO select SYS_MEM_BLOCKS + select SENSOR_ASYNC_API help Enable Sensing Subsystem. @@ -25,6 +26,28 @@ config SENSING_MAX_CONNECTIONS same sensor by different clients or the same client to different sensors). +config SENSING_RTIO_BLOCK_SIZE + int "Block size of the RTIO context" + default 64 + +config SENSING_RTIO_BLOCK_COUNT + int "Number of memory blocks of the RTIO context" + default 32 + +config SENSING_PROCESSING_THREAD_STACK_SIZE + int "Stack size for the subsystem's data processing thread" + default 1024 + help + Thread stack size to use for the sensor data processing of the sensing + subsystem. The more data is expected to come through prior to being + dispatched to clients, the larger the stack will need to be. + +config SENSING_PROCESSING_THREAD_PRIORITY + int "Thread priority of the subsystem's data processing thread" + default 10 + help + The sensor subsystem's data processing thread priority + config SENSING_SHELL bool "Shell commands for sensing subsystem" diff --git a/subsys/sensing/include/sensing/internal/sensing.h b/subsys/sensing/include/sensing/internal/sensing.h index bfa1cfc652f02a..15a5ed9177d8e2 100644 --- a/subsys/sensing/include/sensing/internal/sensing.h +++ b/subsys/sensing/include/sensing/internal/sensing.h @@ -16,6 +16,7 @@ struct sensing_connection { const struct sensing_sensor_info *info; const struct sensing_callback_list *cb_list; + enum sensing_sensor_mode mode; q31_t attributes[SENSOR_ATTR_COMMON_COUNT]; uint32_t attribute_mask; } __packed __aligned(4); @@ -28,6 +29,8 @@ extern struct sensing_connection_pool { BUILD_ASSERT(SENSOR_ATTR_COMMON_COUNT <= 32, "Too many sensor attributes"); +extern struct rtio sensing_rtio_ctx; + static inline bool __sensing_is_connected(const struct sensing_sensor_info *info, const struct sensing_connection *connection) { diff --git a/subsys/sensing/src/processing.c b/subsys/sensing/src/processing.c new file mode 100644 index 00000000000000..ab001ae501219c --- /dev/null +++ b/subsys/sensing/src/processing.c @@ -0,0 +1,78 @@ +// +// Created by peress on 05/07/23. +// + +#include +#include +#include +#include +#include + +#include "sensing/internal/sensing.h" + +LOG_MODULE_REGISTER(sensing_processing, CONFIG_SENSING_LOG_LEVEL); + +static void processing_task(void *a, void *b, void *c) +{ + struct sensing_sensor_info *info; + uint8_t *data = NULL; + uint32_t data_len = 0; + int rc; + int get_data_rc; + + ARG_UNUSED(a); + ARG_UNUSED(b); + ARG_UNUSED(c); + + if (IS_ENABLED(CONFIG_USERSPACE) && !k_is_user_context()) { + rtio_access_grant(&sensing_rtio_ctx, k_current_get()); + k_thread_user_mode_enter(processing_task, a, b, c); + } + + while (true) { + struct rtio_cqe cqe; + + rc = rtio_cqe_copy_out(&sensing_rtio_ctx, &cqe, 1, K_FOREVER); + + if (rc < 1) { + continue; + } + + /* Cache the data from the CQE */ + rc = cqe.result; + info = cqe.userdata; + get_data_rc = + rtio_cqe_get_mempool_buffer(&sensing_rtio_ctx, &cqe, &data, &data_len); + + /* Do something with the data */ + LOG_DBG("Processing data for [%d], rc=%d, has_data=%d, data=%p, len=%" PRIu32, + (int)(info - STRUCT_SECTION_START(sensing_sensor_info)), rc, + get_data_rc == 0, (void *)data, data_len); + + if (get_data_rc != 0 || data_len == 0) { + continue; + } + + sys_mutex_lock(__sensing_connection_pool.lock, K_FOREVER); + for (int i = 0; i < ARRAY_SIZE(__sensing_connection_pool.pool); ++i) { + struct sensing_connection *connection = &__sensing_connection_pool.pool[i]; + if (!__sensing_is_connected(info, connection)) { + continue; + } + sensing_data_event_t cb = connection->cb_list->on_data_event; + + if (cb == NULL) { + continue; + } + /* TODO we actually need to decode the data first before this for loop */ + cb(connection, data); + } + sys_mutex_unlock(__sensing_connection_pool.lock); + + /* Release the memory */ + rtio_release_buffer(&sensing_rtio_ctx, data, data_len); + } +} + +K_THREAD_DEFINE(sensing_processor, CONFIG_SENSING_PROCESSING_THREAD_STACK_SIZE, processing_task, + NULL, NULL, NULL, CONFIG_SENSING_PROCESSING_THREAD_PRIORITY, 0, 0); diff --git a/subsys/sensing/src/sensor_connections.c b/subsys/sensing/src/sensor_connections.c index 7079d49c71f669..71134e8581f699 100644 --- a/subsys/sensing/src/sensor_connections.c +++ b/subsys/sensing/src/sensor_connections.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -13,7 +14,7 @@ LOG_MODULE_REGISTER(sensing_connect, CONFIG_SENSING_LOG_LEVEL); struct sensing_connection *name = handle; \ __ASSERT_NO_MSG((uintptr_t)name >= (uintptr_t)__sensing_connection_pool.pool); \ __ASSERT_NO_MSG((uintptr_t)name < (uintptr_t)__sensing_connection_pool.pool + \ - sizeof(__sensing_connection_pool.pool)); + sizeof(__sensing_connection_pool.pool)) SENSING_DMEM SYS_MUTEX_DEFINE(connection_lock); @@ -32,6 +33,10 @@ SENSING_DMEM struct sensing_connection_pool __sensing_connection_pool = { #define __lock sys_mutex_lock(__sensing_connection_pool.lock, K_FOREVER) #define __unlock sys_mutex_unlock(__sensing_connection_pool.lock) +RTIO_DEFINE_WITH_MEMPOOL(sensing_rtio_ctx, CONFIG_SENSING_MAX_CONNECTIONS, + CONFIG_SENSING_MAX_CONNECTIONS, CONFIG_SENSING_RTIO_BLOCK_COUNT, + CONFIG_SENSING_RTIO_BLOCK_SIZE, 4); + int sensing_open_sensor(const struct sensing_sensor_info *info, const struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle) @@ -84,10 +89,11 @@ int sensing_close_sensor(sensing_sensor_handle_t handle) return rc; } -int sensing_set_attributes(sensing_sensor_handle_t handle, +int sensing_set_attributes(sensing_sensor_handle_t handle, enum sensing_sensor_mode mode, struct sensing_sensor_attribute *attributes, size_t count) { __HANDLE_TO_CONNECTION(connection, handle); + int rc; __lock; for (size_t i = 0; i < count; ++i) { @@ -101,9 +107,21 @@ int sensing_set_attributes(sensing_sensor_handle_t handle, LOG_DBG("Updated attribute (%d) to 0x%08x->0x%08x", attributes[i].attribute, attributes[i].value, value); } + connection->mode = mode; __sensing_arbitrate(); + + switch (mode) { + case SENSING_SENSOR_MODE_ONE_SHOT: + LOG_DBG("Starting one-shot read"); + rc = sensor_read(connection->info->iodev, &sensing_rtio_ctx, + (void *)connection->info); + break; + default: + rc = -EINVAL; + break; + } __unlock; - return 0; + return rc; } const struct sensing_sensor_info *sensing_get_sensor_info(sensing_sensor_handle_t handle) diff --git a/subsys/sensing/src/sensor_pipe.c b/subsys/sensing/src/sensor_pipe.c index 09def4b6136894..c3b264bfbb0922 100644 --- a/subsys/sensing/src/sensor_pipe.c +++ b/subsys/sensing/src/sensor_pipe.c @@ -9,6 +9,8 @@ #include #include +#include "sensing/internal/sensing.h" + LOG_MODULE_REGISTER(sensing_pipe, CONFIG_SENSING_LOG_LEVEL); #define DT_DRV_COMPAT zephyr_sensing_pipe @@ -17,6 +19,10 @@ struct sensor_pipe_config { const struct sensor_info *parent_info; }; +struct sensor_pipe_data { + struct rtio_iodev *oneshot_iodev; +}; + static int attribute_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { @@ -26,11 +32,30 @@ static int attribute_set(const struct device *dev, enum sensor_channel chan, return sensor_attr_set(cfg->parent_info->dev, chan, attr, val); } -static const struct sensor_driver_api sensor_pipe_api = { +static int submit(const struct device *sensor, struct rtio_iodev_sqe *sqe) +{ + struct sensor_pipe_data *data = sensor->data; + + const struct sensing_sensor_info *info = sqe->sqe.userdata; + + LOG_DBG("Trying to read %s [%d] type=%d", info->info->dev->name, + (int)(info - STRUCT_SECTION_START(sensing_sensor_info)), info->type); + + int rc = sensor_read(data->oneshot_iodev, &sensing_rtio_ctx, sqe->sqe.userdata); + + if (rc == 0) { + rtio_iodev_sqe_ok(sqe, 0); + } else { + rtio_iodev_sqe_err(sqe, rc); + } + return rc; +} + +SENSING_DMEM static const struct sensor_driver_api sensor_pipe_api = { .attr_set = attribute_set, .attr_get = NULL, .get_decoder = NULL, - .submit = NULL, + .submit = submit, }; static int sensing_sensor_pipe_init(const struct device *dev) @@ -45,7 +70,12 @@ static int sensing_sensor_pipe_init(const struct device *dev) static const struct sensor_pipe_config cfg_##inst = { \ .parent_info = &SENSOR_INFO_DT_NAME(DT_INST_PHANDLE(inst, dev)), \ }; \ - SENSING_SENSOR_DT_INST_DEFINE(inst, sensing_sensor_pipe_init, NULL, NULL, &cfg_##inst, \ - APPLICATION, 10, &sensor_pipe_api); + SENSOR_DT_READ_IODEV(underlying_reader_##inst, DT_INST_PHANDLE(inst, dev), \ + SENSOR_CHAN_ALL); \ + static struct sensor_pipe_data data_##inst = { \ + .oneshot_iodev = &underlying_reader_##inst, \ + }; \ + SENSING_SENSOR_DT_INST_DEFINE(inst, sensing_sensor_pipe_init, NULL, &data_##inst, \ + &cfg_##inst, APPLICATION, 10, &sensor_pipe_api); DT_INST_FOREACH_STATUS_OKAY(SENSING_PIPE_INIT) diff --git a/subsys/sensing/src/shell.c b/subsys/sensing/src/shell.c index eea8b2773f912e..8070abfcf0d9c1 100644 --- a/subsys/sensing/src/shell.c +++ b/subsys/sensing/src/shell.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #define SENSING_INFO_HELP "Get sensor info, such as vendor and model name, for all sensors." @@ -13,7 +15,57 @@ #define SENSING_CONFIG_HELP \ "Configure an existing connection:\n" \ - " " + " [ ... " \ + "]" + +static const char *mode_string_map[] = { + [SENSING_SENSOR_MODE_CONTINUOUS] = "continuous", + [SENSING_SENSOR_MODE_ONE_SHOT] = "one_shot", + [SENSING_SENSOR_MODE_PASSIVE_CONTINUOUS] = "passive_continuous", + [SENSING_SENSOR_MODE_PASSIVE_ONE_SHOT] = "passive_one_shot", + [SENSING_SENSOR_MODE_DONE] = "done", +}; + +static int parse_sensor_mode(const char *arg, enum sensing_sensor_mode *mode) +{ + for (int i = 0; i < ARRAY_SIZE(mode_string_map); ++i) { + if (strcmp(mode_string_map[i], arg) == 0) { + *mode = i; + return 0; + } + } + return -1; +} + +static const char *sensor_attribute_name[SENSOR_ATTR_COMMON_COUNT] = { + [SENSOR_ATTR_SAMPLING_FREQUENCY] = "sampling_frequency", + [SENSOR_ATTR_LOWER_THRESH] = "lower_thresh", + [SENSOR_ATTR_UPPER_THRESH] = "upper_thresh", + [SENSOR_ATTR_SLOPE_TH] = "slope_th", + [SENSOR_ATTR_SLOPE_DUR] = "slope_dur", + [SENSOR_ATTR_HYSTERESIS] = "hysteresis", + [SENSOR_ATTR_OVERSAMPLING] = "oversampling", + [SENSOR_ATTR_FULL_SCALE] = "full_scale", + [SENSOR_ATTR_OFFSET] = "offset", + [SENSOR_ATTR_CALIB_TARGET] = "calib_target", + [SENSOR_ATTR_CONFIGURATION] = "configuration", + [SENSOR_ATTR_CALIBRATION] = "calibration", + [SENSOR_ATTR_FEATURE_MASK] = "feature_mask", + [SENSOR_ATTR_ALERT] = "alert", + [SENSOR_ATTR_FF_DUR] = "ff_dur", + [SENSOR_ATTR_FIFO_WATERMARK] = "fifo_wm", +}; + +static int parse_sensor_attribute(const char *arg, enum sensor_attribute *attr) +{ + for (int i = 0; i < ARRAY_SIZE(sensor_attribute_name); ++i) { + if (strcmp(sensor_attribute_name[i], arg) == 0) { + *attr = i; + return 0; + } + } + return -1; +} #define SENSOR_TYPE_TO_STRING(type) \ case type: \ @@ -72,11 +124,19 @@ static int cmd_get_sensor_info(const struct shell *sh, size_t argc, char **argv) struct shell_cmd_connection { sensing_sensor_handle_t handle; bool is_used; + char shell_name[5]; }; static struct shell_cmd_connection open_connections[CONFIG_SENSING_MAX_CONNECTIONS]; +static void sensing_shell_on_data_event(sensing_sensor_handle_t handle, const void *data) +{ + const struct sensing_sensor_info *info = sensing_get_sensor_info(handle); + + printk("Got data for '%s' at %p\n", get_sensor_type_string(info->type), data); +} + static const struct sensing_callback_list callback_list = { - .on_data_event = NULL, + .on_data_event = sensing_shell_on_data_event, }; static int cmd_open_connection(const struct shell *sh, size_t argc, char **argv) @@ -137,7 +197,8 @@ static int cmd_open_connection(const struct shell *sh, size_t argc, char **argv) } open_connections[connection_idx].is_used = true; - shell_print(sh, "New connection [%d] to sensor [%ld] created", connection_idx, sensor_index); + shell_print(sh, "New connection [%d] to sensor [%ld] created", connection_idx, + sensor_index); return 0; } @@ -211,6 +272,7 @@ static int parse_sensor_value(const struct shell *sh, const char *val_str, q31_t static int cmd_config(const struct shell *sh, size_t argc, char **argv) { + int rc; char *endptr; long connection_index = strtol(argv[1], &endptr, 0); @@ -221,25 +283,36 @@ static int cmd_config(const struct shell *sh, size_t argc, char **argv) return -EINVAL; } - enum sensor_attribute attribute; - if (strcmp("sampling_frequency", argv[2]) == 0) { - attribute = SENSOR_ATTR_SAMPLING_FREQUENCY; - } else { - shell_error(sh, "Invalid attribute '%s'", argv[2]); + enum sensing_sensor_mode mode; + rc = parse_sensor_mode(argv[2], &mode); + if (rc != 0) { + shell_error(sh, "Invalid mode '%s'", argv[2]); return -EINVAL; } - struct sensing_sensor_attribute config = { - .attribute = attribute, - }; - int rc = parse_sensor_value(sh, argv[3], &config.value, &config.shift); - - if (rc != 0) { - shell_error(sh, "Invalid value '%s'", argv[3]); + int config_count = 0; + struct sensing_sensor_attribute configs[4] = {0}; + if (argc % 2 == 0) { + shell_error(sh, "Invalid config, must use pairs of "); return -EINVAL; } + for (int i = 3; i < argc; i += 2) { + rc = parse_sensor_attribute(argv[i], &configs[config_count].attribute); + if (rc != 0) { + shell_error(sh, "Invalid attribute '%s'", argv[i]); + return -EINVAL; + } + rc = parse_sensor_value(sh, argv[i + 1], &configs[config_count].value, + &configs[config_count].shift); + if (rc != 0) { + shell_error(sh, "Invalid value '%s'", argv[i + 1]); + return -EINVAL; + } + config_count++; + } - rc = sensing_set_attributes(open_connections[connection_index].handle, &config, 1); + rc = sensing_set_attributes(open_connections[connection_index].handle, mode, configs, + config_count); if (rc != 0) { shell_error(sh, "Failed to set attribute '%s' to '%s'", argv[2], argv[3]); return rc; @@ -247,10 +320,98 @@ static int cmd_config(const struct shell *sh, size_t argc, char **argv) return 0; } +static void sensing_node_index_get(size_t idx, struct shell_static_entry *entry) +{ + size_t count; + + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; + + STRUCT_SECTION_START_EXTERN(sensing_sensor_info); + STRUCT_SECTION_COUNT(sensing_sensor_info, &count); + if (idx >= count || idx > 9999) { + return; + } + snprintk(STRUCT_SECTION_START(sensing_sensor_info)[idx].shell_name, 5, "%d", (int)idx); + entry->syntax = STRUCT_SECTION_START(sensing_sensor_info)[idx].shell_name; +} +SHELL_DYNAMIC_CMD_CREATE(dsub_node_index, sensing_node_index_get); + +static void sensing_connection_node_index_get(size_t idx, struct shell_static_entry *entry, + const union shell_cmd_entry *subcmd) +{ + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; + + if (idx >= ARRAY_SIZE(open_connections) || !open_connections[idx].is_used) { + return; + } + + snprintk(open_connections[idx].shell_name, 5, "%d", (int)idx); + entry->syntax = open_connections[idx].shell_name; + entry->subcmd = subcmd; +} + +static void sensing_connection_node_index_get_for_close(size_t idx, + struct shell_static_entry *entry) +{ + sensing_connection_node_index_get(idx, entry, NULL); +} +SHELL_DYNAMIC_CMD_CREATE(dsub_connection_node_index_for_close, + sensing_connection_node_index_get_for_close); + +// static void sensing_attr_for_config(size_t idx, struct shell_static_entry *entry); +// SHELL_DYNAMIC_CMD_CREATE(dsub_sensor_attr_for_config, sensing_attr_for_config); +// +// static void sensing_attr_val_for_config(size_t idx, struct shell_static_entry *entry) +//{ +// entry->syntax = NULL; +// entry->subcmd = &dsub_sensor_attr_for_config; +// } +// SHELL_DYNAMIC_CMD_CREATE(dsub_sensor_attr_val_for_config, sensing_attr_val_for_config); +// +// static void sensing_attr_for_config(size_t idx, struct shell_static_entry *entry) +//{ +// if (idx >= ARRAY_SIZE(sensor_attribute_name)) { +// entry->syntax = NULL; +// return; +// } +// +// entry->syntax = sensor_attribute_name[idx]; +// entry->subcmd = &dsub_sensor_attr_val_for_config; +// } + +static void sensing_sensor_mode_for_config(size_t idx, struct shell_static_entry *entry) +{ + if (idx >= ARRAY_SIZE(mode_string_map)) { + entry->syntax = NULL; + return; + } + + entry->syntax = mode_string_map[idx]; + entry->subcmd = NULL; //&dsub_sensor_attr_for_config; +} +SHELL_DYNAMIC_CMD_CREATE(dsub_sensor_mode_for_config, sensing_sensor_mode_for_config); + +static void sensing_connection_node_index_get_for_config(size_t idx, + struct shell_static_entry *entry) +{ + sensing_connection_node_index_get(idx, entry, &dsub_sensor_mode_for_config); +} +SHELL_DYNAMIC_CMD_CREATE(dsub_connection_node_index_for_config, + sensing_connection_node_index_get_for_config); + SHELL_STATIC_SUBCMD_SET_CREATE( sub_sensing, SHELL_CMD_ARG(info, NULL, SENSING_INFO_HELP, cmd_get_sensor_info, 1, 0), - SHELL_CMD_ARG(open, NULL, SENSING_OPEN_HELP, cmd_open_connection, 1, 1), - SHELL_CMD_ARG(close, NULL, SENSING_CLOSE_HELP, cmd_close_connection, 2, 0), - SHELL_CMD_ARG(config, NULL, SENSING_CONFIG_HELP, cmd_config, 4, 0), SHELL_SUBCMD_SET_END); + SHELL_CMD_ARG(open, &dsub_node_index, SENSING_OPEN_HELP, cmd_open_connection, 1, 1), + SHELL_CMD_ARG(close, &dsub_connection_node_index_for_close, SENSING_CLOSE_HELP, + cmd_close_connection, 2, 0), + SHELL_CMD_ARG(config, &dsub_connection_node_index_for_config, SENSING_CONFIG_HELP, + cmd_config, 3, 11), + SHELL_SUBCMD_SET_END); SHELL_CMD_REGISTER(sensing, &sub_sensing, "Sensing subsystem commands", NULL); diff --git a/subsys/sensing/src/userspace.c b/subsys/sensing/src/userspace.c index f24550bd915467..486814808093b1 100644 --- a/subsys/sensing/src/userspace.c +++ b/subsys/sensing/src/userspace.c @@ -2,9 +2,12 @@ // Created by peress on 29/06/23. // +#include +#include #include #include -#include + +LOG_MODULE_REGISTER(sensing_userspace, CONFIG_SENSING_LOG_LEVEL); K_APPMEM_PARTITION_DEFINE(sensing_mem_partition); @@ -14,9 +17,15 @@ static int sensing_mem_init(void) rc = k_mem_domain_add_partition(&k_mem_domain_default, &sensing_mem_partition); if (rc != 0) { + LOG_ERR("Failed to add sensing memory partition to the default domain"); + return rc; + } + rc = k_mem_domain_add_partition(&k_mem_domain_default, &rtio_partition); + if (rc != 0) { + LOG_ERR("Failed to add rtio partition to the default domain"); return rc; } - return k_mem_domain_add_partition(&k_mem_domain_default, &rtio_partition); + return 0; } SYS_INIT(sensing_mem_init, POST_KERNEL, 99); From 0f773221fdd875c1a79264e3a03a636dad0fcf57 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Tue, 11 Jul 2023 02:05:38 -0600 Subject: [PATCH 09/10] Implement angle sensor --- cmake/linker_script/common/common-ram.cmake | 1 + drivers/sensor/icm42688/icm42688_decoder.c | 18 +- drivers/sensor/icm42688/icm42688_rtio.c | 2 +- .../sensing/sensing,accel-based-angle.yaml | 21 ++ dts/bindings/sensing/sensing,emul.yaml | 39 +++ dts/bindings/vendor-prefixes.txt | 1 + include/zephyr/sensing/datatypes.h | 11 +- include/zephyr/sensing/sensing.h | 5 +- include/zephyr/sensing/sensor.h | 24 +- .../sensor_shell/boards/tdk_robokit1.conf | 1 + .../sensor_shell/boards/tdk_robokit1.overlay | 17 +- samples/sensor/sensor_shell/prj.conf | 8 +- scripts/build/gen_kobject_list.py | 3 +- subsys/sensing/CMakeLists.txt | 3 + subsys/sensing/Kconfig | 4 +- .../include/sensing/internal/sensing.h | 17 +- subsys/sensing/sections.ld | 3 + subsys/sensing/src/processing.c | 142 +++++++- subsys/sensing/src/sensor_arbitrate.c | 6 +- subsys/sensing/src/sensor_connections.c | 35 +- subsys/sensing/src/sensor_pipe.c | 9 +- subsys/sensing/src/shell.c | 89 ++++- subsys/sensing/src/userspace.c | 7 + subsys/sensing/vsensors/CMakeLists.txt | 2 + subsys/sensing/vsensors/Kconfig | 10 + .../vsensors/accel-based-angle/CMakeLists.txt | 2 + .../vsensors/accel-based-angle/driver.c | 321 ++++++++++++++++++ subsys/sensing/vsensors/emul/CMakeLists.txt | 3 + subsys/sensing/vsensors/emul/driver.c | 254 ++++++++++++++ .../zephyr/sensing/vsensors/emul/emul.h | 12 + tests/subsys/sensing/boards/native_posix.conf | 1 + tests/subsys/sensing/src/test_arbitration.c | 6 +- tests/subsys/sensing/src/test_connections.c | 12 +- 33 files changed, 1021 insertions(+), 68 deletions(-) create mode 100644 dts/bindings/sensing/sensing,accel-based-angle.yaml create mode 100644 dts/bindings/sensing/sensing,emul.yaml create mode 100644 subsys/sensing/sections.ld create mode 100644 subsys/sensing/vsensors/CMakeLists.txt create mode 100644 subsys/sensing/vsensors/Kconfig create mode 100644 subsys/sensing/vsensors/accel-based-angle/CMakeLists.txt create mode 100644 subsys/sensing/vsensors/accel-based-angle/driver.c create mode 100644 subsys/sensing/vsensors/emul/CMakeLists.txt create mode 100644 subsys/sensing/vsensors/emul/driver.c create mode 100644 subsys/sensing/vsensors/emul/include/zephyr/sensing/vsensors/emul/emul.h create mode 100644 tests/subsys/sensing/boards/native_posix.conf diff --git a/cmake/linker_script/common/common-ram.cmake b/cmake/linker_script/common/common-ram.cmake index b625ac9daa58bc..cee07d8d834606 100644 --- a/cmake/linker_script/common/common-ram.cmake +++ b/cmake/linker_script/common/common-ram.cmake @@ -56,6 +56,7 @@ endif() if(CONFIG_SENSING) zephyr_iterable_section(NAME sensing_sensor GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) + zephyr_iterable_section(NAME sensing_connection GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) endif() if(CONFIG_UART_MUX) diff --git a/drivers/sensor/icm42688/icm42688_decoder.c b/drivers/sensor/icm42688/icm42688_decoder.c index 2d10220ecef5de..037281f3e1b193 100644 --- a/drivers/sensor/icm42688/icm42688_decoder.c +++ b/drivers/sensor/icm42688/icm42688_decoder.c @@ -23,16 +23,16 @@ static int icm42688_get_shift(enum sensor_channel channel, int accel_fs, int gyr case SENSOR_CHAN_ACCEL_Z: switch (accel_fs) { case ICM42688_ACCEL_FS_2G: - *shift = 5; + *shift = 4; return 0; case ICM42688_ACCEL_FS_4G: - *shift = 6; + *shift = 5; return 0; case ICM42688_ACCEL_FS_8G: - *shift = 7; + *shift = 6; return 0; case ICM42688_ACCEL_FS_16G: - *shift = 8; + *shift = 7; return 0; default: return -EINVAL; @@ -132,12 +132,9 @@ int icm42688_convert_raw_to_q31(struct icm42688_cfg *cfg, enum sensor_channel ch default: return -ENOTSUP; } + intermediate = ((int64_t)whole * INT64_C(1000000) + fraction); - if (shift < 0) { - intermediate = intermediate * INT32_MAX * (1 << -shift) / INT64_C(1000000); - } else if (shift > 0) { - intermediate = intermediate * INT32_MAX / (((1 << shift) - 1) * INT64_C(1000000)); - } + intermediate = intermediate * ((INT64_C(1) << (31 - shift)) - 1) / INT64_C(1000000); *out = CLAMP(intermediate, INT32_MIN, INT32_MAX); return 0; @@ -191,6 +188,9 @@ static uint8_t icm42688_encode_channel(enum sensor_channel chan) BIT(icm42688_get_channel_position(SENSOR_CHAN_GYRO_Y)) | BIT(icm42688_get_channel_position(SENSOR_CHAN_GYRO_Z)); break; + case SENSOR_CHAN_ALL: + encode_bmask = 0x7f; + break; default: break; } diff --git a/drivers/sensor/icm42688/icm42688_rtio.c b/drivers/sensor/icm42688/icm42688_rtio.c index 1d70aadfd53413..ec19260fd030eb 100644 --- a/drivers/sensor/icm42688/icm42688_rtio.c +++ b/drivers/sensor/icm42688/icm42688_rtio.c @@ -203,7 +203,7 @@ static void icm42688_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, v read_len = pkts * packet_size; ((struct icm42688_fifo_data *)buf)->fifo_count = read_len; - __ASSERT_NO_MSG(read_len % pkt_size == 0); + __ASSERT_NO_MSG(read_len % packet_size == 0); uint8_t *read_buf = buf + sizeof(hdr); diff --git a/dts/bindings/sensing/sensing,accel-based-angle.yaml b/dts/bindings/sensing/sensing,accel-based-angle.yaml new file mode 100644 index 00000000000000..f3e223d3c7ed9e --- /dev/null +++ b/dts/bindings/sensing/sensing,accel-based-angle.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: Accelerometer based lid angle virtual sensor + +compatible: "sensing,accel-based-angle" + +include: [sensor-device.yaml, base.yaml] + +properties: + plane0: + type: phandle + required: true + description: | + Node owning the sensing_sensor_info for the first plane's accelerometer + + plane1: + type: phandle + required: true + description: | + Node owning the sensing_sensor_info for the second plane's accelerometer diff --git a/dts/bindings/sensing/sensing,emul.yaml b/dts/bindings/sensing/sensing,emul.yaml new file mode 100644 index 00000000000000..de910a2f1c8602 --- /dev/null +++ b/dts/bindings/sensing/sensing,emul.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: Emulated virtual sensor + +compatible: "sensing,emul" + +include: [sensor-device.yaml, base.yaml] + +properties: + + sensor-types: + type: array + required: true + description: | + One or more sensor data types that are provided by this device. For + example, a 'dev' pointing to a bmi160 may report accel/gyro/die_temp or + any subset of those types. + + rotation-matrix: + type: array + description: | + 3x3 matrix to rotation x, y, and z axes. + In order to make application logic agnostic to how the device was placed + on the board, it's possible to enter the rotation matrix which will be + applied to every sample produced by this sensor. The final orientation + will be: + * X-axis is horizontal and positive toward the right + * Y-axis is vertical and positive toward the top + * Z-axis is depth and positive toward the user + + If not provided, the rotation matrix will be the identity matrix. + Otherwise, the following will be used: + + +- -+ +- -+ +- -+ + | v1 v2 v3 | | sensor_X | = | X | + | v4 v5 v6 | * | sensor_Y | = | Y | + | v7 v8 v9 | | sensor_Z | = | Z | + +- -+ +- -+ +- -+ diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index c70b9b6e0537ae..4c4e25bdb5c808 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -531,6 +531,7 @@ segger SEGGER Microcontroller GmbH seeed Seeed Technology Co., Ltd seirobotics Shenzhen SEI Robotics Co., Ltd semtech Semtech Corporation +sensing Zephyr Sensing Subsystem sensirion Sensirion AG sensortek Sensortek Technology Corporation sff Small Form Factor Committee diff --git a/include/zephyr/sensing/datatypes.h b/include/zephyr/sensing/datatypes.h index 3549aab4bdb692..aa9ce1858eeb1d 100644 --- a/include/zephyr/sensing/datatypes.h +++ b/include/zephyr/sensing/datatypes.h @@ -64,18 +64,25 @@ struct sensing_sensor_value_header { * SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D, * q31 version */ -struct sensing_sensor_value_3d_q31 { +struct sensing_sensor_three_axis_data { struct sensing_sensor_value_header header; int8_t shift; struct { uint32_t timestamp_delta; union { + q31_t values[3]; q31_t v[3]; struct { q31_t x; q31_t y; q31_t z; }; + q31_t bias[3]; + struct { + q31_t x_bias; + q31_t y_bias; + q31_t z_bias; + }; }; } readings[1]; }; @@ -98,7 +105,7 @@ struct sensing_sensor_value_uint32 { * struct sensing_sensor_value_q31 can be used by SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE sensor * q31 version */ -struct sensing_sensor_value_q31 { +struct sensing_sensor_float_data { int8_t shift; struct sensing_sensor_value_header header; struct { diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index f1791edb250c26..c8c296ba2dbbf6 100644 --- a/include/zephyr/sensing/sensing.h +++ b/include/zephyr/sensing/sensing.h @@ -166,7 +166,7 @@ typedef void *sensing_sensor_handle_t; * * @param buf The data buffer with sensor data. */ -typedef void (*sensing_data_event_t)(sensing_sensor_handle_t handle, const void *buf); +typedef void (*sensing_data_event_t)(sensing_sensor_handle_t handle, const void *buf, void *userdata); #include /** @@ -232,7 +232,8 @@ int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **inf */ int sensing_open_sensor(const struct sensing_sensor_info *info, const struct sensing_callback_list *cb_list, - sensing_sensor_handle_t *handle); + sensing_sensor_handle_t *handle, + void *userdata); /** * @brief Close sensor instance. diff --git a/include/zephyr/sensing/sensor.h b/include/zephyr/sensing/sensor.h index f9403961fcf3a9..ced2455e339a7b 100644 --- a/include/zephyr/sensing/sensor.h +++ b/include/zephyr/sensing/sensor.h @@ -11,18 +11,36 @@ #include #include +struct sensing_connection { + const struct sensing_sensor_info *info; + const struct sensing_callback_list *cb_list; + void *userdata; + enum sensing_sensor_mode mode; + q31_t attributes[SENSOR_ATTR_COMMON_COUNT]; + uint32_t attribute_mask; +} __packed __aligned(4); + +#define SENSING_CONNECTION_DT_DEFINE(node_id, target_node_id, type, _cb_list) \ + SENSING_DMEM STRUCT_SECTION_ITERABLE(sensing_connection, node_id##_sensing_connection) = { \ + .info = SENSING_SENSOR_INFO_GET(target_node_id, type), \ + .cb_list = (_cb_list), \ + } + +STRUCT_SECTION_START_EXTERN(sensing_connection); +STRUCT_SECTION_END_EXTERN(sensing_connection); + #define SENSING_SENSOR_INFO_DT_NAME(node_id, type) \ _CONCAT(_CONCAT(__sensing_sensor_info_, DEVICE_DT_NAME_GET(node_id)), type) #define SENSING_SENSOR_INFO_INST_DEFINE_NAMED(node_id, name, prop, idx, _iodev) \ - IF_ENABLED(CONFIG_SENSING_SHELL, (static char node_id##_##idx##_name_buffer[5];)) \ + IF_ENABLED(CONFIG_SENSING_SHELL, (static char node_id##_##idx##_name_buffer[5];)) \ const STRUCT_SECTION_ITERABLE(sensing_sensor_info, name) = { \ .info = &SENSOR_INFO_DT_NAME(DT_PHANDLE(node_id, dev)), \ .dev = DEVICE_DT_GET(node_id), \ .type = DT_PROP_BY_IDX(node_id, prop, idx), \ .iodev = &(_iodev), \ - IF_ENABLED(CONFIG_SENSING_SHELL, (.shell_name = node_id##_##idx##_name_buffer, )) \ - }; + IF_ENABLED(CONFIG_SENSING_SHELL, \ + (.shell_name = node_id##_##idx##_name_buffer, ))}; #define SENSING_SENSOR_INFO_INST_DEFINE(node_id, prop, idx, _iodev) \ SENSING_SENSOR_INFO_INST_DEFINE_NAMED( \ diff --git a/samples/sensor/sensor_shell/boards/tdk_robokit1.conf b/samples/sensor/sensor_shell/boards/tdk_robokit1.conf index aee20b8b10049c..0d027a28490b74 100644 --- a/samples/sensor/sensor_shell/boards/tdk_robokit1.conf +++ b/samples/sensor/sensor_shell/boards/tdk_robokit1.conf @@ -1,3 +1,4 @@ # Copyright (c) 2023 Google LLC # SPDX-License-Identifier: Apache-2.0 CONFIG_SPI_RTIO=y +CONFIG_CMSIS_DSP=y diff --git a/samples/sensor/sensor_shell/boards/tdk_robokit1.overlay b/samples/sensor/sensor_shell/boards/tdk_robokit1.overlay index 45841a4c1fc40d..b7a4319004066d 100644 --- a/samples/sensor/sensor_shell/boards/tdk_robokit1.overlay +++ b/samples/sensor/sensor_shell/boards/tdk_robokit1.overlay @@ -5,10 +5,25 @@ #include / { - accelgyro: accelgyro { + lidaccel: accelgyro { compatible = "zephyr,sensing-pipe"; status = "okay"; + friendly-name = "Lid accel"; dev = <&icm42688>; sensor-types = ; }; + + baseaccel: accelemul { + compatible = "sensing,emul"; + status = "okay"; + friendly-name = "Base accel"; + sensor-types = ; + }; + + angle: angle { + compatible = "sensing,accel-based-angle"; + status = "okay"; + plane0 = <&lidaccel>; + plane1 = <&baseaccel>; + }; }; diff --git a/samples/sensor/sensor_shell/prj.conf b/samples/sensor/sensor_shell/prj.conf index 0e6ac047463ce6..8a1b8c78ae234d 100644 --- a/samples/sensor/sensor_shell/prj.conf +++ b/samples/sensor/sensor_shell/prj.conf @@ -7,9 +7,9 @@ CONFIG_SENSOR_INFO=y CONFIG_LOG=y CONFIG_RTIO_CONSUME_SEM=y -CONFIG_USERSPACE=y +# CONFIG_USERSPACE=y CONFIG_SENSING=y CONFIG_SENSING_SHELL=y -CONFIG_RTIO_LOG_LEVEL_DBG=y -CONFIG_SENSOR_LOG_LEVEL_DBG=y -CONFIG_SENSING_LOG_LEVEL_DBG=y +# CONFIG_RTIO_LOG_LEVEL_DBG=y +# CONFIG_SENSOR_LOG_LEVEL_DBG=y +# CONFIG_SENSING_LOG_LEVEL_DBG=y diff --git a/scripts/build/gen_kobject_list.py b/scripts/build/gen_kobject_list.py index 64524c67499d52..92d7aa75d705da 100755 --- a/scripts/build/gen_kobject_list.py +++ b/scripts/build/gen_kobject_list.py @@ -114,7 +114,8 @@ ("ztest_test_rule", ("CONFIG_ZTEST_NEW_API", True, False)), ("rtio", ("CONFIG_RTIO", False, False)), ("rtio_iodev", ("CONFIG_RTIO", False, False)), - ("sensor_decoder_api", ("CONFIG_SENSOR_ASYNC_API", True, False)) + ("sensor_decoder_api", ("CONFIG_SENSOR_ASYNC_API", True, False)), + ("sensing_connection", ("CONFIG_SENSING", True, False)) ]) def kobject_to_enum(kobj): diff --git a/subsys/sensing/CMakeLists.txt b/subsys/sensing/CMakeLists.txt index 1d19a3c49e4185..3c4541c22e370d 100644 --- a/subsys/sensing/CMakeLists.txt +++ b/subsys/sensing/CMakeLists.txt @@ -12,3 +12,6 @@ zephyr_library_sources_ifdef(CONFIG_SENSING_SHELL src/shell.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE src/userspace.c) zephyr_library_include_directories(include) +add_subdirectory(vsensors) + +zephyr_linker_sources(DATA_SECTIONS sections.ld) diff --git a/subsys/sensing/Kconfig b/subsys/sensing/Kconfig index c73ac89183e014..2b5232108d78eb 100644 --- a/subsys/sensing/Kconfig +++ b/subsys/sensing/Kconfig @@ -16,7 +16,9 @@ module = SENSING module-str = sensing source "subsys/logging/Kconfig.template.log_config" -config SENSING_MAX_CONNECTIONS +source "subsys/sensing/vsensors/Kconfig" + +config SENSING_MAX_DYNAMIC_CONNECTIONS int "Maximum number of simultaneous open connections" default 10 help diff --git a/subsys/sensing/include/sensing/internal/sensing.h b/subsys/sensing/include/sensing/internal/sensing.h index 15a5ed9177d8e2..a3cf674bb9832a 100644 --- a/subsys/sensing/include/sensing/internal/sensing.h +++ b/subsys/sensing/include/sensing/internal/sensing.h @@ -6,23 +6,18 @@ #define ZEPHYR_SUBSYS_SENSING_INCLUDE_SENSING_INTERNAL_SENSING_H #include +#include #include #include #include -#define __SENSING_POOL_MASK_BUNDLE_COUNT \ - (DIV_ROUND_UP(DIV_ROUND_UP(CONFIG_SENSING_MAX_CONNECTIONS, 8), sizeof(uint32_t))) +#define __CONNECTION_POOL_COUNT \ + (STRUCT_SECTION_END(sensing_connection) - STRUCT_SECTION_START(sensing_connection)) -struct sensing_connection { - const struct sensing_sensor_info *info; - const struct sensing_callback_list *cb_list; - enum sensing_sensor_mode mode; - q31_t attributes[SENSOR_ATTR_COMMON_COUNT]; - uint32_t attribute_mask; -} __packed __aligned(4); +#define __SENSING_POOL_MASK_BUNDLE_COUNT \ + (DIV_ROUND_UP(DIV_ROUND_UP(__CONNECTION_POOL_COUNT, 8), sizeof(uint32_t))) extern struct sensing_connection_pool { - struct sensing_connection pool[CONFIG_SENSING_MAX_CONNECTIONS]; sys_bitarray_t *bitarray; struct sys_mutex *lock; } __sensing_connection_pool; @@ -35,7 +30,7 @@ static inline bool __sensing_is_connected(const struct sensing_sensor_info *info const struct sensing_connection *connection) { int is_set; - int connection_index = connection - __sensing_connection_pool.pool; + int connection_index = connection - STRUCT_SECTION_START(sensing_connection); int rc = sys_bitarray_test_bit(__sensing_connection_pool.bitarray, connection_index, &is_set); diff --git a/subsys/sensing/sections.ld b/subsys/sensing/sections.ld new file mode 100644 index 00000000000000..42bf0dd86957da --- /dev/null +++ b/subsys/sensing/sections.ld @@ -0,0 +1,3 @@ +#if defined(CONFIG_SENSING) + ITERABLE_SECTION_RAM(sensing_connection, 4) +#endif /* CONFIG_SENSING */ diff --git a/subsys/sensing/src/processing.c b/subsys/sensing/src/processing.c index ab001ae501219c..6f04399b82ca2b 100644 --- a/subsys/sensing/src/processing.c +++ b/subsys/sensing/src/processing.c @@ -12,6 +12,103 @@ LOG_MODULE_REGISTER(sensing_processing, CONFIG_SENSING_LOG_LEVEL); +static int decode_three_axis_data(int32_t type, struct sensing_sensor_three_axis_data *out, + const struct sensor_decoder_api *decoder, void *data) +{ + uint16_t frame_count; + int rc; + + rc = decoder->get_frame_count(data, &frame_count); + if (rc != 0) { + return rc; + } + + __ASSERT_NO_MSG(frame_count == 1); + LOG_DBG("Decoding 1 frame for 3 axis data from %p", data); + + sensor_frame_iterator_t fit = {0}; + sensor_channel_iterator_t cit = {0}; + enum sensor_channel channel; + q31_t value; + bool has_shift = false; + + while (true) { + rc = decoder->decode(data, &fit, &cit, &channel, &value, 1); + if (rc < 0) { + LOG_ERR("Failed to decode entry (%d)", rc); + return rc; + } + if (rc == 0) { + return 0; + } + switch (type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + case SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D: + if (channel == SENSOR_CHAN_ACCEL_X || channel == SENSOR_CHAN_ACCEL_Y || + channel == SENSOR_CHAN_ACCEL_Z) { + LOG_DBG("Got [%d] for accel type, value=0x%08x", (int)channel, value); + out->readings[0].values[channel] = value; + if (!has_shift) { + rc = decoder->get_shift(data, channel, &out->shift); + if (rc != 0) { + return rc; + } + has_shift = true; + LOG_DBG("Got shift value %d", out->shift); + } + } + break; + case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: + if (channel == SENSOR_CHAN_GYRO_X || channel == SENSOR_CHAN_GYRO_Y || + channel == SENSOR_CHAN_GYRO_Z) { + out->readings[0].values[channel - SENSOR_CHAN_GYRO_X] = value; + if (!has_shift) { + rc = decoder->get_shift(data, channel, &out->shift); + if (rc != 0) { + return rc; + } + has_shift = true; + } + } + break; + } + } +} + +static int decode_float_data(int32_t type, struct sensing_sensor_float_data *out, + const struct sensor_decoder_api *decoder, void *data) +{ + uint16_t frame_count; + int rc; + + rc = decoder->get_frame_count(data, &frame_count); + if (rc != 0) { + return rc; + } + + __ASSERT_NO_MSG(frame_count == 1); + + sensor_frame_iterator_t fit = {0}; + sensor_channel_iterator_t cit = {0}; + enum sensor_channel channel; + bool has_shift = false; + + while (true) { + rc = decoder->decode(data, &fit, &cit, &channel, &out->readings[0].v, 1); + if (rc <= 0) { + return rc; + } + if (type == SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE && + channel == SENSOR_CHAN_ROTATION && !has_shift) { + rc = decoder->get_shift(data, channel, &out->shift); + if (rc != 0) { + return rc; + } + has_shift = true; + } + } +} + static void processing_task(void *a, void *b, void *c) { struct sensing_sensor_info *info; @@ -53,9 +150,46 @@ static void processing_task(void *a, void *b, void *c) continue; } + const struct sensor_decoder_api *decoder = NULL; + + rc = sensor_get_decoder(info->dev, &decoder); + if (rc != 0) { + LOG_ERR("Failed to get decoder"); + goto end; + } + + union { + struct sensing_sensor_three_axis_data three_axis_data; + struct sensing_sensor_float_data float_data; + } decoded_data; + + switch (info->type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + case SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D: + case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: + rc = decode_three_axis_data(info->type, &decoded_data.three_axis_data, + decoder, data); + if (rc != 0) { + LOG_ERR("Failed to decode"); + goto end; + } + break; + case SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE: + rc = decode_float_data(info->type, &decoded_data.float_data, decoder, data); + if (rc != 0) { + LOG_ERR("Failed to decode"); + goto end; + } + break; + default: + LOG_ERR("Sensor type not supported"); + goto end; + } + sys_mutex_lock(__sensing_connection_pool.lock, K_FOREVER); - for (int i = 0; i < ARRAY_SIZE(__sensing_connection_pool.pool); ++i) { - struct sensing_connection *connection = &__sensing_connection_pool.pool[i]; + for (int i = 0; i < __CONNECTION_POOL_COUNT; ++i) { + struct sensing_connection *connection = + &STRUCT_SECTION_START(sensing_connection)[i]; if (!__sensing_is_connected(info, connection)) { continue; } @@ -64,11 +198,11 @@ static void processing_task(void *a, void *b, void *c) if (cb == NULL) { continue; } - /* TODO we actually need to decode the data first before this for loop */ - cb(connection, data); + cb(connection, &decoded_data, connection->userdata); } sys_mutex_unlock(__sensing_connection_pool.lock); + end: /* Release the memory */ rtio_release_buffer(&sensing_rtio_ctx, data, data_len); } diff --git a/subsys/sensing/src/sensor_arbitrate.c b/subsys/sensing/src/sensor_arbitrate.c index fae5276bef1e66..630d918e10fd5f 100644 --- a/subsys/sensing/src/sensor_arbitrate.c +++ b/subsys/sensing/src/sensor_arbitrate.c @@ -47,11 +47,11 @@ static void set_arbitrated_value(const struct device *dev, int32_t type, static int arbitrate_sensor_attribute(const struct sensing_sensor_info *info, enum sensor_attribute attribute) { - const struct sensing_connection *connections = __sensing_connection_pool.pool; + const struct sensing_connection *connections = STRUCT_SECTION_START(sensing_connection); int connection_count = 0; - q31_t value; + q31_t value = 0; - for (int i = 0; i < CONFIG_SENSING_MAX_CONNECTIONS; ++i) { + for (int i = 0; i < __CONNECTION_POOL_COUNT; ++i) { if (!__sensing_is_connected(info, &connections[i])) { continue; } diff --git a/subsys/sensing/src/sensor_connections.c b/subsys/sensing/src/sensor_connections.c index 71134e8581f699..9fdb2b5f56da22 100644 --- a/subsys/sensing/src/sensor_connections.c +++ b/subsys/sensing/src/sensor_connections.c @@ -12,16 +12,15 @@ LOG_MODULE_REGISTER(sensing_connect, CONFIG_SENSING_LOG_LEVEL); #define __HANDLE_TO_CONNECTION(name, handle) \ struct sensing_connection *name = handle; \ - __ASSERT_NO_MSG((uintptr_t)name >= (uintptr_t)__sensing_connection_pool.pool); \ - __ASSERT_NO_MSG((uintptr_t)name < (uintptr_t)__sensing_connection_pool.pool + \ - sizeof(__sensing_connection_pool.pool)) + __ASSERT_NO_MSG((uintptr_t)name >= (uintptr_t)STRUCT_SECTION_START(sensing_connection)); \ + __ASSERT_NO_MSG((uintptr_t)name < (uintptr_t)STRUCT_SECTION_END(sensing_connection)) SENSING_DMEM SYS_MUTEX_DEFINE(connection_lock); -SENSING_DMEM static uint32_t bitarray_bundles[__SENSING_POOL_MASK_BUNDLE_COUNT] = {0}; +SENSING_DMEM static uint32_t bitarray_bundles[4] = {0}; SENSING_DMEM static sys_bitarray_t bitarray = { - .num_bits = CONFIG_SENSING_MAX_CONNECTIONS, - .num_bundles = __SENSING_POOL_MASK_BUNDLE_COUNT, + .num_bits = ARRAY_SIZE(bitarray_bundles) * 32, + .num_bundles = ARRAY_SIZE(bitarray_bundles), .bundles = bitarray_bundles, }; @@ -30,16 +29,18 @@ SENSING_DMEM struct sensing_connection_pool __sensing_connection_pool = { .lock = &connection_lock, }; +STRUCT_SECTION_ITERABLE_ARRAY(sensing_connection, dynamic_connections, + CONFIG_SENSING_MAX_DYNAMIC_CONNECTIONS); + #define __lock sys_mutex_lock(__sensing_connection_pool.lock, K_FOREVER) #define __unlock sys_mutex_unlock(__sensing_connection_pool.lock) -RTIO_DEFINE_WITH_MEMPOOL(sensing_rtio_ctx, CONFIG_SENSING_MAX_CONNECTIONS, - CONFIG_SENSING_MAX_CONNECTIONS, CONFIG_SENSING_RTIO_BLOCK_COUNT, +RTIO_DEFINE_WITH_MEMPOOL(sensing_rtio_ctx, 32, 32, CONFIG_SENSING_RTIO_BLOCK_COUNT, CONFIG_SENSING_RTIO_BLOCK_SIZE, 4); int sensing_open_sensor(const struct sensing_sensor_info *info, const struct sensing_callback_list *cb_list, - sensing_sensor_handle_t *handle) + sensing_sensor_handle_t *handle, void *userdata) { struct sensing_connection *connection; size_t offset; @@ -50,19 +51,22 @@ int sensing_open_sensor(const struct sensing_sensor_info *info, __ASSERT_NO_MSG(handle != NULL); __lock; + bitarray.num_bits = __CONNECTION_POOL_COUNT; // TODO this should only happen once rc = sys_bitarray_alloc(__sensing_connection_pool.bitarray, 1, &offset); if (rc != 0) { __unlock; return rc; } - connection = &__sensing_connection_pool.pool[offset]; + LOG_DBG("Got offset %d/%d", (int)offset, (int)__CONNECTION_POOL_COUNT); + connection = &STRUCT_SECTION_START(sensing_connection)[offset]; LOG_DBG("Connection opened @ %p (size=%d) for info @ %p", connection, (int)sizeof(struct sensing_connection), info); memset(connection, 0, sizeof(struct sensing_connection)); connection->info = info; connection->cb_list = cb_list; + connection->userdata = userdata; *handle = connection; __unlock; return 0; @@ -76,9 +80,9 @@ int sensing_close_sensor(sensing_sensor_handle_t handle) __lock; if (__sensing_is_connected(NULL, connection)) { LOG_DBG("Releasing connection at %p/%d", handle, - connection - __sensing_connection_pool.pool); + connection - STRUCT_SECTION_START(sensing_connection)); rc = sys_bitarray_free(__sensing_connection_pool.bitarray, 1, - connection - __sensing_connection_pool.pool); + connection - STRUCT_SECTION_START(sensing_connection)); if (rc == 0) { __sensing_arbitrate(); } else { @@ -116,6 +120,9 @@ int sensing_set_attributes(sensing_sensor_handle_t handle, enum sensing_sensor_m rc = sensor_read(connection->info->iodev, &sensing_rtio_ctx, (void *)connection->info); break; + case SENSING_SENSOR_MODE_DONE: + rc = 0; + break; default: rc = -EINVAL; break; @@ -136,7 +143,9 @@ void sensing_reset_connections(void) __lock; sys_bitarray_clear_region(__sensing_connection_pool.bitarray, __sensing_connection_pool.bitarray->num_bits, 0); - memset(__sensing_connection_pool.pool, 0, sizeof(__sensing_connection_pool.pool)); + memset(STRUCT_SECTION_START(sensing_connection), 0, + (uintptr_t)STRUCT_SECTION_END(sensing_connection) - + (uintptr_t)STRUCT_SECTION_START(sensing_connection)); __sensing_arbitrate(); __unlock; } diff --git a/subsys/sensing/src/sensor_pipe.c b/subsys/sensing/src/sensor_pipe.c index c3b264bfbb0922..5977066a251722 100644 --- a/subsys/sensing/src/sensor_pipe.c +++ b/subsys/sensing/src/sensor_pipe.c @@ -51,10 +51,17 @@ static int submit(const struct device *sensor, struct rtio_iodev_sqe *sqe) return rc; } +static int get_decoder(const struct device *sensor, const struct sensor_decoder_api **api) +{ + const struct sensor_pipe_config *cfg = sensor->config; + + return sensor_get_decoder(cfg->parent_info->dev, api); +} + SENSING_DMEM static const struct sensor_driver_api sensor_pipe_api = { .attr_set = attribute_set, .attr_get = NULL, - .get_decoder = NULL, + .get_decoder = get_decoder, .submit = submit, }; diff --git a/subsys/sensing/src/shell.c b/subsys/sensing/src/shell.c index 8070abfcf0d9c1..6c7f08d09d79a5 100644 --- a/subsys/sensing/src/shell.c +++ b/subsys/sensing/src/shell.c @@ -76,6 +76,7 @@ static const char *get_sensor_type_string(int32_t type) switch (type) { SENSOR_TYPE_TO_STRING(SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D); SENSOR_TYPE_TO_STRING(SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D); + SENSOR_TYPE_TO_STRING(SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE); default: return "UNKNOWN"; } @@ -125,14 +126,92 @@ struct shell_cmd_connection { sensing_sensor_handle_t handle; bool is_used; char shell_name[5]; + const struct shell *owning_shell; }; -static struct shell_cmd_connection open_connections[CONFIG_SENSING_MAX_CONNECTIONS]; +static struct shell_cmd_connection open_connections[CONFIG_SENSING_MAX_DYNAMIC_CONNECTIONS]; -static void sensing_shell_on_data_event(sensing_sensor_handle_t handle, const void *data) +static void sensing_shell_print_three_axis_data(const struct shell *sh, + const struct sensing_sensor_info *info, + const struct sensing_sensor_three_axis_data *data) { + int64_t intermediate[] = { + (int64_t)data->readings[0].values[0], + (int64_t)data->readings[0].values[1], + (int64_t)data->readings[0].values[2], + }; + +// shell_info(sh, +// "%s: shift=%d, mask=0x%016" PRIx64 " (" +// "0x%08" PRIx32 "/0x%016" PRIx64 ", " +// "0x%08" PRIx32 "/0x%016" PRIx64 ", " +// "0x%08" PRIx32 "/0x%016" PRIx64 ")", +// get_sensor_type_string(info->type), data->shift, GENMASK64(63, 31), +// data->readings[0].values[0], intermediate[0], data->readings[0].values[1], +// intermediate[1], data->readings[0].values[2], intermediate[2]); + + intermediate[0] = (data->shift >= 0) ? (intermediate[0] << data->shift) + : (intermediate[0] >> -data->shift); + intermediate[1] = (data->shift >= 0) ? (intermediate[1] << data->shift) + : (intermediate[1] >> -data->shift); + intermediate[2] = (data->shift >= 0) ? (intermediate[2] << data->shift) + : (intermediate[2] >> -data->shift); + // shell_info(sh, + // "%s: %" PRIi32 ".%06" PRIu32 ", %" PRIi32 ".%06" PRIu32 ", %" PRIi32 + // ".%06" PRIu32, + // get_sensor_type_string(info->type), + // (int32_t)FIELD_GET(GENMASK64(63, 31), intermediate[0]), + // (uint32_t)((uint64_t)FIELD_GET(GENMASK64(30, 0), intermediate[0]) * + // INT64_C(1000000) / INT32_MAX), + // (int32_t)FIELD_GET(GENMASK64(63, 31), intermediate[1]), + // (uint32_t)((uint64_t)FIELD_GET(GENMASK64(30, 0), intermediate[1]) * + // INT64_C(1000000) / INT32_MAX), + // (int32_t)FIELD_GET(GENMASK64(63, 31), intermediate[2]), + // (uint32_t)((uint64_t)FIELD_GET(GENMASK64(30, 0), intermediate[2]) * + // INT64_C(1000000) / INT32_MAX)); + shell_info(sh, + "%s %" PRIi32 ".%06" PRIu32 ", %" PRIi32 ".%06" PRIu32 ", %" PRIi32 + ".%06" PRIu32, + get_sensor_type_string(info->type), (int32_t)(intermediate[0] / INT32_MAX), + (uint32_t)((intermediate[0] % INT32_MAX) * INT64_C(1000000) / INT32_MAX), + (int32_t)(intermediate[1] / INT32_MAX), + (uint32_t)((intermediate[1] % INT32_MAX) * INT64_C(1000000) / INT32_MAX), + (int32_t)(intermediate[2] / INT32_MAX), + (uint32_t)((intermediate[2] % INT32_MAX) * INT64_C(1000000) / INT32_MAX)); +} + +static void sensing_shell_print_float_data(const struct shell *sh, + const struct sensing_sensor_info *info, + const struct sensing_sensor_float_data *data) +{ + int64_t intermediate = (int64_t)data->readings[0].v; + + intermediate = + (data->shift >= 0) ? (intermediate << data->shift) : (intermediate >> -data->shift); + + shell_info(sh, "%s: %" PRIi32 ".%06" PRIu32, get_sensor_type_string(info->type), + (int32_t)(intermediate / INT32_MAX), + (uint32_t)((intermediate % INT32_MAX) * INT64_C(1000000) / INT32_MAX)); +} + +static void sensing_shell_on_data_event(sensing_sensor_handle_t handle, const void *data, + void *userdata) +{ + struct shell_cmd_connection *connection = userdata; const struct sensing_sensor_info *info = sensing_get_sensor_info(handle); - printk("Got data for '%s' at %p\n", get_sensor_type_string(info->type), data); + switch (info->type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + case SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D: + case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: + sensing_shell_print_three_axis_data(connection->owning_shell, info, data); + break; + case SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE: + sensing_shell_print_float_data(connection->owning_shell, info, data); + break; + default: + shell_info(connection->owning_shell, "Got data for '%s' at %p", + get_sensor_type_string(info->type), data); + } } static const struct sensing_callback_list callback_list = { @@ -189,7 +268,8 @@ static int cmd_open_connection(const struct shell *sh, size_t argc, char **argv) } rc = sensing_open_sensor(&sensors[sensor_index], &callback_list, - &open_connections[connection_idx].handle); + &open_connections[connection_idx].handle, + &open_connections[connection_idx]); if (rc != 0) { shell_error(sh, "Failed to open connection"); @@ -197,6 +277,7 @@ static int cmd_open_connection(const struct shell *sh, size_t argc, char **argv) } open_connections[connection_idx].is_used = true; + open_connections[connection_idx].owning_shell = sh; shell_print(sh, "New connection [%d] to sensor [%ld] created", connection_idx, sensor_index); diff --git a/subsys/sensing/src/userspace.c b/subsys/sensing/src/userspace.c index 486814808093b1..44b1b4f3de1606 100644 --- a/subsys/sensing/src/userspace.c +++ b/subsys/sensing/src/userspace.c @@ -7,6 +7,8 @@ #include #include +#include "sensing/internal/sensing.h" + LOG_MODULE_REGISTER(sensing_userspace, CONFIG_SENSING_LOG_LEVEL); K_APPMEM_PARTITION_DEFINE(sensing_mem_partition); @@ -15,6 +17,11 @@ static int sensing_mem_init(void) { int rc; + for (struct sensing_connection *ptr = STRUCT_SECTION_START(sensing_connection); + ptr < STRUCT_SECTION_END(sensing_connection); ++ptr) { + k_object_access_all_grant(ptr); + } + rc = k_mem_domain_add_partition(&k_mem_domain_default, &sensing_mem_partition); if (rc != 0) { LOG_ERR("Failed to add sensing memory partition to the default domain"); diff --git a/subsys/sensing/vsensors/CMakeLists.txt b/subsys/sensing/vsensors/CMakeLists.txt new file mode 100644 index 00000000000000..177f66e9f85d2d --- /dev/null +++ b/subsys/sensing/vsensors/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory_ifdef(CONFIG_SENSING_ACCEL_BASED_ANGLE accel-based-angle) +add_subdirectory_ifdef(CONFIG_SENSING_EMUL emul) diff --git a/subsys/sensing/vsensors/Kconfig b/subsys/sensing/vsensors/Kconfig new file mode 100644 index 00000000000000..e3284fb8bcbdb5 --- /dev/null +++ b/subsys/sensing/vsensors/Kconfig @@ -0,0 +1,10 @@ +config SENSING_ACCEL_BASED_ANGLE + bool + default y + depends on DT_HAS_SENSING_ACCEL_BASED_ANGLE_ENABLED + select DSP + +config SENSING_EMUL + bool + default y + depends on DT_HAS_SENSING_EMUL_ENABLED diff --git a/subsys/sensing/vsensors/accel-based-angle/CMakeLists.txt b/subsys/sensing/vsensors/accel-based-angle/CMakeLists.txt new file mode 100644 index 00000000000000..95cef32bf7b5de --- /dev/null +++ b/subsys/sensing/vsensors/accel-based-angle/CMakeLists.txt @@ -0,0 +1,2 @@ +zephyr_library() +zephyr_library_sources(driver.c) diff --git a/subsys/sensing/vsensors/accel-based-angle/driver.c b/subsys/sensing/vsensors/accel-based-angle/driver.c new file mode 100644 index 00000000000000..d91709618e29f2 --- /dev/null +++ b/subsys/sensing/vsensors/accel-based-angle/driver.c @@ -0,0 +1,321 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(accel_based_angle, CONFIG_SENSING_LOG_LEVEL); + +#define DT_DRV_COMPAT sensing_accel_based_angle +struct drv_config { + const struct sensing_sensor_info *plane0; + const struct sensing_sensor_info *plane1; +}; + +struct drv_data { + sensing_sensor_handle_t plane0; + sensing_sensor_handle_t plane1; + struct sensing_sensor_three_axis_data plane0_latest_sample; + struct sensing_sensor_three_axis_data plane1_latest_sample; + bool plane0_has_sample; + bool plane1_has_sample; + + struct rtio_iodev_sqe *pending_read; +}; + +static int attribute_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + struct drv_data *data = dev->data; + struct sensing_sensor_attribute attribute = { + .attribute = attr, + .value = 0, + .shift = 0, + }; + int rc; + + rc = sensing_set_attributes(data->plane0, SENSING_SENSOR_MODE_DONE, &attribute, 1); + if (rc != 0) { + LOG_ERR("Failed to set plane0 attribute"); + return rc; + } + rc = sensing_set_attributes(data->plane1, SENSING_SENSOR_MODE_DONE, &attribute, 1); + if (rc != 0) { + LOG_ERR("Failed to set plane1 attribute"); + return rc; + } + return rc; +} + +static int submit(const struct device *sensor, struct rtio_iodev_sqe *sqe) +{ + struct drv_data *data = sensor->data; + const struct sensor_read_config *read_cfg = sqe->sqe.iodev->data; + int rc; + + if (read_cfg->is_streaming) { + LOG_ERR("Streaming is not yet supported"); + rtio_iodev_sqe_err(sqe, -ENOTSUP); + return -ENOTSUP; + } + + rc = sensing_set_attributes(data->plane0, SENSING_SENSOR_MODE_ONE_SHOT, NULL, 0); + rc |= sensing_set_attributes(data->plane1, SENSING_SENSOR_MODE_ONE_SHOT, NULL, 0); + + if (rc != 0) { + rtio_iodev_sqe_err(sqe, rc); + LOG_ERR("Failed to initiate read"); + } else { + data->pending_read = sqe; + } + return 0; +} + +struct encoded_data { + uint64_t timestamp_ns; + int8_t shift; + q31_t val; +} __packed; + +static int decoder_get_frame_count(const uint8_t *buffer, uint16_t *frame_count) +{ + ARG_UNUSED(buffer); + *frame_count = 1; + return 0; +} + +static int decoder_get_timestamp(const uint8_t *buffer, uint64_t *timestamp_ns) +{ + *timestamp_ns = ((struct encoded_data *)buffer)->timestamp_ns; + return 0; +} + +static bool decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) +{ + ARG_UNUSED(buffer); + ARG_UNUSED(trigger); + return false; +} + +static int decoder_get_shift(const uint8_t *buffer, enum sensor_channel channel_type, int8_t *shift) +{ + ARG_UNUSED(buffer); + + if (channel_type != SENSOR_CHAN_ROTATION) { + return -EINVAL; + } + *shift = ((struct encoded_data *)buffer)->shift; + return 0; +} + +static int decoder_decode(const uint8_t *buffer, sensor_frame_iterator_t *fit, + sensor_channel_iterator_t *cit, enum sensor_channel *channels, + q31_t *values, uint8_t max_count) +{ + if (*fit != 0) { + return 0; + } + if (*cit > 0) { + return -EINVAL; + } + + values[0] = ((struct encoded_data *)buffer)->val; + channels[0] = SENSOR_CHAN_ROTATION; + *fit = 1; + *cit = 0; + return 1; +} + +SENSING_DMEM static const struct sensor_decoder_api decoder_api = { + .get_frame_count = decoder_get_frame_count, + .get_timestamp = decoder_get_timestamp, + .has_trigger = decoder_has_trigger, + .get_shift = decoder_get_shift, + .decode = decoder_decode, +}; + +static int get_decoder(const struct device *dev, const struct sensor_decoder_api **api) +{ + ARG_UNUSED(dev); + *api = &decoder_api; + return 0; +} + +SENSING_DMEM static const struct sensor_driver_api angle_api = { + .attr_set = attribute_set, + .attr_get = NULL, + .get_decoder = get_decoder, + .submit = submit, +}; + +static void on_data_event(sensing_sensor_handle_t handle, const void *buf, void *userdata) +{ + const struct device *dev = userdata; + struct drv_data *data = dev->data; + + if (handle == data->plane0) { + LOG_INF("Got data for plane0"); + memcpy(&data->plane0_latest_sample, buf, + sizeof(struct sensing_sensor_three_axis_data)); + data->plane0_has_sample = true; + } else if (handle == data->plane1) { + LOG_INF("Got data for plane1"); + memcpy(&data->plane1_latest_sample, buf, + sizeof(struct sensing_sensor_three_axis_data)); + data->plane1_has_sample = true; + } + + if (!data->plane0_has_sample || !data->plane1_has_sample) { + return; + } + + /* We have 2 samples */ + LOG_DBG("plane0(0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ")", + data->plane0_latest_sample.readings[0].x, data->plane0_latest_sample.readings[0].y, + data->plane0_latest_sample.readings[0].z); + LOG_DBG("plane1(0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ")", + data->plane1_latest_sample.readings[0].x, data->plane1_latest_sample.readings[0].y, + data->plane1_latest_sample.readings[0].z); + int8_t shift = MAX(data->plane0_latest_sample.shift, data->plane1_latest_sample.shift); + + /* Check that they both use the same shift */ + if (data->plane0_latest_sample.shift != data->plane1_latest_sample.shift) { + + if (data->plane0_latest_sample.shift != shift) { + int8_t new_shift = data->plane0_latest_sample.shift - shift; + data->plane0_latest_sample.readings[0].x = + (new_shift < 0) + ? (data->plane0_latest_sample.readings[0].x >> -new_shift) + : (data->plane0_latest_sample.readings[0].x << new_shift); + data->plane0_latest_sample.readings[0].y = + (new_shift < 0) + ? (data->plane0_latest_sample.readings[0].y >> -new_shift) + : (data->plane0_latest_sample.readings[0].y << new_shift); + data->plane0_latest_sample.readings[0].z = + (new_shift < 0) + ? (data->plane0_latest_sample.readings[0].z >> -new_shift) + : (data->plane0_latest_sample.readings[0].z << new_shift); + } + + if (data->plane1_latest_sample.shift != shift) { + int8_t new_shift = data->plane1_latest_sample.shift - shift; + data->plane1_latest_sample.readings[0].x = + (new_shift < 0) + ? (data->plane1_latest_sample.readings[0].x >> -new_shift) + : (data->plane1_latest_sample.readings[0].x << new_shift); + data->plane1_latest_sample.readings[0].y = + (new_shift < 0) + ? (data->plane1_latest_sample.readings[0].y >> -new_shift) + : (data->plane1_latest_sample.readings[0].y << new_shift); + data->plane1_latest_sample.readings[0].z = + (new_shift < 0) + ? (data->plane1_latest_sample.readings[0].z >> -new_shift) + : (data->plane1_latest_sample.readings[0].z << new_shift); + } + } + + LOG_DBG("plane0(0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ") (%d, %d, %d)", + data->plane0_latest_sample.readings[0].x, data->plane0_latest_sample.readings[0].y, + data->plane0_latest_sample.readings[0].z, data->plane0_latest_sample.readings[0].x, + data->plane0_latest_sample.readings[0].y, data->plane0_latest_sample.readings[0].z); + LOG_DBG("plane1(0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ") (%d, %d, %d)", + data->plane1_latest_sample.readings[0].x, data->plane1_latest_sample.readings[0].y, + data->plane1_latest_sample.readings[0].z, data->plane1_latest_sample.readings[0].x, + data->plane1_latest_sample.readings[0].y, data->plane1_latest_sample.readings[0].z); + + /* + * 5.27 x 5.27 = 10.54 + * 10.54 >> 14 = 24.40 + */ + q63_t result; + int32_t integer_part; + + zdsp_dot_prod_q31(data->plane0_latest_sample.readings[0].values, + data->plane1_latest_sample.readings[0].values, 3, &result); + integer_part = (int32_t)FIELD_GET(GENMASK64(63, 48 - shift * 2), result); + + LOG_DBG("Dot product is 0x%016" PRIx64 " %d.%06u shift=%d", result, integer_part, + (uint32_t)(FIELD_GET(GENMASK64(47 - shift * 2, 0), result) * INT64_C(1000000) / + ((INT64_C(1) << (48 - shift * 2)) - 1)), + shift); + + data->plane0_has_sample = false; + data->plane1_has_sample = false; + + uint8_t *out_buf; + uint32_t buf_len; + int rc = rtio_sqe_rx_buf(data->pending_read, sizeof(struct encoded_data), + sizeof(struct encoded_data), &out_buf, &buf_len); + if (rc != 0) { + rtio_iodev_sqe_err(data->pending_read, rc); + data->pending_read = NULL; + return; + } + + struct encoded_data *edata = (struct encoded_data *)out_buf; + edata->timestamp_ns = MAX(data->plane0_latest_sample.header.base_timestamp, + data->plane1_latest_sample.header.base_timestamp); + edata->shift = ilog2(llabs(integer_part)) + 1; + int8_t extra_shift = (47 - shift * 2) - (31 - edata->shift) + 1; + edata->val = FIELD_GET(GENMASK(31, 0), result >> extra_shift); + LOG_DBG("shift=%d, val=0x%08" PRIx32, edata->shift, edata->val); + rtio_iodev_sqe_ok(data->pending_read, 0); + data->pending_read = NULL; +} + +static const struct sensing_callback_list cb_list = { + .on_data_event = on_data_event, +}; + +static int init(const struct device *dev) +{ + const struct drv_config *cfg = dev->config; + struct drv_data *data = dev->data; + int rc; + + rc = sensing_open_sensor(cfg->plane0, &cb_list, &data->plane0, (void *)dev); + if (rc != 0) { + LOG_ERR("Failed to open connection to plane0"); + return rc; + } + + rc = sensing_open_sensor(cfg->plane1, &cb_list, &data->plane1, (void *)dev); + if (rc != 0) { + sensing_close_sensor(data->plane0); + LOG_ERR("Failed to open connection to plane1"); + return rc; + } + + return 0; +} + +#define DECLARE_IODEV(node_id, inst) \ + SENSOR_DT_READ_IODEV(read_iodev_##inst, node_id, SENSOR_CHAN_ALL); \ + IF_ENABLED(CONFIG_SENSING_SHELL, (static char name_buffer_##inst[5];)) \ + static struct sensor_info sensor_info_##inst = SENSOR_INFO_INITIALIZER( \ + DEVICE_DT_GET(node_id), DT_NODE_VENDOR_OR(node_id, NULL), \ + DT_NODE_MODEL_OR(node_id, NULL), DT_PROP_OR(node_id, friendly_name, NULL)); \ + const STRUCT_SECTION_ITERABLE(sensing_sensor_info, sensing_sensor_info_##inst) = { \ + .info = &sensor_info_##inst, \ + .dev = DEVICE_DT_GET(node_id), \ + .type = SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE, \ + .iodev = &read_iodev_##inst, \ + IF_ENABLED(CONFIG_SENSING_SHELL, (.shell_name = name_buffer_##inst, ))} + +#define DRV_INIT(inst) \ + static const struct drv_config cfg_##inst = { \ + .plane0 = SENSING_SENSOR_INFO_GET(DT_INST_PHANDLE(inst, plane0), \ + SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D), \ + .plane1 = SENSING_SENSOR_INFO_GET(DT_INST_PHANDLE(inst, plane1), \ + SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D), \ + }; \ + static struct drv_data data_##inst = {0}; \ + DECLARE_IODEV(DT_DRV_INST(inst), inst); \ + DEVICE_DT_INST_DEFINE(inst, init, NULL, &data_##inst, &cfg_##inst, APPLICATION, 10, \ + &angle_api); + +DT_INST_FOREACH_STATUS_OKAY(DRV_INIT) diff --git a/subsys/sensing/vsensors/emul/CMakeLists.txt b/subsys/sensing/vsensors/emul/CMakeLists.txt new file mode 100644 index 00000000000000..47bab4b38b063d --- /dev/null +++ b/subsys/sensing/vsensors/emul/CMakeLists.txt @@ -0,0 +1,3 @@ +zephyr_library() +zephyr_library_sources(driver.c) +zephyr_include_directories(include) diff --git a/subsys/sensing/vsensors/emul/driver.c b/subsys/sensing/vsensors/emul/driver.c new file mode 100644 index 00000000000000..b4ea50bbe6956e --- /dev/null +++ b/subsys/sensing/vsensors/emul/driver.c @@ -0,0 +1,254 @@ + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(sensing_emul, CONFIG_SENSING_LOG_LEVEL); + +#define DT_DRV_COMPAT sensing_emul +struct drv_config { + const struct sensing_sensor_info **info; + size_t info_count; +}; + +struct drv_data { +}; + +static inline bool is_channel_supported(const struct drv_config *cfg, enum sensor_channel channel) +{ + int32_t required_type; + + switch (channel) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + required_type = SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D; + break; + default: + return false; + } + + for (size_t i = 0; i < cfg->info_count; ++i) { + if (cfg->info[i]->type == required_type) { + return true; + } + } + return false; +} + +static int attribute_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + return 0; +} + +struct raw_data { + uint64_t timestamp_ns; + uint8_t count; + enum sensor_channel channels[0]; +} __packed; + +static int submit(const struct device *sensor, struct rtio_iodev_sqe *sqe) +{ + const struct drv_config *cfg = sensor->config; + const struct sensor_read_config *read_cfg = sqe->sqe.iodev->data; + uint8_t *buf; + uint32_t buf_len; + uint8_t channel_count = 0; + int rc; + + if (read_cfg->is_streaming) { + rtio_iodev_sqe_err(sqe, -ENOTSUP); + return 0; + } + + /* For now just assume the user wants to read all the channels */ + for (size_t i = 0; i < cfg->info_count; ++i) { + switch (cfg->info[i]->type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + case SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D: + case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: + channel_count += 3; + break; + case SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE: + channel_count += 1; + break; + default: + rtio_iodev_sqe_err(sqe, -ENOTSUP); + return 0; + } + } + + const uint32_t desired_size = + sizeof(struct raw_data) + channel_count * sizeof(enum sensor_channel); + + rc = rtio_sqe_rx_buf(sqe, desired_size, desired_size, &buf, &buf_len); + if (rc != 0) { + rtio_iodev_sqe_err(sqe, rc); + return 0; + } + + ((struct raw_data *)buf)->timestamp_ns = k_ticks_to_ns_floor64(k_uptime_ticks()); + ((struct raw_data *)buf)->count = channel_count; + buf += sizeof(struct raw_data); + + int count = 0; + for (size_t i = 0; i < cfg->info_count; ++i) { + switch (cfg->info[i]->type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + case SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D: + ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_ACCEL_X; + ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_ACCEL_Y; + ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_ACCEL_Z; + break; + case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: + ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_GYRO_X; + ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_GYRO_Y; + ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_GYRO_Z; + break; + case SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE: + ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_ROTATION; + break; + default: + rtio_iodev_sqe_err(sqe, -ENOTSUP); + return 0; + } + } + + rtio_iodev_sqe_ok(sqe, 0); + return 0; +} + +static int decoder_get_frame_count(const uint8_t *buffer, uint16_t *frame_count) +{ + ARG_UNUSED(buffer); + *frame_count = 1; + return 0; +} + +static int decoder_get_timestamp(const uint8_t *buffer, uint64_t *timestamp_ns) +{ + *timestamp_ns = ((uint64_t *)buffer)[0]; + return 0; +} + +static bool decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) +{ + ARG_UNUSED(buffer); + ARG_UNUSED(trigger); + return false; +} + +static int decoder_get_shift(const uint8_t *buffer, enum sensor_channel channel_type, int8_t *shift) +{ + ARG_UNUSED(buffer); + ARG_UNUSED(channel_type); + *shift = 0; + return 0; +} + +static int decoder_decode(const uint8_t *buffer, sensor_frame_iterator_t *fit, + sensor_channel_iterator_t *cit, enum sensor_channel *channels, + q31_t *values, uint8_t max_count) +{ + if (*fit != 0) { + return 0; + } + + const struct raw_data *data = (const struct raw_data *)buffer; + int count = 0; + + if (*cit >= data->count) { + return -EINVAL; + } + + while (*cit < data->count && count < max_count) { + channels[count] = data->channels[*cit]; + values[count++] = INT32_MAX; + *cit += 1; + } + + if (*cit == data->count) { + *fit += 1; + *cit = 0; + } + return count; +} + +SENSING_DMEM static const struct sensor_decoder_api decoder_api = { + .get_frame_count = decoder_get_frame_count, + .get_timestamp = decoder_get_timestamp, + .has_trigger = decoder_has_trigger, + .get_shift = decoder_get_shift, + .decode = decoder_decode, +}; + +static int get_decoder(const struct device *dev, const struct sensor_decoder_api **api) +{ + ARG_UNUSED(dev); + *api = &decoder_api; + return 0; +} + +SENSING_DMEM static const struct sensor_driver_api emul_api = { + .attr_set = attribute_set, + .attr_get = NULL, + .get_decoder = get_decoder, + .submit = submit, +}; + +static int init(const struct device *dev) +{ + // const struct drv_config *cfg = dev->config; + // struct drv_data *data = dev->data; + + return 0; +} + +#define EMUL_SENSOR_INFO_NAME(node_id, type) \ + _CONCAT(_CONCAT(__emul_sensor_info, DEVICE_DT_NAME_GET(node_id)), type) + +#define DECLARE_SENSOR_INFO_NAME(node_id, name, prop, idx, _iodev, _info) \ + IF_ENABLED(CONFIG_SENSING_SHELL, (static char node_id##_##idx##_name_buffer[5];)) \ + const STRUCT_SECTION_ITERABLE(sensing_sensor_info, name) = { \ + .info = &(_info), \ + .dev = DEVICE_DT_GET(node_id), \ + .type = DT_PROP_BY_IDX(node_id, prop, idx), \ + .iodev = &(_iodev), \ + IF_ENABLED(CONFIG_SENSING_SHELL, (.shell_name = node_id##_##idx##_name_buffer, ))} + +#define DECLARE_SENSOR_INFO(node_id, prop, idx, _iodev, _info) \ + DECLARE_SENSOR_INFO_NAME( \ + node_id, SENSING_SENSOR_INFO_DT_NAME(node_id, DT_PROP_BY_IDX(node_id, prop, idx)), \ + prop, idx, _iodev, _info) + +#define DECLARE_IODEV(node_id, inst) \ + SENSOR_DT_READ_IODEV(emul_read_iodev_##inst, node_id, SENSOR_CHAN_ALL); \ + static struct sensor_info sensor_info_##inst = SENSOR_INFO_INITIALIZER( \ + DEVICE_DT_GET(node_id), DT_NODE_VENDOR_OR(node_id, NULL), \ + DT_NODE_MODEL_OR(node_id, NULL), DT_PROP_OR(node_id, friendly_name, NULL)); \ + DT_FOREACH_PROP_ELEM_VARGS(node_id, sensor_types, DECLARE_SENSOR_INFO, \ + emul_read_iodev_##inst, sensor_info_##inst) + +#define SENSOR_INFO_ITEM(node_id, prop, idx) \ + &SENSING_SENSOR_INFO_DT_NAME(node_id, DT_PROP_BY_IDX(node_id, prop, idx)) + +#define DRV_INIT(inst) \ + DECLARE_IODEV(DT_DRV_INST(inst), inst); \ + static const struct sensing_sensor_info *info_array_##inst[DT_INST_PROP_LEN( \ + inst, sensor_types)] = { \ + DT_INST_FOREACH_PROP_ELEM_SEP(inst, sensor_types, SENSOR_INFO_ITEM, (, ))}; \ + static const struct drv_config cfg_##inst = { \ + .info = (const struct sensing_sensor_info **)&info_array_##inst, \ + .info_count = DT_INST_PROP_LEN(inst, sensor_types), \ + }; \ + static struct drv_data data_##inst = {}; \ + DEVICE_DT_INST_DEFINE(inst, init, NULL, &data_##inst, &cfg_##inst, APPLICATION, 10, \ + &emul_api); + +DT_INST_FOREACH_STATUS_OKAY(DRV_INIT) diff --git a/subsys/sensing/vsensors/emul/include/zephyr/sensing/vsensors/emul/emul.h b/subsys/sensing/vsensors/emul/include/zephyr/sensing/vsensors/emul/emul.h new file mode 100644 index 00000000000000..ac61faf389875f --- /dev/null +++ b/subsys/sensing/vsensors/emul/include/zephyr/sensing/vsensors/emul/emul.h @@ -0,0 +1,12 @@ +// +// Created by peress on 07/07/23. +// + +#ifndef ZEPHYR_SUBSYS_SENSING_VSENSORS_EMUL_INCLUDE_ZEPHYR_SENSING_VSENSORS_EMUL_EMUL_H +#define ZEPHYR_SUBSYS_SENSING_VSENSORS_EMUL_INCLUDE_ZEPHYR_SENSING_VSENSORS_EMUL_EMUL_H + +#include + +void vsensors_emul_set(const struct device *dev); + +#endif // ZEPHYR_SUBSYS_SENSING_VSENSORS_EMUL_INCLUDE_ZEPHYR_SENSING_VSENSORS_EMUL_EMUL_H diff --git a/tests/subsys/sensing/boards/native_posix.conf b/tests/subsys/sensing/boards/native_posix.conf new file mode 100644 index 00000000000000..2b3af7b4476885 --- /dev/null +++ b/tests/subsys/sensing/boards/native_posix.conf @@ -0,0 +1 @@ +CONFIG_SPI_RTIO=y diff --git a/tests/subsys/sensing/src/test_arbitration.c b/tests/subsys/sensing/src/test_arbitration.c index b7ca5fd5587cea..32ed409f6f41b4 100644 --- a/tests/subsys/sensing/src/test_arbitration.c +++ b/tests/subsys/sensing/src/test_arbitration.c @@ -30,7 +30,7 @@ ZTEST(sensing, test_single_connection_arbitration) .value = FIELD_PREP(GENMASK(31, 24), 100), .shift = 8, }; - zassert_ok(sensing_set_attributes(handle, &attribute, 1)); + zassert_ok(sensing_set_attributes(handle, SENSING_SENSOR_MODE_DONE, &attribute, 1)); uint8_t reg_val; icm42688_emul_get_reg(icm42688, REG_ACCEL_CONFIG0, ®_val, 1); @@ -59,10 +59,10 @@ ZTEST(sensing, test_double_connection_arbitration) .value = FIELD_PREP(GENMASK(31, 23), 100), .shift = 9, }; - zassert_ok(sensing_set_attributes(handles[0], &attribute, 1)); + zassert_ok(sensing_set_attributes(handles[0], SENSING_SENSOR_MODE_DONE, &attribute, 1)); attribute.value = FIELD_PREP(GENMASK(31, 23), 200); - zassert_ok(sensing_set_attributes(handles[1], &attribute, 1)); + zassert_ok(sensing_set_attributes(handles[1], SENSING_SENSOR_MODE_DONE, &attribute, 1)); icm42688_emul_get_reg(icm42688, REG_ACCEL_CONFIG0, ®_val, 1); zassert_equal(0b0111, FIELD_GET(MASK_ACCEL_ODR, reg_val), "ACCEL_CONFIG0=0x%02x", diff --git a/tests/subsys/sensing/src/test_connections.c b/tests/subsys/sensing/src/test_connections.c index f79c309bc7cf20..5437a4355b0e19 100644 --- a/tests/subsys/sensing/src/test_connections.c +++ b/tests/subsys/sensing/src/test_connections.c @@ -13,24 +13,26 @@ ZTEST(sensing, test_open_connections_limit) const struct sensing_sensor_info *sensor = SENSING_SENSOR_INFO_GET( DT_NODELABEL(accelgyro), SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D); const struct sensing_callback_list cb_list; - sensing_sensor_handle_t handles[CONFIG_SENSING_MAX_CONNECTIONS + 1]; + sensing_sensor_handle_t handles[CONFIG_SENSING_MAX_DYNAMIC_CONNECTIONS + 1]; zassert_not_null(sensor); /* Allocate all the connection */ - for (int i = 0; i < CONFIG_SENSING_MAX_CONNECTIONS; ++i) { + for (int i = 0; i < CONFIG_SENSING_MAX_DYNAMIC_CONNECTIONS; ++i) { zassert_ok(sensing_open_sensor(sensor, &cb_list, &handles[i])); } /* Try to over allocate */ - zassert_equal(-ENOSPC, sensing_open_sensor(sensor, &cb_list, - &handles[CONFIG_SENSING_MAX_CONNECTIONS])); + zassert_equal(-ENOSPC, + sensing_open_sensor(sensor, &cb_list, + &handles[CONFIG_SENSING_MAX_DYNAMIC_CONNECTIONS])); /* Free one connection */ zassert_ok(sensing_close_sensor(handles[0])); /* Allocate one */ - zassert_ok(sensing_open_sensor(sensor, &cb_list, &handles[CONFIG_SENSING_MAX_CONNECTIONS])); + zassert_ok(sensing_open_sensor(sensor, &cb_list, + &handles[CONFIG_SENSING_MAX_DYNAMIC_CONNECTIONS])); } ZTEST(sensing, test_connection_get_info) From ceeaa656d5405ed3e144d7734e42221c586dde94 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Fri, 14 Jul 2023 14:28:40 -0600 Subject: [PATCH 10/10] Rework logic to encode the data in the drivers --- include/zephyr/rtio/rtio.h | 128 ++++----- include/zephyr/rtio/rtio_mpsc.h | 4 +- include/zephyr/sensing/sensor.h | 2 + include/zephyr/sensing/transform.h | 16 ++ samples/sensor/sensor_shell/prj.conf | 7 +- subsys/sensing/CMakeLists.txt | 5 +- subsys/sensing/src/data_transform.c | 124 +++++++++ subsys/sensing/src/processing.c | 171 ++---------- subsys/sensing/src/sensor_connections.c | 6 +- subsys/sensing/src/sensor_pipe.c | 89 ++++++- .../vsensors/accel-based-angle/driver.c | 87 +----- subsys/sensing/vsensors/emul/driver.c | 247 ++++++++---------- 12 files changed, 418 insertions(+), 468 deletions(-) create mode 100644 include/zephyr/sensing/transform.h create mode 100644 subsys/sensing/src/data_transform.c diff --git a/include/zephyr/rtio/rtio.h b/include/zephyr/rtio/rtio.h index 8845fa097fafda..56e58b4b2a4831 100644 --- a/include/zephyr/rtio/rtio.h +++ b/include/zephyr/rtio/rtio.h @@ -42,7 +42,6 @@ extern "C" { #endif - /** * @brief RTIO * @defgroup rtio RTIO @@ -84,7 +83,6 @@ extern "C" { * @} */ - /** * @brief RTIO SQE Flags * @defgroup rtio_sqe_flags RTIO SQE Flags @@ -113,7 +111,6 @@ extern "C" { */ #define RTIO_SQE_TRANSACTION BIT(1) - /** * @brief The buffer should be allocated by the RTIO mempool * @@ -263,13 +260,13 @@ struct rtio_sqe { /** OP_TX, OP_RX */ struct { uint32_t buf_len; /**< Length of buffer */ - uint8_t *buf; /**< Buffer to use*/ + uint8_t *buf; /**< Buffer to use*/ }; /** OP_TINY_TX */ struct { uint8_t tiny_buf_len; /**< Length of tiny buffer */ - uint8_t tiny_buf[7]; /**< Tiny buffer */ + uint8_t tiny_buf[7]; /**< Tiny buffer */ }; /** OP_CALLBACK */ @@ -284,7 +281,6 @@ struct rtio_sqe { uint8_t *tx_buf; uint8_t *rx_buf; }; - }; }; @@ -452,27 +448,25 @@ struct rtio_iodev { #define RTIO_OP_NOP 0 /** An operation that receives (reads) */ -#define RTIO_OP_RX (RTIO_OP_NOP+1) +#define RTIO_OP_RX (RTIO_OP_NOP + 1) /** An operation that transmits (writes) */ -#define RTIO_OP_TX (RTIO_OP_RX+1) +#define RTIO_OP_TX (RTIO_OP_RX + 1) /** An operation that transmits tiny writes by copying the data to write */ -#define RTIO_OP_TINY_TX (RTIO_OP_TX+1) +#define RTIO_OP_TINY_TX (RTIO_OP_TX + 1) /** An operation that calls a given function (callback) */ -#define RTIO_OP_CALLBACK (RTIO_OP_TINY_TX+1) +#define RTIO_OP_CALLBACK (RTIO_OP_TINY_TX + 1) /** An operation that transceives (reads and writes simultaneously) */ -#define RTIO_OP_TXRX (RTIO_OP_CALLBACK+1) - +#define RTIO_OP_TXRX (RTIO_OP_CALLBACK + 1) /** * @brief Prepare a nop (no op) submission */ -static inline void rtio_sqe_prep_nop(struct rtio_sqe *sqe, - const struct rtio_iodev *iodev, - void *userdata) +static inline void rtio_sqe_prep_nop(struct rtio_sqe *sqe, const struct rtio_iodev *iodev, + void *userdata) { memset(sqe, 0, sizeof(struct rtio_sqe)); sqe->op = RTIO_OP_NOP; @@ -483,12 +477,8 @@ static inline void rtio_sqe_prep_nop(struct rtio_sqe *sqe, /** * @brief Prepare a read op submission */ -static inline void rtio_sqe_prep_read(struct rtio_sqe *sqe, - const struct rtio_iodev *iodev, - int8_t prio, - uint8_t *buf, - uint32_t len, - void *userdata) +static inline void rtio_sqe_prep_read(struct rtio_sqe *sqe, const struct rtio_iodev *iodev, + int8_t prio, uint8_t *buf, uint32_t len, void *userdata) { memset(sqe, 0, sizeof(struct rtio_sqe)); sqe->op = RTIO_OP_RX; @@ -523,12 +513,8 @@ static inline void rtio_sqe_prep_read_multishot(struct rtio_sqe *sqe, /** * @brief Prepare a write op submission */ -static inline void rtio_sqe_prep_write(struct rtio_sqe *sqe, - const struct rtio_iodev *iodev, - int8_t prio, - uint8_t *buf, - uint32_t len, - void *userdata) +static inline void rtio_sqe_prep_write(struct rtio_sqe *sqe, const struct rtio_iodev *iodev, + int8_t prio, uint8_t *buf, uint32_t len, void *userdata) { memset(sqe, 0, sizeof(struct rtio_sqe)); sqe->op = RTIO_OP_TX; @@ -549,12 +535,9 @@ static inline void rtio_sqe_prep_write(struct rtio_sqe *sqe, * This is useful in many scenarios with RTL logic where a write of the register to * subsequently read must be done. */ -static inline void rtio_sqe_prep_tiny_write(struct rtio_sqe *sqe, - const struct rtio_iodev *iodev, - int8_t prio, - const uint8_t *tiny_write_data, - uint8_t tiny_write_len, - void *userdata) +static inline void rtio_sqe_prep_tiny_write(struct rtio_sqe *sqe, const struct rtio_iodev *iodev, + int8_t prio, const uint8_t *tiny_write_data, + uint8_t tiny_write_len, void *userdata) { __ASSERT_NO_MSG(tiny_write_len <= sizeof(sqe->tiny_buf)); @@ -575,10 +558,8 @@ static inline void rtio_sqe_prep_tiny_write(struct rtio_sqe *sqe, * Used where general purpose logic is required in a queue of io operations to do * transforms or logic. */ -static inline void rtio_sqe_prep_callback(struct rtio_sqe *sqe, - rtio_callback_t callback, - void *arg0, - void *userdata) +static inline void rtio_sqe_prep_callback(struct rtio_sqe *sqe, rtio_callback_t callback, + void *arg0, void *userdata) { memset(sqe, 0, sizeof(struct rtio_sqe)); sqe->op = RTIO_OP_CALLBACK; @@ -592,13 +573,9 @@ static inline void rtio_sqe_prep_callback(struct rtio_sqe *sqe, /** * @brief Prepare a transceive op submission */ -static inline void rtio_sqe_prep_transceive(struct rtio_sqe *sqe, - const struct rtio_iodev *iodev, - int8_t prio, - uint8_t *tx_buf, - uint8_t *rx_buf, - uint32_t buf_len, - void *userdata) +static inline void rtio_sqe_prep_transceive(struct rtio_sqe *sqe, const struct rtio_iodev *iodev, + int8_t prio, uint8_t *tx_buf, uint8_t *rx_buf, + uint32_t buf_len, void *userdata) { memset(sqe, 0, sizeof(struct rtio_sqe)); sqe->op = RTIO_OP_TXRX; @@ -656,8 +633,8 @@ static inline void rtio_cqe_pool_free(struct rtio_cqe_pool *pool, struct rtio_cq pool->pool_free++; } -static inline int rtio_block_pool_alloc(struct rtio_block_pool *pool, size_t min_sz, - size_t max_sz, uint8_t **buf, uint32_t *buf_len) +static inline int rtio_block_pool_alloc(struct rtio_block_pool *pool, size_t min_sz, size_t max_sz, + uint8_t **buf, uint32_t *buf_len) { uint32_t bytes = max_sz; @@ -741,17 +718,20 @@ static inline void rtio_block_pool_free(struct rtio_block_pool *pool, void *buf, */ #define RTIO_DMEM COND_CODE_1(CONFIG_USERSPACE, (K_APP_DMEM(rtio_partition) static), (static)) -#define Z_RTIO_BLOCK_POOL_DEFINE(name, blk_sz, blk_cnt, blk_align) \ - RTIO_BMEM uint8_t __aligned(WB_UP(blk_align)) \ - _block_pool_##name[blk_cnt*WB_UP(blk_sz)]; \ - _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(_sys_blocks_##name, WB_UP(blk_sz), \ - blk_cnt, _block_pool_##name, \ - RTIO_DMEM); \ - static struct rtio_block_pool name = { \ - .mempool = &_sys_blocks_##name, \ - .blk_size = blk_sz, \ +#define Z_RTIO_BLOCK_POOL_DEFINE_SCOPED(scope, name, blk_sz, blk_cnt, blk_align) \ + RTIO_BMEM uint8_t __aligned(WB_UP(blk_align)) \ + _block_pool_##name[blk_cnt*WB_UP(blk_sz)]; \ + _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(_sys_blocks_##name, WB_UP(blk_sz), \ + blk_cnt, _block_pool_##name, \ + RTIO_DMEM); \ + __DEBRACKET scope struct rtio_block_pool name = { \ + .mempool = &_sys_blocks_##name, \ + .blk_size = blk_sz, \ } +#define Z_RTIO_BLOCK_POOL_DEFINE(name, blk_sz, blk_cnt, blk_align) \ + Z_RTIO_BLOCK_POOL_DEFINE_SCOPED((static), name, blk_sz, blk_cnt, blk_align) + #define Z_RTIO_DEFINE(name, _sqe_pool, _cqe_pool, _block_pool) \ IF_ENABLED(CONFIG_RTIO_SUBMIT_SEM, \ (static K_SEM_DEFINE(_submit_sem_##name, 0, K_SEM_MAX_LIMIT))) \ @@ -779,7 +759,7 @@ static inline void rtio_block_pool_free(struct rtio_block_pool *pool, void *buf, #define RTIO_DEFINE(name, sq_sz, cq_sz) \ Z_RTIO_SQE_POOL_DEFINE(name##_sqe_pool, sq_sz); \ Z_RTIO_CQE_POOL_DEFINE(name##_cqe_pool, cq_sz); \ - Z_RTIO_DEFINE(name, &name##_sqe_pool, &name##_cqe_pool, NULL) \ + Z_RTIO_DEFINE(name, &name##_sqe_pool, &name##_cqe_pool, NULL) /* clang-format on */ @@ -793,12 +773,17 @@ static inline void rtio_block_pool_free(struct rtio_block_pool *pool, void *buf, * @param blk_size The number of bytes in each block * @param balign The block alignment */ -#define RTIO_DEFINE_WITH_MEMPOOL(name, sq_sz, cq_sz, num_blks, blk_size, balign) \ - Z_RTIO_SQE_POOL_DEFINE(name##_sqe_pool, sq_sz); \ - Z_RTIO_CQE_POOL_DEFINE(name##_cqe_pool, cq_sz); \ - Z_RTIO_BLOCK_POOL_DEFINE(name##_block_pool, blk_size, num_blks, balign); \ +#define RTIO_DEFINE_WITH_MEMPOOL(name, sq_sz, cq_sz, num_blks, blk_size, balign) \ + Z_RTIO_SQE_POOL_DEFINE(name##_sqe_pool, sq_sz); \ + Z_RTIO_CQE_POOL_DEFINE(name##_cqe_pool, cq_sz); \ + Z_RTIO_BLOCK_POOL_DEFINE(name##_block_pool, blk_size, num_blks, balign); \ Z_RTIO_DEFINE(name, &name##_sqe_pool, &name##_cqe_pool, &name##_block_pool) +#define RTIO_DEFINE_WITH_EXT_MEMPOOL(name, sq_sz, cq_sz, mempool) \ + Z_RTIO_SQE_POOL_DEFINE(name##_sqe_pool, sq_sz); \ + Z_RTIO_CQE_POOL_DEFINE(name##_cqe_pool, cq_sz); \ + Z_RTIO_DEFINE(name, &name##_sqe_pool, &name##_cqe_pool, &mempool) + /* clang-format on */ /** @@ -842,7 +827,6 @@ static inline struct rtio_iodev_sqe *rtio_txn_next(const struct rtio_iodev_sqe * } } - /** * @brief Get the next sqe in the chain * @@ -1061,9 +1045,9 @@ static inline int z_impl_rtio_cqe_get_mempool_buffer(const struct rtio *r, struc *buff = r->block_pool->mempool->buffer + blk_idx * r->block_pool->blk_size; *buff_len = blk_count * r->block_pool->blk_size; __ASSERT_NO_MSG(*buff >= r->block_pool->mempool->buffer); - __ASSERT_NO_MSG(*buff < - r->block_pool->mempool->buffer + - r->block_pool->blk_size * r->block_pool->mempool->num_blocks); + __ASSERT_NO_MSG(*buff < r->block_pool->mempool->buffer + + r->block_pool->blk_size * + r->block_pool->mempool->num_blocks); return 0; } return -EINVAL; @@ -1193,8 +1177,8 @@ static inline int rtio_sqe_rx_buf(const struct rtio_iodev_sqe *iodev_sqe, uint32 return 0; } - int rc = rtio_block_pool_alloc(r->block_pool, min_buf_len, max_buf_len, - buf, buf_len); + int rc = rtio_block_pool_alloc(r->block_pool, min_buf_len, max_buf_len, buf, + buf_len); if (rc == 0) { sqe->buf = *buf; sqe->buf_len = *buf_len; @@ -1306,8 +1290,7 @@ __syscall int rtio_sqe_copy_in_get_handles(struct rtio *r, const struct rtio_sqe struct rtio_sqe **handle, size_t sqe_count); static inline int z_impl_rtio_sqe_copy_in_get_handles(struct rtio *r, const struct rtio_sqe *sqes, - struct rtio_sqe **handle, - size_t sqe_count) + struct rtio_sqe **handle, size_t sqe_count) { struct rtio_sqe *sqe; uint32_t acquirable = rtio_sqe_acquirable(r); @@ -1364,13 +1347,9 @@ static inline int rtio_sqe_copy_in(struct rtio *r, const struct rtio_sqe *sqes, * * @retval copy_count Count of copied CQEs (0 to cqe_count) */ -__syscall int rtio_cqe_copy_out(struct rtio *r, - struct rtio_cqe *cqes, - size_t cqe_count, +__syscall int rtio_cqe_copy_out(struct rtio *r, struct rtio_cqe *cqes, size_t cqe_count, k_timeout_t timeout); -static inline int z_impl_rtio_cqe_copy_out(struct rtio *r, - struct rtio_cqe *cqes, - size_t cqe_count, +static inline int z_impl_rtio_cqe_copy_out(struct rtio *r, struct rtio_cqe *cqes, size_t cqe_count, k_timeout_t timeout) { size_t copied = 0; @@ -1432,7 +1411,6 @@ static inline int z_impl_rtio_submit(struct rtio *r, uint32_t wait_count) */ rtio_executor_submit(r); - /* TODO could be nicer if we could suspend the thread and not * wake up on each completion here. */ diff --git a/include/zephyr/rtio/rtio_mpsc.h b/include/zephyr/rtio/rtio_mpsc.h index f129f5712aaadf..8749f9374978ca 100644 --- a/include/zephyr/rtio/rtio_mpsc.h +++ b/include/zephyr/rtio/rtio_mpsc.h @@ -147,8 +147,8 @@ static ALWAYS_INLINE void rtio_mpsc_push(struct rtio_mpsc *q, struct rtio_mpsc_n static inline struct rtio_mpsc_node *rtio_mpsc_pop(struct rtio_mpsc *q) { struct rtio_mpsc_node *head; - struct rtio_mpsc_node *tail = q->tail; - struct rtio_mpsc_node *next = (struct rtio_mpsc_node *)mpsc_ptr_get(tail->next); + struct rtio_mpsc_node *tail = q == NULL ? NULL : q->tail; + struct rtio_mpsc_node *next = tail == NULL ? NULL : (struct rtio_mpsc_node *)mpsc_ptr_get(tail->next); /* Skip over the stub/sentinel */ if (tail == &q->stub) { diff --git a/include/zephyr/sensing/sensor.h b/include/zephyr/sensing/sensor.h index ced2455e339a7b..925fd41ab203b6 100644 --- a/include/zephyr/sensing/sensor.h +++ b/include/zephyr/sensing/sensor.h @@ -20,6 +20,8 @@ struct sensing_connection { uint32_t attribute_mask; } __packed __aligned(4); +extern struct rtio_block_pool sensing_rtio_block_pool; + #define SENSING_CONNECTION_DT_DEFINE(node_id, target_node_id, type, _cb_list) \ SENSING_DMEM STRUCT_SECTION_ITERABLE(sensing_connection, node_id##_sensing_connection) = { \ .info = SENSING_SENSOR_INFO_GET(target_node_id, type), \ diff --git a/include/zephyr/sensing/transform.h b/include/zephyr/sensing/transform.h new file mode 100644 index 00000000000000..9ccc9b20658c37 --- /dev/null +++ b/include/zephyr/sensing/transform.h @@ -0,0 +1,16 @@ +// +// Created by peress on 13/07/23. +// + +#ifndef ZEPHYR_INCLUDE_ZEPHYR_SENSING_TRANSFORM_H +#define ZEPHYR_INCLUDE_ZEPHYR_SENSING_TRANSFORM_H + +#include + +int decode_three_axis_data(int32_t type, struct sensing_sensor_three_axis_data *out, + const struct sensor_decoder_api *decoder, void *data); + +int decode_float_data(int32_t type, struct sensing_sensor_float_data *out, + const struct sensor_decoder_api *decoder, void *data); + +#endif // ZEPHYR_INCLUDE_ZEPHYR_SENSING_TRANSFORM_H diff --git a/samples/sensor/sensor_shell/prj.conf b/samples/sensor/sensor_shell/prj.conf index 8a1b8c78ae234d..33baa97310b446 100644 --- a/samples/sensor/sensor_shell/prj.conf +++ b/samples/sensor/sensor_shell/prj.conf @@ -7,9 +7,10 @@ CONFIG_SENSOR_INFO=y CONFIG_LOG=y CONFIG_RTIO_CONSUME_SEM=y +CONFIG_ASSERT=y # CONFIG_USERSPACE=y CONFIG_SENSING=y CONFIG_SENSING_SHELL=y -# CONFIG_RTIO_LOG_LEVEL_DBG=y -# CONFIG_SENSOR_LOG_LEVEL_DBG=y -# CONFIG_SENSING_LOG_LEVEL_DBG=y +CONFIG_RTIO_LOG_LEVEL_DBG=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y +CONFIG_SENSING_LOG_LEVEL_DBG=y diff --git a/subsys/sensing/CMakeLists.txt b/subsys/sensing/CMakeLists.txt index 3c4541c22e370d..185438bc1ee043 100644 --- a/subsys/sensing/CMakeLists.txt +++ b/subsys/sensing/CMakeLists.txt @@ -2,11 +2,12 @@ zephyr_library() zephyr_library_sources( + src/data_transform.c + src/processing.c src/sensor_arbitrate.c + src/sensor_connections.c src/sensor_info.c src/sensor_pipe.c - src/sensor_connections.c - src/processing.c ) zephyr_library_sources_ifdef(CONFIG_SENSING_SHELL src/shell.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE src/userspace.c) diff --git a/subsys/sensing/src/data_transform.c b/subsys/sensing/src/data_transform.c new file mode 100644 index 00000000000000..c74e2a04bb4f44 --- /dev/null +++ b/subsys/sensing/src/data_transform.c @@ -0,0 +1,124 @@ +#include +#include + +LOG_MODULE_REGISTER(sensing_transform, CONFIG_SENSING_LOG_LEVEL); + +static int decode_header(struct sensing_sensor_value_header *header, + const struct sensor_decoder_api *decoder, void *data) +{ + uint16_t frame_count; + uint64_t timestamp_ns; + int rc; + + rc = decoder->get_timestamp(data, ×tamp_ns); + rc |= decoder->get_frame_count(data, &frame_count); + if (rc != 0) { + return -EINVAL; + } + header->base_timestamp = timestamp_ns; + header->reading_count = frame_count; + return 0; +} + +int decode_three_axis_data(int32_t type, struct sensing_sensor_three_axis_data *out, + const struct sensor_decoder_api *decoder, void *data) +{ + uint16_t frame_count; + int rc; + + rc = decoder->get_frame_count(data, &frame_count); + if (rc != 0) { + return rc; + } + + __ASSERT_NO_MSG(frame_count == 1); + LOG_DBG("Decoding 1 frame for 3 axis data from %p", data); + + sensor_frame_iterator_t fit = {0}; + sensor_channel_iterator_t cit = {0}; + enum sensor_channel channel; + q31_t value; + bool has_shift = false; + + rc = decode_header(&out->header, decoder, data); + if (rc != 0) { + return rc; + } + + while (true) { + rc = decoder->decode(data, &fit, &cit, &channel, &value, 1); + if (rc < 0) { + LOG_ERR("Failed to decode entry (%d)", rc); + return rc; + } + if (rc == 0) { + return 0; + } + switch (type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + case SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D: + if (channel == SENSOR_CHAN_ACCEL_X || channel == SENSOR_CHAN_ACCEL_Y || + channel == SENSOR_CHAN_ACCEL_Z) { + LOG_DBG("Got [%d] for accel type, value=0x%08x", (int)channel, + value); + out->readings[0].values[channel] = value; + if (!has_shift) { + rc = decoder->get_shift(data, channel, &out->shift); + if (rc != 0) { + return rc; + } + has_shift = true; + LOG_DBG("Got shift value %d", out->shift); + } + } + break; + case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: + if (channel == SENSOR_CHAN_GYRO_X || channel == SENSOR_CHAN_GYRO_Y || + channel == SENSOR_CHAN_GYRO_Z) { + out->readings[0].values[channel - SENSOR_CHAN_GYRO_X] = value; + if (!has_shift) { + rc = decoder->get_shift(data, channel, &out->shift); + if (rc != 0) { + return rc; + } + has_shift = true; + } + } + break; + } + } +} + +int decode_float_data(int32_t type, struct sensing_sensor_float_data *out, + const struct sensor_decoder_api *decoder, void *data) +{ + uint16_t frame_count; + int rc; + + rc = decoder->get_frame_count(data, &frame_count); + if (rc != 0) { + return rc; + } + + __ASSERT_NO_MSG(frame_count == 1); + + sensor_frame_iterator_t fit = {0}; + sensor_channel_iterator_t cit = {0}; + enum sensor_channel channel; + bool has_shift = false; + + while (true) { + rc = decoder->decode(data, &fit, &cit, &channel, &out->readings[0].v, 1); + if (rc <= 0) { + return rc; + } + if (type == SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE && + channel == SENSOR_CHAN_ROTATION && !has_shift) { + rc = decoder->get_shift(data, channel, &out->shift); + if (rc != 0) { + return rc; + } + has_shift = true; + } + } +} diff --git a/subsys/sensing/src/processing.c b/subsys/sensing/src/processing.c index 6f04399b82ca2b..f17559a4a6036c 100644 --- a/subsys/sensing/src/processing.c +++ b/subsys/sensing/src/processing.c @@ -12,106 +12,29 @@ LOG_MODULE_REGISTER(sensing_processing, CONFIG_SENSING_LOG_LEVEL); -static int decode_three_axis_data(int32_t type, struct sensing_sensor_three_axis_data *out, - const struct sensor_decoder_api *decoder, void *data) +static void process_info_node(struct sensing_sensor_info *info, const void *data) { - uint16_t frame_count; - int rc; - - rc = decoder->get_frame_count(data, &frame_count); - if (rc != 0) { - return rc; - } - - __ASSERT_NO_MSG(frame_count == 1); - LOG_DBG("Decoding 1 frame for 3 axis data from %p", data); - - sensor_frame_iterator_t fit = {0}; - sensor_channel_iterator_t cit = {0}; - enum sensor_channel channel; - q31_t value; - bool has_shift = false; - - while (true) { - rc = decoder->decode(data, &fit, &cit, &channel, &value, 1); - if (rc < 0) { - LOG_ERR("Failed to decode entry (%d)", rc); - return rc; - } - if (rc == 0) { - return 0; - } - switch (type) { - case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: - case SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D: - if (channel == SENSOR_CHAN_ACCEL_X || channel == SENSOR_CHAN_ACCEL_Y || - channel == SENSOR_CHAN_ACCEL_Z) { - LOG_DBG("Got [%d] for accel type, value=0x%08x", (int)channel, value); - out->readings[0].values[channel] = value; - if (!has_shift) { - rc = decoder->get_shift(data, channel, &out->shift); - if (rc != 0) { - return rc; - } - has_shift = true; - LOG_DBG("Got shift value %d", out->shift); - } - } - break; - case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: - if (channel == SENSOR_CHAN_GYRO_X || channel == SENSOR_CHAN_GYRO_Y || - channel == SENSOR_CHAN_GYRO_Z) { - out->readings[0].values[channel - SENSOR_CHAN_GYRO_X] = value; - if (!has_shift) { - rc = decoder->get_shift(data, channel, &out->shift); - if (rc != 0) { - return rc; - } - has_shift = true; - } - } - break; + LOG_DBG("Broadcasting data for [%d], data=%p", + (int)(info - STRUCT_SECTION_START(sensing_sensor_info)), data); + sys_mutex_lock(__sensing_connection_pool.lock, K_FOREVER); + for (int i = 0; i < __CONNECTION_POOL_COUNT; ++i) { + struct sensing_connection *connection = + &STRUCT_SECTION_START(sensing_connection)[i]; + if (!__sensing_is_connected(info, connection)) { + continue; } - } -} - -static int decode_float_data(int32_t type, struct sensing_sensor_float_data *out, - const struct sensor_decoder_api *decoder, void *data) -{ - uint16_t frame_count; - int rc; + sensing_data_event_t cb = connection->cb_list->on_data_event; - rc = decoder->get_frame_count(data, &frame_count); - if (rc != 0) { - return rc; - } - - __ASSERT_NO_MSG(frame_count == 1); - - sensor_frame_iterator_t fit = {0}; - sensor_channel_iterator_t cit = {0}; - enum sensor_channel channel; - bool has_shift = false; - - while (true) { - rc = decoder->decode(data, &fit, &cit, &channel, &out->readings[0].v, 1); - if (rc <= 0) { - return rc; - } - if (type == SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE && - channel == SENSOR_CHAN_ROTATION && !has_shift) { - rc = decoder->get_shift(data, channel, &out->shift); - if (rc != 0) { - return rc; - } - has_shift = true; + if (cb == NULL) { + continue; } + cb(connection, data, connection->userdata); } + sys_mutex_unlock(__sensing_connection_pool.lock); } static void processing_task(void *a, void *b, void *c) { - struct sensing_sensor_info *info; uint8_t *data = NULL; uint32_t data_len = 0; int rc; @@ -137,73 +60,21 @@ static void processing_task(void *a, void *b, void *c) /* Cache the data from the CQE */ rc = cqe.result; - info = cqe.userdata; + + /* Get the associated data */ get_data_rc = rtio_cqe_get_mempool_buffer(&sensing_rtio_ctx, &cqe, &data, &data_len); - - /* Do something with the data */ - LOG_DBG("Processing data for [%d], rc=%d, has_data=%d, data=%p, len=%" PRIu32, - (int)(info - STRUCT_SECTION_START(sensing_sensor_info)), rc, - get_data_rc == 0, (void *)data, data_len); - if (get_data_rc != 0 || data_len == 0) { continue; } - const struct sensor_decoder_api *decoder = NULL; - - rc = sensor_get_decoder(info->dev, &decoder); - if (rc != 0) { - LOG_ERR("Failed to get decoder"); - goto end; - } - - union { - struct sensing_sensor_three_axis_data three_axis_data; - struct sensing_sensor_float_data float_data; - } decoded_data; - - switch (info->type) { - case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: - case SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D: - case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: - rc = decode_three_axis_data(info->type, &decoded_data.three_axis_data, - decoder, data); - if (rc != 0) { - LOG_ERR("Failed to decode"); - goto end; - } - break; - case SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE: - rc = decode_float_data(info->type, &decoded_data.float_data, decoder, data); - if (rc != 0) { - LOG_ERR("Failed to decode"); - goto end; - } - break; - default: - LOG_ERR("Sensor type not supported"); - goto end; - } - - sys_mutex_lock(__sensing_connection_pool.lock, K_FOREVER); - for (int i = 0; i < __CONNECTION_POOL_COUNT; ++i) { - struct sensing_connection *connection = - &STRUCT_SECTION_START(sensing_connection)[i]; - if (!__sensing_is_connected(info, connection)) { - continue; - } - sensing_data_event_t cb = connection->cb_list->on_data_event; - - if (cb == NULL) { - continue; - } - cb(connection, &decoded_data, connection->userdata); + if ((uintptr_t)cqe.userdata >= + (uintptr_t)STRUCT_SECTION_START(sensing_sensor_info) && + (uintptr_t)cqe.userdata < (uintptr_t)STRUCT_SECTION_END(sensing_sensor_info)) { + // We got back a result for an info node + process_info_node(cqe.userdata, data); } - sys_mutex_unlock(__sensing_connection_pool.lock); - end: - /* Release the memory */ rtio_release_buffer(&sensing_rtio_ctx, data, data_len); } } diff --git a/subsys/sensing/src/sensor_connections.c b/subsys/sensing/src/sensor_connections.c index 9fdb2b5f56da22..c4991b963746aa 100644 --- a/subsys/sensing/src/sensor_connections.c +++ b/subsys/sensing/src/sensor_connections.c @@ -35,8 +35,10 @@ STRUCT_SECTION_ITERABLE_ARRAY(sensing_connection, dynamic_connections, #define __lock sys_mutex_lock(__sensing_connection_pool.lock, K_FOREVER) #define __unlock sys_mutex_unlock(__sensing_connection_pool.lock) -RTIO_DEFINE_WITH_MEMPOOL(sensing_rtio_ctx, 32, 32, CONFIG_SENSING_RTIO_BLOCK_COUNT, - CONFIG_SENSING_RTIO_BLOCK_SIZE, 4); +Z_RTIO_BLOCK_POOL_DEFINE_SCOPED((), sensing_rtio_block_pool, CONFIG_SENSING_RTIO_BLOCK_COUNT, + CONFIG_SENSING_RTIO_BLOCK_SIZE, 4); + +RTIO_DEFINE_WITH_EXT_MEMPOOL(sensing_rtio_ctx, 32, 32, sensing_rtio_block_pool); int sensing_open_sensor(const struct sensing_sensor_info *info, const struct sensing_callback_list *cb_list, diff --git a/subsys/sensing/src/sensor_pipe.c b/subsys/sensing/src/sensor_pipe.c index 5977066a251722..552a123834a843 100644 --- a/subsys/sensing/src/sensor_pipe.c +++ b/subsys/sensing/src/sensor_pipe.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "sensing/internal/sensing.h" @@ -17,10 +18,13 @@ LOG_MODULE_REGISTER(sensing_pipe, CONFIG_SENSING_LOG_LEVEL); struct sensor_pipe_config { const struct sensor_info *parent_info; + struct rtio *rtio_ctx; + const struct sensor_decoder_api *decoder; }; struct sensor_pipe_data { struct rtio_iodev *oneshot_iodev; + uint8_t *data; }; static int attribute_set(const struct device *dev, enum sensor_channel chan, @@ -34,6 +38,7 @@ static int attribute_set(const struct device *dev, enum sensor_channel chan, static int submit(const struct device *sensor, struct rtio_iodev_sqe *sqe) { + const struct sensor_pipe_config *config = sensor->config; struct sensor_pipe_data *data = sensor->data; const struct sensing_sensor_info *info = sqe->sqe.userdata; @@ -41,27 +46,86 @@ static int submit(const struct device *sensor, struct rtio_iodev_sqe *sqe) LOG_DBG("Trying to read %s [%d] type=%d", info->info->dev->name, (int)(info - STRUCT_SECTION_START(sensing_sensor_info)), info->type); - int rc = sensor_read(data->oneshot_iodev, &sensing_rtio_ctx, sqe->sqe.userdata); + LOG_DBG("RTIO ctx %p", (void*)config->rtio_ctx); + k_msleep(50); + int rc = sensor_read(data->oneshot_iodev, config->rtio_ctx, sqe); - if (rc == 0) { - rtio_iodev_sqe_ok(sqe, 0); - } else { + if (rc != 0) { rtio_iodev_sqe_err(sqe, rc); + return 0; } - return rc; -} -static int get_decoder(const struct device *sensor, const struct sensor_decoder_api **api) -{ - const struct sensor_pipe_config *cfg = sensor->config; + struct rtio_cqe cqe; + + rc = rtio_cqe_copy_out(config->rtio_ctx, &cqe, 1, K_FOREVER); + if (rc != 1) { + rtio_iodev_sqe_err(sqe, rc); + return 0; + } + + uint8_t *read_data; + uint32_t read_data_len; - return sensor_get_decoder(cfg->parent_info->dev, api); + rc = rtio_cqe_get_mempool_buffer(&sensing_rtio_ctx, &cqe, &read_data, &read_data_len); + if (rc != 0) { + rtio_iodev_sqe_err(sqe, rc); + return 0; + } + + uint8_t *buffer; + uint32_t buffer_len; + + /* Decode the data here and post it as a result to the cqe */ + switch (info->type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + case SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D: + case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: + rc = rtio_sqe_rx_buf(sqe, sizeof(struct sensing_sensor_three_axis_data), + sizeof(struct sensing_sensor_three_axis_data), &buffer, + &buffer_len); + if (rc != 0) { + rtio_iodev_sqe_err(sqe, rc); + break; + } + rc = decode_three_axis_data(info->type, + (struct sensing_sensor_three_axis_data *)buffer, + config->decoder, read_data); + if (rc != 0) { + LOG_ERR("Failed to decode"); + rtio_iodev_sqe_err(sqe, rc); + } else { + rtio_iodev_sqe_ok(sqe, 0); + } + break; + case SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE: + rc = rtio_sqe_rx_buf(sqe, sizeof(struct sensing_sensor_float_data), + sizeof(struct sensing_sensor_float_data), &buffer, + &buffer_len); + if (rc != 0) { + rtio_iodev_sqe_err(sqe, rc); + break; + } + rc = decode_float_data(info->type, (struct sensing_sensor_float_data *)buffer, + config->decoder, read_data); + if (rc != 0) { + LOG_ERR("Failed to decode"); + rtio_iodev_sqe_err(sqe, rc); + } else { + rtio_iodev_sqe_ok(sqe, 0); + } + break; + default: + LOG_ERR("Sensor type not supported"); + rtio_iodev_sqe_err(sqe, -ENOTSUP); + } + rtio_release_buffer(&sensing_rtio_ctx, read_data, read_data_len); + return 0; } SENSING_DMEM static const struct sensor_driver_api sensor_pipe_api = { .attr_set = attribute_set, .attr_get = NULL, - .get_decoder = get_decoder, + .get_decoder = NULL, .submit = submit, }; @@ -74,8 +138,11 @@ static int sensing_sensor_pipe_init(const struct device *dev) } #define SENSING_PIPE_INIT(inst) \ + RTIO_DEFINE_WITH_EXT_MEMPOOL(rtio_##inst, 4, 4, sensing_rtio_block_pool); \ static const struct sensor_pipe_config cfg_##inst = { \ .parent_info = &SENSOR_INFO_DT_NAME(DT_INST_PHANDLE(inst, dev)), \ + .rtio_ctx = &rtio_##inst, \ + .decoder = SENSOR_DECODER_DT_GET(DT_INST_PHANDLE(inst, dev)), \ }; \ SENSOR_DT_READ_IODEV(underlying_reader_##inst, DT_INST_PHANDLE(inst, dev), \ SENSOR_CHAN_ALL); \ diff --git a/subsys/sensing/vsensors/accel-based-angle/driver.c b/subsys/sensing/vsensors/accel-based-angle/driver.c index d91709618e29f2..0b4647baceab3e 100644 --- a/subsys/sensing/vsensors/accel-based-angle/driver.c +++ b/subsys/sensing/vsensors/accel-based-angle/driver.c @@ -73,82 +73,12 @@ static int submit(const struct device *sensor, struct rtio_iodev_sqe *sqe) data->pending_read = sqe; } return 0; -} - -struct encoded_data { - uint64_t timestamp_ns; - int8_t shift; - q31_t val; -} __packed; - -static int decoder_get_frame_count(const uint8_t *buffer, uint16_t *frame_count) -{ - ARG_UNUSED(buffer); - *frame_count = 1; - return 0; -} - -static int decoder_get_timestamp(const uint8_t *buffer, uint64_t *timestamp_ns) -{ - *timestamp_ns = ((struct encoded_data *)buffer)->timestamp_ns; - return 0; -} - -static bool decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) -{ - ARG_UNUSED(buffer); - ARG_UNUSED(trigger); - return false; -} - -static int decoder_get_shift(const uint8_t *buffer, enum sensor_channel channel_type, int8_t *shift) -{ - ARG_UNUSED(buffer); - - if (channel_type != SENSOR_CHAN_ROTATION) { - return -EINVAL; - } - *shift = ((struct encoded_data *)buffer)->shift; - return 0; -} - -static int decoder_decode(const uint8_t *buffer, sensor_frame_iterator_t *fit, - sensor_channel_iterator_t *cit, enum sensor_channel *channels, - q31_t *values, uint8_t max_count) -{ - if (*fit != 0) { - return 0; - } - if (*cit > 0) { - return -EINVAL; - } - - values[0] = ((struct encoded_data *)buffer)->val; - channels[0] = SENSOR_CHAN_ROTATION; - *fit = 1; - *cit = 0; - return 1; -} - -SENSING_DMEM static const struct sensor_decoder_api decoder_api = { - .get_frame_count = decoder_get_frame_count, - .get_timestamp = decoder_get_timestamp, - .has_trigger = decoder_has_trigger, - .get_shift = decoder_get_shift, - .decode = decoder_decode, -}; - -static int get_decoder(const struct device *dev, const struct sensor_decoder_api **api) -{ - ARG_UNUSED(dev); - *api = &decoder_api; - return 0; -} +}v SENSING_DMEM static const struct sensor_driver_api angle_api = { .attr_set = attribute_set, .attr_get = NULL, - .get_decoder = get_decoder, + .get_decoder = NULL, .submit = submit, }; @@ -248,21 +178,22 @@ static void on_data_event(sensing_sensor_handle_t handle, const void *buf, void uint8_t *out_buf; uint32_t buf_len; - int rc = rtio_sqe_rx_buf(data->pending_read, sizeof(struct encoded_data), - sizeof(struct encoded_data), &out_buf, &buf_len); + int rc = rtio_sqe_rx_buf(data->pending_read, sizeof(struct sensing_sensor_float_data), + sizeof(struct sensing_sensor_float_data), &out_buf, &buf_len); if (rc != 0) { rtio_iodev_sqe_err(data->pending_read, rc); data->pending_read = NULL; return; } - struct encoded_data *edata = (struct encoded_data *)out_buf; - edata->timestamp_ns = MAX(data->plane0_latest_sample.header.base_timestamp, + struct sensing_sensor_float_data *edata = (struct sensing_sensor_float_data *)out_buf; + edata->header.base_timestamp = MAX(data->plane0_latest_sample.header.base_timestamp, data->plane1_latest_sample.header.base_timestamp); + edata->header.reading_count = 1; edata->shift = ilog2(llabs(integer_part)) + 1; int8_t extra_shift = (47 - shift * 2) - (31 - edata->shift) + 1; - edata->val = FIELD_GET(GENMASK(31, 0), result >> extra_shift); - LOG_DBG("shift=%d, val=0x%08" PRIx32, edata->shift, edata->val); + edata->readings[0].v = FIELD_GET(GENMASK(31, 0), result >> extra_shift); + LOG_DBG("shift=%d, val=0x%08" PRIx32, edata->shift, edata->readings[0].v); rtio_iodev_sqe_ok(data->pending_read, 0); data->pending_read = NULL; } diff --git a/subsys/sensing/vsensors/emul/driver.c b/subsys/sensing/vsensors/emul/driver.c index b4ea50bbe6956e..84cd00147a7eb2 100644 --- a/subsys/sensing/vsensors/emul/driver.c +++ b/subsys/sensing/vsensors/emul/driver.c @@ -18,48 +18,56 @@ struct drv_config { struct drv_data { }; -static inline bool is_channel_supported(const struct drv_config *cfg, enum sensor_channel channel) -{ - int32_t required_type; - - switch (channel) { - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - case SENSOR_CHAN_ACCEL_XYZ: - required_type = SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D; - break; - default: - return false; - } - - for (size_t i = 0; i < cfg->info_count; ++i) { - if (cfg->info[i]->type == required_type) { - return true; - } - } - return false; -} - static int attribute_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { return 0; } -struct raw_data { - uint64_t timestamp_ns; - uint8_t count; - enum sensor_channel channels[0]; -} __packed; +static int is_channel_supported(enum sensor_channel channel, const struct drv_config *cfg) +{ + for (int i = 0; i < cfg->info_count; ++i) { + int32_t type = cfg->info[i]->type; + switch (channel) { + case SENSOR_CHAN_ALL: + return i; + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + if (type == SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D || + type == SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D) { + return i; + } + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + if (type == SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D) { + return i; + } + break; + case SENSOR_CHAN_ROTATION: + if (type == SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE) { + return i; + } + break; + default: + break; + } + } + + return -1; +} static int submit(const struct device *sensor, struct rtio_iodev_sqe *sqe) { const struct drv_config *cfg = sensor->config; const struct sensor_read_config *read_cfg = sqe->sqe.iodev->data; + const struct sensing_sensor_info *info = NULL; uint8_t *buf; uint32_t buf_len; - uint8_t channel_count = 0; int rc; if (read_cfg->is_streaming) { @@ -68,137 +76,86 @@ static int submit(const struct device *sensor, struct rtio_iodev_sqe *sqe) } /* For now just assume the user wants to read all the channels */ - for (size_t i = 0; i < cfg->info_count; ++i) { - switch (cfg->info[i]->type) { - case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: - case SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D: - case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: - channel_count += 3; - break; - case SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE: - channel_count += 1; - break; - default: - rtio_iodev_sqe_err(sqe, -ENOTSUP); - return 0; - } - } - - const uint32_t desired_size = - sizeof(struct raw_data) + channel_count * sizeof(enum sensor_channel); - rc = rtio_sqe_rx_buf(sqe, desired_size, desired_size, &buf, &buf_len); - if (rc != 0) { - rtio_iodev_sqe_err(sqe, rc); - return 0; - } - - ((struct raw_data *)buf)->timestamp_ns = k_ticks_to_ns_floor64(k_uptime_ticks()); - ((struct raw_data *)buf)->count = channel_count; - buf += sizeof(struct raw_data); - - int count = 0; - for (size_t i = 0; i < cfg->info_count; ++i) { - switch (cfg->info[i]->type) { - case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: - case SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D: - ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_ACCEL_X; - ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_ACCEL_Y; - ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_ACCEL_Z; - break; - case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: - ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_GYRO_X; - ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_GYRO_Y; - ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_GYRO_Z; + for (size_t i = 0; i < read_cfg->count; ++i) { + int idx = is_channel_supported(read_cfg->channels[i], cfg); + if (idx >= 0) { + info = cfg->info[idx]; break; - case SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE: - ((enum sensor_channel *)buf)[count++] = SENSOR_CHAN_ROTATION; - break; - default: - rtio_iodev_sqe_err(sqe, -ENOTSUP); - return 0; } } - rtio_iodev_sqe_ok(sqe, 0); - return 0; -} - -static int decoder_get_frame_count(const uint8_t *buffer, uint16_t *frame_count) -{ - ARG_UNUSED(buffer); - *frame_count = 1; - return 0; -} - -static int decoder_get_timestamp(const uint8_t *buffer, uint64_t *timestamp_ns) -{ - *timestamp_ns = ((uint64_t *)buffer)[0]; - return 0; -} - -static bool decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) -{ - ARG_UNUSED(buffer); - ARG_UNUSED(trigger); - return false; -} - -static int decoder_get_shift(const uint8_t *buffer, enum sensor_channel channel_type, int8_t *shift) -{ - ARG_UNUSED(buffer); - ARG_UNUSED(channel_type); - *shift = 0; - return 0; -} - -static int decoder_decode(const uint8_t *buffer, sensor_frame_iterator_t *fit, - sensor_channel_iterator_t *cit, enum sensor_channel *channels, - q31_t *values, uint8_t max_count) -{ - if (*fit != 0) { + if (info == NULL) { + LOG_ERR("Invalid read request"); + rtio_iodev_sqe_err(sqe, -EINVAL); return 0; } - const struct raw_data *data = (const struct raw_data *)buffer; - int count = 0; - - if (*cit >= data->count) { - return -EINVAL; - } - - while (*cit < data->count && count < max_count) { - channels[count] = data->channels[*cit]; - values[count++] = INT32_MAX; - *cit += 1; - } - - if (*cit == data->count) { - *fit += 1; - *cit = 0; + switch (info->type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + case SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D: + rc = rtio_sqe_rx_buf(sqe, sizeof(struct sensing_sensor_three_axis_data), + sizeof(struct sensing_sensor_three_axis_data), &buf, &buf_len); + if (rc != 0) { + rtio_iodev_sqe_err(sqe, rc); + } else { + struct sensing_sensor_three_axis_data *edata = + (struct sensing_sensor_three_axis_data *)buf; + edata->header.base_timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + edata->header.reading_count = 1; + edata->shift = 4; + edata->readings[0].timestamp_delta = 0; + edata->readings[0].x = (q31_t)((9.8f / 16.0f) * INT32_MAX); + edata->readings[0].y = 0; + edata->readings[0].z = 0; + rtio_iodev_sqe_ok(sqe, 0); + } + break; + case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: + rc = rtio_sqe_rx_buf(sqe, sizeof(struct sensing_sensor_three_axis_data), + sizeof(struct sensing_sensor_three_axis_data), &buf, &buf_len); + if (rc != 0) { + rtio_iodev_sqe_err(sqe, rc); + } else { + struct sensing_sensor_three_axis_data *edata = + (struct sensing_sensor_three_axis_data *)buf; + edata->header.base_timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + edata->header.reading_count = 1; + edata->shift = 0; + edata->readings[0].timestamp_delta = 0; + edata->readings[0].x = 0; + edata->readings[0].y = 0; + edata->readings[0].z = 0; + rtio_iodev_sqe_ok(sqe, 0); + } + break; + case SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE: + rc = rtio_sqe_rx_buf(sqe, sizeof(struct sensing_sensor_float_data), + sizeof(struct sensing_sensor_float_data), &buf, &buf_len); + if (rc != 0) { + rtio_iodev_sqe_err(sqe, rc); + } else { + struct sensing_sensor_float_data *edata = + (struct sensing_sensor_float_data *)buf; + edata->header.base_timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + edata->header.reading_count = 1; + edata->shift = 0; + edata->readings[0].timestamp_delta = 0; + edata->readings[0].v = 0; + rtio_iodev_sqe_ok(sqe, 0); + } + break; + default: + rtio_iodev_sqe_err(sqe, -ENOTSUP); + break; } - return count; -} - -SENSING_DMEM static const struct sensor_decoder_api decoder_api = { - .get_frame_count = decoder_get_frame_count, - .get_timestamp = decoder_get_timestamp, - .has_trigger = decoder_has_trigger, - .get_shift = decoder_get_shift, - .decode = decoder_decode, -}; - -static int get_decoder(const struct device *dev, const struct sensor_decoder_api **api) -{ - ARG_UNUSED(dev); - *api = &decoder_api; return 0; } SENSING_DMEM static const struct sensor_driver_api emul_api = { .attr_set = attribute_set, .attr_get = NULL, - .get_decoder = get_decoder, + .get_decoder = NULL, .submit = submit, };