* This patch also includes new tests to test batch events related APIs at sensorctl
Change-Id: If59c1b43b10c6b39bf72687bfb67eb9e305fe62b
Signed-off-by: Boram Bae <boram21.bae@samsung.com>
SENSOR_DEVICE_GSR,
SENSOR_DEVICE_SIMSENSE,
SENSOR_DEVICE_PPG,
-
} sensor_device_type;
/*
#endif
typedef void (*sensor_cb_t)(sensor_t sensor, unsigned int event_type, sensor_data_t *data, void *user_data);
+typedef void (*sensor_events_cb_t)(sensor_t sensor, unsigned int event_type, sensor_data_t* events[], int events_count, void *user_data);
typedef void (*sensorhub_cb_t)(sensor_t sensor, unsigned int event_type, sensorhub_data_t *data, void *user_data);
typedef void (*sensor_accuracy_changed_cb_t) (sensor_t sensor, unsigned long long timestamp, int accuracy, void *user_data);
bool sensord_register_event(int handle, unsigned int event_type, unsigned int interval, unsigned int max_batch_latency, sensor_cb_t cb, void *user_data);
/**
+ * @brief Register a callback with a connected sensor for a given event_type. This callback will be called when a given event occurs in a connected sensor.
+ *
+ * @param[in] handle a handle represensting a connected sensor.
+ * @param[in] event_type an event type to register
+ * @param[in] max_batch_latency An event in the batch can be delayed by at most max_batch_latency microseconds. If this is set to zero, batch mode is disabled.
+ * @param[in] cb a callback which is called when a given event occurs
+ * @param[in] user_data the callback is called with user_data
+ * @return true on success, otherwise false.
+ */
+bool sensord_register_events(int handle, unsigned int event_type, unsigned int max_batch_latency, sensor_events_cb_t cb, void *user_data);
+
+/**
* @brief Register a callback with a connected context sensor for a given event_type. This callback will be called when a given event occurs in a connected context sensor.
*
* @param[in] handle a handle represensting a connected context sensor.
bool sensord_unregister_event(int handle, unsigned int event_type);
/**
+ * @brief Unregister a event with a connected sensor. After unregistering, that event will not be sent.
+ *
+ * @param[in] handle a handle represensting a connected sensor.
+ * @param[in] event_type an event type to unregister.
+ * @return true on success, otherwise false.
+ */
+bool sensord_unregister_events(int handle, unsigned int event_type);
+
+/**
* @brief Register a callback with a connected sensor. This callback will be called when the accuracy of a sensor has changed.
*
* @param[in] handle a handle represensting a connected sensor.
int sensord_provider_set_attribute_str_cb(sensord_provider_h provider, sensord_provider_attribute_str_cb callback, void *user_data);
int sensord_provider_publish(sensord_provider_h provider, sensor_data_t data);
+int sensord_provider_publish_events(sensord_provider_h provider, sensor_data_t events[], int count);
/* Deprecated */
typedef void (*sensor_external_command_cb_t)(int handle, const char* data, int data_cnt, void *user_data);
return false;
}
+API bool sensord_register_events(int handle, unsigned int event_type, unsigned int max_batch_latency, sensor_events_cb_t cb, void *user_data)
+{
+ return false;
+}
+
+API bool sensord_unregister_events(int handle, unsigned int event_type)
+{
+ return false;
+}
+
API bool sensord_register_accuracy_cb(int handle, sensor_accuracy_changed_cb_t cb, void *user_data)
{
return false;
{
return OP_ERROR;
}
+
+API int sensord_provider_publish_events(sensord_provider_h provider, sensor_data_t events[], int count)
+{
+ return OP_ERROR;
+}
typedef struct {
int listener_id;
- sensor_cb_t cb;
+ void* cb;
+ bool is_events_cb;
sensor_accuracy_changed_cb_t acc_cb;
sensor_info *sensor;
- sensor_data_t *data;
+ char* data;
+ size_t data_size;
void *user_data;
} callback_info_s;
if (info->sensor)
event_type = CONVERT_TYPE_EVENT(info->sensor->get_type());
- if (info->cb && info->sensor && listeners.find(info->listener_id) != listeners.end())
- info->cb(info->sensor, event_type, info->data, info->user_data);
+ if (info->cb && info->sensor && listeners.find(info->listener_id) != listeners.end()) {
+ if (info->is_events_cb) {
+ size_t element_size = sizeof(sensor_data_t);
+ size_t count = info->data_size / element_size;
+ sensor_data_t *events[count];
+ char* p = (char*)info->data;
+ for (size_t i = 0 ; i < count; ++i) {
+ events[i] = (sensor_data_t *)(p + i * element_size);
+ }
+ ((sensor_events_cb_t)info->cb)(info->sensor, event_type, events, count, info->user_data);
+ } else {
+ ((sensor_cb_t)info->cb)(info->sensor, event_type, (sensor_data_t*)info->data, info->user_data);
+ }
+ }
delete [] info->data;
delete info;
AUTOLOCK(lock);
- if (info->acc_cb && info->sensor && listeners.find(info->listener_id) != listeners.end())
- info->acc_cb(info->sensor, info->data->timestamp, info->data->accuracy, info->user_data);
+ if (info->acc_cb && info->sensor && listeners.find(info->listener_id) != listeners.end()) {
+ sensor_data_t * data = (sensor_data_t *)info->data;
+ info->acc_cb(info->sensor, data->timestamp, data->accuracy, info->user_data);
+ }
delete [] info->data;
delete info;
class sensor_event_handler : public ipc::channel_handler
{
public:
- sensor_event_handler(int id, sensor_t sensor, sensor_cb_t cb, void *user_data)
+ sensor_event_handler(int id, sensor_t sensor, void* cb, bool is_events_cb, void *user_data)
: m_listener_id(id)
, m_sensor(reinterpret_cast<sensor_info *>(sensor))
, m_cb(cb)
, m_user_data(user_data)
+ , m_is_events_cb(is_events_cb)
{}
void connected(ipc::channel *ch) {}
void read(ipc::channel *ch, ipc::message &msg)
{
callback_info_s *info;
- sensor_data_t *data = (sensor_data_t *) new(std::nothrow) char[msg.size()];
+ auto size = msg.size();
+ char *data = new(std::nothrow) char[size];
- memcpy(data, msg.body(), msg.size());
+ memcpy(data, msg.body(), size);
info = new(std::nothrow) callback_info_s();
info->listener_id = m_listener_id;
info->cb = m_cb;
info->sensor = m_sensor;
info->data = data;
+ info->data_size = size;
info->user_data = m_user_data;
+ info->is_events_cb = m_is_events_cb;
g_idle_add(callback_dispatcher, info);
}
private:
int m_listener_id;
sensor_info *m_sensor;
- sensor_cb_t m_cb;
+ void* m_cb;
void *m_user_data;
+ bool m_is_events_cb;
};
class sensor_accuracy_handler : public ipc::channel_handler
void read(ipc::channel *ch, ipc::message &msg)
{
callback_info_s *info;
- sensor_data_t *data = (sensor_data_t *) new(std::nothrow) char[msg.size()];
+ char *data = new(std::nothrow) char[msg.size()];
memcpy(data, msg.body(), msg.size());
return true;
}
-API bool sensord_register_event(int handle, unsigned int event_type,
- unsigned int interval, unsigned int max_batch_latency, sensor_cb_t cb, void *user_data)
+static inline bool sensord_register_event_impl(int handle, unsigned int event_type,
+ unsigned int interval, unsigned int max_batch_latency, void* cb, bool is_events_callback, void *user_data)
{
sensor::sensor_listener *listener;
int prev_interval;
return false;
}
- handler = new(std::nothrow) sensor_event_handler(handle, listener->get_sensor(), cb, user_data);
+ handler = new(std::nothrow) sensor_event_handler(handle, listener->get_sensor(), cb, is_events_callback, user_data);
if (!handler) {
listener->set_max_batch_latency(prev_max_batch_latency);
listener->set_interval(prev_interval);
return true;
}
-API bool sensord_unregister_event(int handle, unsigned int event_type)
+API bool sensord_register_event(int handle, unsigned int event_type,
+ unsigned int interval, unsigned int max_batch_latency, sensor_cb_t cb, void *user_data)
+{
+ return sensord_register_event_impl(handle, event_type, interval, max_batch_latency, (void*)cb, false, user_data);
+}
+
+static inline bool sensord_unregister_event_imple(int handle)
{
sensor::sensor_listener *listener;
return true;
}
+API bool sensord_unregister_event(int handle, unsigned int event_type)
+{
+ return sensord_unregister_event_imple(handle);
+}
+
+API bool sensord_register_events(int handle, unsigned int event_type, unsigned int max_batch_latency, sensor_events_cb_t cb, void *user_data)
+{
+ return sensord_register_event_impl(handle, event_type, 0, max_batch_latency, (void*)cb, true, user_data);
+}
+
+API bool sensord_unregister_events(int handle, unsigned int event_type)
+{
+ return sensord_unregister_event_imple(handle);
+}
+
API bool sensord_register_accuracy_cb(int handle, sensor_accuracy_changed_cb_t cb, void *user_data)
{
sensor::sensor_listener *listener;
sensor_provider *p = static_cast<sensor_provider *>(provider);
/* TODO: synchronous call is enough? */
- return p->publish(&data, sizeof(data));
+ return p->publish(data);
}
+API int sensord_provider_publish_events(sensord_provider_h provider, sensor_data_t events[], int count)
+{
+ retvm_if(!provider, -EINVAL, "Invalid paramter");
+
+ sensor_provider *p = static_cast<sensor_provider *>(provider);
+
+ return p->publish(events, count);
+};
+
/* deperecated */
API sensor_t sensord_get_sensor(sensor_type_t type)
{
return true;
}
-static std::unordered_map<int, sensord_provider_h> external_providers;
-static int provider_id = 0;
-
-typedef struct external_cb_info_s {
- int id;
- sensor_external_command_cb_t cb;
- void *user_data;
-} external_cb_info_s;
-
-static void external_attr_cb(sensord_provider_h provider, int attribute, const char *data, int cnt, void *user_data)
-{
- external_cb_info_s *info = (external_cb_info_s *)user_data;
-
- if (info->cb)
- info->cb(info->id, data, cnt, info->user_data);
-}
-
/* deprecated */
API int sensord_external_connect(const char *key, sensor_external_command_cb_t cb, void *user_data)
{
_D("Restored provider[%s]", get_uri());
}
-int sensor_provider::publish(sensor_data_t *data, int len)
+int sensor_provider::publish(const sensor_data_t &data)
{
ipc::message msg;
msg.set_type(CMD_PROVIDER_PUBLISH);
- msg.enclose((const char *)data, len);
+ msg.enclose((const void *)(&data), sizeof(data));
+
+ m_channel->send_sync(&msg);
+
+ return OP_SUCCESS;
+}
+
+int sensor_provider::publish(const sensor_data_t data[], const int count)
+{
+ ipc::message msg;
+ msg.set_type(CMD_PROVIDER_PUBLISH);
+ msg.enclose((const void *)data, sizeof(sensor_data_t) * count);
m_channel->send_sync(&msg);
void set_interval_cb(sensord_provider_interval_changed_cb cb, void *user_data);
void set_attribute_str_cb(sensord_provider_attribute_str_cb cb, void *user_data);
- int publish(sensor_data_t *data, int len);
+ int publish(const sensor_data_t &data);
+ int publish(const sensor_data_t data[], const int count);
private:
class channel_handler;
bool m_some_speed;
sensor_frequency_compensator m_acceleration_compensator;
-
};
#endif /* __PEDOMETER_H__ */
/************************************************************************
*/
bool is_slow_step(void);
-
};
#endif /* __STEP_DETECTION_H__ */
#define SENSOR_EVENT(type) ((type) << 16 | 0x1)
+bool sensor_adapter::is_batch_mode = false;
+
bool sensor_adapter::is_supported(sensor_type_t type)
{
sensor_t sensor;
handle = sensord_connect(sensors[info.index]);
ASSERT_GE(handle, 0);
- ret = sensord_register_event(handle, SENSOR_EVENT(info.type), info.interval, info.batch_latency, info.cb, NULL);
+ if (is_batch_mode) {
+ ret = sensord_register_events(handle, SENSOR_EVENT(info.type), info.batch_latency, info.events_cb, NULL);
+ } else {
+ ret = sensord_register_event(handle, SENSOR_EVENT(info.type), info.interval, info.batch_latency, info.cb, NULL);
+ }
ASSERT_TRUE(ret);
ret = sensord_start(handle, info.powersave);
ret = sensord_stop(handle);
EXPECT_TRUE(ret);
- ret = sensord_unregister_event(handle, SENSOR_EVENT(info.type));
+ if (is_batch_mode) {
+ ret = sensord_unregister_events(handle, SENSOR_EVENT(info.type));
+ } else {
+ ret = sensord_unregister_event(handle, SENSOR_EVENT(info.type));
+ }
EXPECT_TRUE(ret);
ret = sensord_disconnect(handle);
class sensor_info {
public:
+ sensor_info()
+ { }
+
sensor_info(sensor_type_t _type, int _index, int _interval, int _batch_latency, int _powersave, sensor_cb_t _cb, void *_user_data)
: type(_type)
, index(_index)
, user_data(_user_data)
{ }
- sensor_type_t type;
- int index;
- int interval;
- int batch_latency;
- int powersave;
- sensor_cb_t cb;
- void *user_data;
+ sensor_info(sensor_type_t _type, int _index, int _interval, int _batch_latency, int _powersave, sensor_events_cb_t _events_cb, void *_user_data)
+ : type(_type)
+ , index(_index)
+ , interval(_interval)
+ , batch_latency(_batch_latency)
+ , powersave(_powersave)
+ , events_cb(_events_cb)
+ , user_data(_user_data)
+ { }
+
+ sensor_type_t type { UNKNOWN_SENSOR };
+ int index { 0 };
+ int interval { 0 };
+ int batch_latency { 0 };
+ int powersave { 0 };
+ union
+ {
+ sensor_cb_t cb { NULL };
+ sensor_events_cb_t events_cb;
+ };
+ void *user_data { NULL };
};
class sensor_adapter {
static bool get_data(int handle, sensor_type_t type, sensor_data_t &data);
static bool flush(int handle);
+ static bool is_batch_mode;
};
#include "injector.h"
#include "info.h"
#include "loopback.h"
+#include "sensor_adapter.h"
static sensor_manager *manager;
{
sensor_manager *manager = NULL;
- if (!strcmp(command, "test"))
+ if (!strcmp(command, "test")) {
manager = new(std::nothrow) tester_manager;
- if (!strcmp(command, "inject"))
+ } else if (!strcmp(command, "batch_mode_test")) {
+ sensor_adapter::is_batch_mode = true;
+ manager = new(std::nothrow) tester_manager;
+ } else if (!strcmp(command, "inject")) {
manager = new(std::nothrow) injector_manager;
- if (!strcmp(command, "info"))
+ } else if (!strcmp(command, "info")) {
manager = new(std::nothrow) info_manager;
- if (!strcmp(command, "loopback"))
+ } else if (!strcmp(command, "loopback")) {
manager = new(std::nothrow) loopback_manager;
+ }
if (!manager) {
_E("failed to allocate memory for manager\n");
#include "test_bench.h"
#define MYSENSOR_URI "http://example.org/sensor/general/mysensor/mysensor"
+#define MYSENSOR_BATCH_URI "http://example.org/sensor/general/mysensor/mysensor-batch"
+
#define MYSENSOR_NAME "mysensor"
+#define MYSENSOR_BATCH_NAME "mysensor-batch"
#define MYSENSOR_VENDOR "tizen"
+#define NUMBER_OF_EVENT 100
+
static bool started = false;
static bool added = false;
static bool called = false;
_I("[%llu] %f %f %f\n", data->timestamp, data->values[0], data->values[1], data->values[2]);
}
+static void events_cb(sensor_t sensor, unsigned int event_type, sensor_data_t* datas[], int events_count, void *user_data)
+{
+ for (int i = 0 ; i < events_count; i++) {
+ _I("[%llu]", datas[i]->timestamp);
+ for (int j = 0; j < datas[i]->value_count; j++)
+ _I(" %f", datas[i]->values[j]);
+ _I("\n");
+ }
+}
+
static void start_cb(sensord_provider_h provider, void *user_data)
{
started = true;
return TRUE;
}
+static gboolean publish_batch_event(gpointer gdata)
+{
+ if (!started) return FALSE;
+
+ sensord_provider_h *provider = reinterpret_cast<sensord_provider_h *>(gdata);
+
+ sensor_data_t data[NUMBER_OF_EVENT];
+
+ for (int i = 0 ; i < NUMBER_OF_EVENT; i++) {
+ data[i].accuracy = 3;
+ data[i].timestamp = sensor::utils::get_timestamp();
+ data[i].value_count = 3;
+ data[i].values[0] = i;
+ data[i].values[1] = i;
+ data[i].values[2] = i;
+ }
+ sensord_provider_publish_events(provider, data, NUMBER_OF_EVENT);
+ _N("[ PUBLISH ] %d events\n", NUMBER_OF_EVENT);
+ g_timeout_add_seconds(1, publish_batch_event, provider);
+ return FALSE;
+}
+
static void add_mysensor(void)
{
sensord_provider_h provider;
return true;
}
+/* TODO: change it from manual test to auto-test */
+TESTCASE(skip_sensor_provider, mysensor_batch_p)
+{
+ int err = 0;
+ sensor_t sensor;
+ sensord_provider_h provider;
+
+ err = sensord_create_provider(MYSENSOR_BATCH_URI, &provider);
+ ASSERT_EQ(err, 0);
+
+ err = sensord_provider_set_name(provider, MYSENSOR_BATCH_NAME);
+ ASSERT_EQ(err, 0);
+ err = sensord_provider_set_vendor(provider, MYSENSOR_VENDOR);
+ ASSERT_EQ(err, 0);
+ err = sensord_provider_set_range(provider, 0.0f, 1.0f);
+ ASSERT_EQ(err, 0);
+ err = sensord_provider_set_resolution(provider, 0.01f);
+ ASSERT_EQ(err, 0);
+
+ err = sensord_add_provider(provider);
+ ASSERT_EQ(err, 0);
+
+ err = sensord_provider_set_start_cb(provider, start_cb, NULL);
+ ASSERT_EQ(err, 0);
+ err = sensord_provider_set_stop_cb(provider, stop_cb, NULL);
+ ASSERT_EQ(err, 0);
+ err = sensord_provider_set_interval_changed_cb(provider, interval_cb, NULL);
+ ASSERT_EQ(err, 0);
+
+ err = sensord_get_default_sensor_by_uri(MYSENSOR_BATCH_URI, &sensor);
+ ASSERT_EQ(err, 0);
+
+ g_timeout_add_seconds(1, publish_batch_event, provider);
+ mainloop::run();
+
+ err = sensord_remove_provider(provider);
+ ASSERT_EQ(err, 0);
+ err = sensord_destroy_provider(provider);
+ ASSERT_EQ(err, 0);
+
+ return true;
+}
+
+
+/* TODO: change it from manual test to auto-test */
+TESTCASE(skip_sensor_provider, mysensor_batch_with_listener_p_1)
+{
+ int err;
+ bool ret;
+ int handle;
+ sensor_t sensor;
+
+ called = false;
+
+ err = sensord_get_default_sensor_by_uri(MYSENSOR_BATCH_URI, &sensor);
+ ASSERT_EQ(err, 0);
+
+ handle = sensord_connect(sensor);
+ ASSERT_EQ(err, 0);
+
+ ret = sensord_register_events(handle, 1, 100, events_cb, NULL);
+ ASSERT_TRUE(ret);
+
+ ret = sensord_start(handle, 0);
+ ASSERT_TRUE(ret);
+
+ ret = sensord_change_event_interval(handle, 0, 100);
+ ASSERT_TRUE(ret);
+
+ mainloop::run();
+
+ ret = sensord_stop(handle);
+ ASSERT_TRUE(ret);
+
+ ret = sensord_unregister_events(handle, 1);
+ ASSERT_TRUE(ret);
+
+ ret = sensord_disconnect(handle);
+ ASSERT_TRUE(ret);
+
+ return true;
+}
_N("\n");
}
+static void test_events_cb(sensor_t sensor, unsigned int event_type, sensor_data_t* datas[], int events_count, void *user_data)
+{
+ for (int i = 0 ; i < events_count; i++) {
+ _N("%llu ", datas[i]->timestamp);
+ for (int j = 0; j < datas[i]->value_count; j++)
+ _N(" %10f", datas[i]->values[j]);
+ _N("\n");
+ }
+}
+
TESTCASE(manual_test, sensor)
{
int handle;
bool ret;
int index = 0;
sensor_data_t data;
+ sensor_info info;
if (sensor_adapter::get_count(stype) > 1) {
_N("There are more than 2 sensors. please enter the index : ");
std::cin >> index;
}
- sensor_info info(stype, index, interval, latency, powersave, test_cb, NULL);
+ if (sensor_adapter::is_batch_mode) {
+ info = sensor_info(stype, index, interval, latency, powersave, test_events_cb, NULL);
+ } else {
+ info = sensor_info(stype, index, interval, latency, powersave, test_cb, NULL);
+ }
ret = sensor_adapter::start(info, handle);
ASSERT_TRUE(ret);
void sensor_handler::set_cache(sensor_data_t *data, int size)
{
- if (m_last_data == NULL) {
- m_last_data = (sensor_data_t*)malloc(size);
+ if (m_last_data_size != size) {
+ m_last_data_size = size;
+ if (m_last_data) {
+ free(m_last_data);
+ }
+ m_last_data = (sensor_data_t*)malloc(m_last_data_size);
retm_if(m_last_data == NULL, "Memory allocation failed");
}
_D("Listener[%d] try to start", get_id());
ret = sensor->start(this);
- retv_if (ret < 0, OP_ERROR);
+ retv_if(ret < 0, OP_ERROR);
/* m_started is changed only when it is explicitly called by user,
* not automatically determined by any pause policy. */
auto it = m_app_sensors.find(ch);
retv_if(it == m_app_sensors.end(), -EINVAL);
- sensor_data_t *data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
+ size_t size = msg.header()->length;
+ void *data = (void *)malloc(size);
retvm_if(!data, -ENOMEM, "Failed to allocate memory");
- msg.disclose((char *)data);
-
- it->second->publish(data, sizeof(sensor_data_t));
+ msg.disclose(data);
+ it->second->publish((sensor_data_t*)data, size);
return OP_SUCCESS;
}