sensing: initial sensor list and enumerate each sensor

Implement sensing_init():
	1) create sensors from device tree
	2) sequence sensors following node dependency ordering rule generated by
	   Zephyr DTS
	3) initial each sensor, includes:
		a) creating sensor connection between reporter and client,
		b) calling sensor init callback,
		c) setting sensor state
Implement sensing_open_sensor():
	1) malloc connection from reporter to application
	2) bind connection
Implement sensing_close_sensr():
	1) unbind connection
	2) free connection from reporter to application
Implement sensing_set_config():
	1) call set_interval
	2) cann set_sensitivity
Implement sensing_get_config():
	1) call get_interval
	2) call get_sensitivity

Signed-off-by: Guangfu Hu <guangfu.hu@intel.com>
This commit is contained in:
Guangfu Hu 2023-05-19 10:26:13 +08:00 committed by Anas Nashif
parent 25ca09ea01
commit 335278d60a
8 changed files with 561 additions and 13 deletions

View file

@ -54,6 +54,10 @@ if(CONFIG_NETWORKING)
zephyr_iterable_section(NAME eth_bridge GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4)
endif()
if(CONFIG_SENSING)
zephyr_iterable_section(NAME sensing_sensor GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4)
endif()
if(CONFIG_UART_MUX)
zephyr_iterable_section(NAME uart_mux GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4)
endif()

View file

@ -136,6 +136,10 @@ if(CONFIG_SETTINGS)
zephyr_iterable_section(NAME settings_handler_static KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4)
endif()
if(CONFIG_SENSING)
zephyr_iterable_section(NAME sensing_sensor_info KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4)
endif()
if(CONFIG_SENSOR_INFO)
zephyr_iterable_section(NAME sensor_info KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4)
endif()

View file

@ -120,6 +120,10 @@
ITERABLE_SECTION_RAM(rtio_cqe_pool, 4)
#endif /* CONFIG_RTIO */
#if defined(CONFIG_SENSING)
ITERABLE_SECTION_RAM(sensing_sensor, 4)
#endif /* CONFIG_SENSING */
#ifdef CONFIG_USERSPACE
_static_kernel_objects_end = .;
#endif

View file

@ -10,6 +10,10 @@
ITERABLE_SECTION_ROM(settings_handler_static, 4)
#endif
#if defined(CONFIG_SENSING)
ITERABLE_SECTION_ROM(sensing_sensor_info, 4)
#endif
#if defined(CONFIG_SENSOR_INFO)
ITERABLE_SECTION_ROM(sensor_info, 4)
#endif

View file

@ -14,4 +14,16 @@ 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

View file

@ -6,46 +6,140 @@
#include <zephyr/sensing/sensing.h>
#include <zephyr/sensing/sensing_sensor.h>
#include <stdlib.h>
#include "sensor_mgmt.h"
#include <zephyr/logging/log.h>
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 *info,
int sensing_open_sensor(const struct sensing_sensor_info *sensor_info,
const struct sensing_callback_list *cb_list,
sensing_sensor_handle_t *handle)
{
return -ENOTSUP;
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)
{
return -ENOTSUP;
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)
int sensing_close_sensor(sensing_sensor_handle_t *handle)
{
return -ENOTSUP;
return close_sensor((struct sensing_connection **)handle);
}
int sensing_set_config(sensing_sensor_handle_t handle,
struct sensing_sensor_config *configs,
int count)
{
return -ENOTSUP;
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)
{
return -ENOTSUP;
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 NULL;
return get_sensor_info(handle);
}

View file

@ -15,18 +15,309 @@
#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);
static struct sensing_mgmt_context sensing_ctx = {0};
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);

View file

@ -9,16 +9,151 @@
#include <zephyr/sensing/sensing_datatypes.h>
#include <zephyr/sensing/sensing_sensor.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/slist.h>
#ifdef __cplusplus
extern "C" {
#endif
struct sensing_mgmt_context {
bool sensing_initialized;
int sensor_num;
struct sensing_sensor_info *info;
#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;
}
/**
* @}
*/