e69ce68d40
Initializers must be compile time constants (not expressions!) for clang to be happy. Clang rightfully pointed out that the callback_list member of sensing_connection was being initialized using an expression that was not compile-time constant. The macros passed along a pointer created by taking the address of a global constant and then at initialization time attempting to dereference it using the * operator. So in the end the compiler has identifier its trying to first take the address of and then later dereference in an initializer. Clang didn't appreciate this, though gcc seemed to be just fine. Actually clang 17 might work just fine with this as well, but clang 16 (the clang I tried) didn't like it at all. Instead store the pointer to the callback list rather than copying the struct. This could be done the other way and not passing a pointer through the macros perhaps. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
125 lines
3.2 KiB
C
125 lines
3.2 KiB
C
/*
|
|
* Copyright (c) 2022 Intel Corporation.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include <zephyr/sys/__assert.h>
|
|
#include <zephyr/logging/log.h>
|
|
#include <zephyr/rtio/rtio.h>
|
|
#include <zephyr/sensing/sensing_sensor.h>
|
|
#include "sensor_mgmt.h"
|
|
|
|
LOG_MODULE_DECLARE(sensing, CONFIG_SENSING_LOG_LEVEL);
|
|
|
|
/* check whether it is right time for client to consume this sample */
|
|
static inline bool sensor_test_consume_time(struct sensing_sensor *sensor,
|
|
struct sensing_connection *conn,
|
|
uint64_t cur_time)
|
|
{
|
|
LOG_DBG("sensor:%s next_consume_time:%lld cur_time:%lld",
|
|
sensor->dev->name, conn->next_consume_time, cur_time);
|
|
|
|
return conn->next_consume_time <= cur_time;
|
|
}
|
|
|
|
static void update_client_consume_time(struct sensing_sensor *sensor,
|
|
struct sensing_connection *conn)
|
|
{
|
|
uint32_t interval = conn->interval;
|
|
|
|
if (conn->next_consume_time == 0) {
|
|
conn->next_consume_time = get_us();
|
|
}
|
|
|
|
conn->next_consume_time += interval;
|
|
}
|
|
|
|
/* send data to clients based on interval and sensitivity */
|
|
static int send_data_to_clients(struct sensing_sensor *sensor,
|
|
void *data)
|
|
{
|
|
struct sensing_sensor *client;
|
|
struct sensing_connection *conn;
|
|
|
|
for_each_client_conn(sensor, conn) {
|
|
client = conn->sink;
|
|
LOG_DBG("sensor:%s send data to client:%p", conn->source->dev->name, conn);
|
|
|
|
if (!is_client_request_data(conn)) {
|
|
continue;
|
|
}
|
|
|
|
/* sensor_test_consume_time(), check whether time is ready or not:
|
|
* true: it's time for client consuming the data
|
|
* false: client time not arrived yet, not consume the data
|
|
*/
|
|
if (!sensor_test_consume_time(sensor, conn, get_us())) {
|
|
continue;
|
|
}
|
|
|
|
update_client_consume_time(sensor, conn);
|
|
|
|
if (!conn->callback_list->on_data_event) {
|
|
LOG_WRN("sensor:%s event callback not registered",
|
|
conn->source->dev->name);
|
|
continue;
|
|
}
|
|
conn->callback_list->on_data_event(conn, data,
|
|
conn->callback_list->context);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
STRUCT_SECTION_START_EXTERN(sensing_sensor);
|
|
STRUCT_SECTION_END_EXTERN(sensing_sensor);
|
|
|
|
static void dispatch_task(void *a, void *b, void *c)
|
|
{
|
|
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(dispatch_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;
|
|
|
|
/* Get the associated data */
|
|
get_data_rc =
|
|
rtio_cqe_get_mempool_buffer(&sensing_rtio_ctx, &cqe, &data, &data_len);
|
|
if (get_data_rc != 0 || data_len == 0) {
|
|
continue;
|
|
}
|
|
|
|
if ((uintptr_t)cqe.userdata >=
|
|
(uintptr_t)STRUCT_SECTION_START(sensing_sensor) &&
|
|
(uintptr_t)cqe.userdata < (uintptr_t)STRUCT_SECTION_END(sensing_sensor)) {
|
|
struct sensing_sensor *sensor = cqe.userdata;
|
|
|
|
send_data_to_clients(sensor, data);
|
|
}
|
|
|
|
rtio_release_buffer(&sensing_rtio_ctx, data, data_len);
|
|
}
|
|
}
|
|
|
|
K_THREAD_DEFINE(sensing_dispatch, CONFIG_SENSING_DISPATCH_THREAD_STACK_SIZE, dispatch_task,
|
|
NULL, NULL, NULL, CONFIG_SENSING_DISPATCH_THREAD_PRIORITY, 0, 0);
|