sensor: add HeartRate recorder 43/78643/1
authorMu-Woong Lee <muwoong.lee@samsung.com>
Wed, 6 Jul 2016 09:24:09 +0000 (18:24 +0900)
committerMu-Woong Lee <muwoong.lee@samsung.com>
Wed, 6 Jul 2016 09:24:09 +0000 (18:24 +0900)
Change-Id: Ib3e0ce16e34c5429715cd6095eed3de2f31ffed7
Signed-off-by: Mu-Woong Lee <muwoong.lee@samsung.com>
src/sensor/ClientInfo.cpp
src/sensor/ClientInfo.h
src/sensor/CreateProvider.cpp
src/sensor/SensorProvider.cpp
src/sensor/heartrate/HeartRate.cpp [new file with mode: 0644]
src/sensor/heartrate/HeartRate.h [new file with mode: 0644]
src/sensor/heartrate/HeartRateLogger.cpp [new file with mode: 0644]
src/sensor/heartrate/HeartRateLogger.h [new file with mode: 0644]
src/sensor/heartrate/HeartRateQuerier.cpp [new file with mode: 0644]
src/sensor/heartrate/HeartRateQuerier.h [new file with mode: 0644]

index e1913f7a00ca1e707f53892e9445fa4b9ec30767..6c5955daa350091559826d1cd87673874575982e 100644 (file)
@@ -164,6 +164,20 @@ bool ClientInfo::remove(std::string subject, std::string pkgId)
        return ret;
 }
 
+void ClientInfo::getParam(std::vector<Json> &options, const char *key, float *min, float *max)
+{
+       double val;
+
+       for (Json& opt : options) {
+               if (!opt.get(NULL, key, &val))
+                       continue;
+               if (min)
+                       *min = MIN(*min, static_cast<float>(val));
+               if (max)
+                       *max = MAX(*max, static_cast<float>(val));
+       }
+}
+
 void ClientInfo::purgeClient(std::string pkgId)
 {
        IF_FAIL_VOID_TAG(__dbMgr, _W, "DB not initialized");
index a14dc3caddec426369c4c2c646f8e59f07caa6bf..e3ee643faf982327a20a98e45ecf904e3c653c33 100644 (file)
@@ -37,6 +37,8 @@ namespace ctx {
                bool set(std::string subject, std::string pkgId, Json option, int retentionPeriod);
                bool remove(std::string subject, std::string pkgId);
 
+               void getParam(std::vector<Json>& options, const char *key, float *min, float *max);
+
                static void purgeClient(std::string pkgId);
 
        private:
index 768ba8129470554bc21683c826a96175a6bd4551..73e9f19a324132445a254506d88aa34737e9e979 100644 (file)
@@ -19,6 +19,7 @@
 #include "pedometer/Pedometer.h"
 #include "pressure/Pressure.h"
 #include "sleep/Sleep.h"
+#include "heartrate/HeartRate.h"
 
 using namespace ctx;
 
@@ -27,6 +28,7 @@ extern "C" SO_EXPORT ContextProvider* CreateProvider(const char *subject)
        ADD_PROVIDER(SUBJ_SENSOR_PEDOMETER, PedometerProvider);
        ADD_PROVIDER(SUBJ_SENSOR_PRESSURE,  PressureProvider);
        ADD_PROVIDER(SUBJ_SENSOR_SLEEP_MONITOR,  SleepProvider);
+       ADD_PROVIDER(SUBJ_SENSOR_HEART_RATE,  HeartRateProvider);
 
        return NULL;
 }
index 12c0eed25f48a5a5ae114817e53e3d74a8741f53..1e680acad74d9c31300c073cf44cfdf8226e189a 100644 (file)
@@ -156,13 +156,20 @@ int SensorProvider::__removeClient(std::string pkgId)
 
        /* Check if there is no client anymore */
        ret = __clientInfo.get(getSubject(), options);
-       IF_FAIL_RETURN(ret != ERR_NONE, ERR_NONE);
-       IF_FAIL_RETURN(ret == ERR_NO_DATA, ERR_OPERATION_FAILED);
 
-       /* Stop listening */
-       sensorLogger->stop();
+       if (ret == ERR_NONE) {
+               /* Still, one or more clients exist */
+               /* If necessary, the logger restarts its logging logic with updated parameters */
+               sensorLogger->start();
+               return ERR_NONE;
 
-       return ERR_NONE;
+       } else if (ret == ERR_NO_DATA) {
+               /* No client */
+               sensorLogger->stop();
+               return ERR_NONE;
+       }
+
+       return ERR_OPERATION_FAILED;
 }
 
 void SensorProvider::removeClient(std::string subject, std::string pkgId)
diff --git a/src/sensor/heartrate/HeartRate.cpp b/src/sensor/heartrate/HeartRate.cpp
new file mode 100644 (file)
index 0000000..03fae8a
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <SensorRecorderTypes.h>
+#include <Util.h>
+#include "../TypesInternal.h"
+#include "HeartRateLogger.h"
+#include "HeartRateQuerier.h"
+#include "HeartRate.h"
+
+using namespace ctx;
+
+HeartRateProvider::HeartRateProvider() :
+       SensorProvider(SUBJ_SENSOR_HEART_RATE)
+{
+       IF_FAIL_VOID(isSupported());
+
+       sensorLogger = new(std::nothrow) HeartRateLogger();
+       IF_FAIL_VOID_TAG(sensorLogger, _E, "Memory allocation failed");
+}
+
+HeartRateProvider::~HeartRateProvider()
+{
+}
+
+void HeartRateProvider::getPrivilege(std::vector<const char*> &privilege)
+{
+       privilege.push_back(PRIV_HEALTHINFO);
+}
+
+bool HeartRateProvider::isSupported()
+{
+       return util::getSystemInfoBool("tizen.org/feature/sensor.heart_rate_monitor");
+}
+
+Querier* HeartRateProvider::getQuerier(Json option)
+{
+       HeartRateQuerier *querier = new(std::nothrow) HeartRateQuerier(this, option);
+       IF_FAIL_RETURN_TAG(querier, NULL, _E, "Memory allocation failed");
+       return querier;
+}
diff --git a/src/sensor/heartrate/HeartRate.h b/src/sensor/heartrate/HeartRate.h
new file mode 100644 (file)
index 0000000..c9d071b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONTEXT_HEARTRATE_PROVIDER_H__
+#define __CONTEXT_HEARTRATE_PROVIDER_H__
+
+#include "../SensorProvider.h"
+
+namespace ctx {
+
+       class HeartRateProvider : public SensorProvider {
+       public:
+               HeartRateProvider();
+               ~HeartRateProvider();
+
+               bool isSupported();
+               void getPrivilege(std::vector<const char*> &privilege);
+
+       protected:
+               Querier* getQuerier(Json option);
+       };
+}
+
+#endif /* _CONTEXT_HEARTRATE_PROVIDER_H_ */
diff --git a/src/sensor/heartrate/HeartRateLogger.cpp b/src/sensor/heartrate/HeartRateLogger.cpp
new file mode 100644 (file)
index 0000000..05adbe1
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <climits>
+#include <sqlite3.h>
+#include <SensorRecorderTypes.h>
+#include "../TypesInternal.h"
+#include "../ClientInfo.h"
+#include "../TimeUtil.h"
+#include "HeartRateLogger.h"
+
+#define SAMPLING_INTERVAL      200             /* ms */
+#define VALID_HR_LB                    30              /* BPM */
+#define MIN_VALID_COUNT                3
+#define MAX_TIMER_INTERVAL     1440    /* minutes */
+#define MEASURING_LIMIT                10000   /* ms */
+
+using namespace ctx;
+
+HeartRateLogger::HeartRateLogger() :
+       __timerMgr(NULL),
+       __timerId(-1),
+       __timerInterval(INT_MAX),
+       __expiredTime(0)
+{
+       setSensor(HRM_SENSOR);
+       setPowerSave(false);
+       setSamplingInterval(SAMPLING_INTERVAL);
+
+       /* Create the log table */
+       executeQuery(
+                       "CREATE TABLE IF NOT EXISTS " HEART_RATE_RECORD " (" \
+                               KEY_UNIV_TIME " INTEGER NOT NULL PRIMARY KEY, " \
+                               KEY_HEART_RATE " REAL NOT NULL" \
+                       ")");
+
+       ClientInfo clientInfo;
+       if (clientInfo.exist(SUBJ_SENSOR_HEART_RATE))
+               start();
+}
+
+HeartRateLogger::~HeartRateLogger()
+{
+       stop();
+}
+
+bool HeartRateLogger::start()
+{
+       std::vector<Json> options;
+       ClientInfo clientInfo;
+       float interval = MAX_TIMER_INTERVAL;
+
+       if (clientInfo.get(SUBJ_SENSOR_HEART_RATE, options) != ERR_NONE)
+               return false;
+
+       clientInfo.getParam(options, KEY_INTERVAL, &interval, NULL);
+
+       if (!__timerMgr) {
+               __timerMgr = new(std::nothrow) TimerManager;
+               IF_FAIL_RETURN_TAG(__timerMgr, false, _E, "Memory allocation failed");
+       }
+
+       if (interval == __timerInterval)
+               return true;
+
+       __timerInterval = interval;
+
+       _I(GREEN("Start to record (at every %d minutes)"), __timerInterval);
+
+       if (__timerId > 0)
+               __timerMgr->remove(__timerId);
+
+       __timerId = __timerMgr->setFor(__timerInterval, this);
+
+       if (__timerId < 0) {
+               _E("Setting timer failed");
+               __timerInterval = INT_MAX;
+               return false;
+       }
+
+       return true;
+}
+
+void HeartRateLogger::stop()
+{
+       _I(GREEN("Stop recording"));
+
+       if (__timerMgr)
+               delete __timerMgr;
+
+       __timerMgr = NULL;
+       __timerId = -1;
+       __timerInterval = INT_MAX;
+
+       unlisten();
+}
+
+void HeartRateLogger::flushCache(bool force)
+{
+}
+
+bool HeartRateLogger::onTimerExpired(int timerId)
+{
+       IF_FAIL_RETURN(!isRunning(), true);
+
+       if (!listen())
+               _W("Starting sensor failed");
+
+       __expiredTime = TimeUtil::getTime();
+       _I("Measuring starts at %llu", __expiredTime);
+       return true;
+}
+
+void HeartRateLogger::onEvent(sensor_data_t *eventData)
+{
+       static int validCnt = 0;
+       uint64_t receivedTime = TimeUtil::getTime();
+
+       IF_FAIL_CATCH_TAG(receivedTime - __expiredTime < MEASURING_LIMIT, _I, "Measuring failed (timeout)");
+
+       if (eventData->values[0] > VALID_HR_LB)
+               ++validCnt;
+       else
+               validCnt = 0;
+
+       if (validCnt < MIN_VALID_COUNT)
+               return;
+
+       __record(eventData->values[0], receivedTime);
+
+CATCH:
+       removeExpired(SUBJ_SENSOR_HEART_RATE, HEART_RATE_RECORD, KEY_UNIV_TIME);
+       unlisten();
+}
+
+void HeartRateLogger::__record(float heartrate, uint64_t eventTime)
+{
+       char *query = sqlite3_mprintf(
+                       "INSERT INTO " HEART_RATE_RECORD \
+                               " (" KEY_UNIV_TIME ", " KEY_HEART_RATE ") VALUES (%llu, %.3f)",
+                       eventTime, heartrate);
+       executeQuery(query);
+       sqlite3_free(query);
+}
diff --git a/src/sensor/heartrate/HeartRateLogger.h b/src/sensor/heartrate/HeartRateLogger.h
new file mode 100644 (file)
index 0000000..b3a56c1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONTEXT_HEARTRATE_LOGGER_H__
+#define __CONTEXT_HEARTRATE_LOGGER_H__
+
+#include <TimerManager.h>
+#include "../SensorLogger.h"
+#include "../SensorProxy.h"
+
+namespace ctx {
+
+       class HeartRateLogger : public SensorLogger, public SensorProxy, public ITimerListener {
+       public:
+               HeartRateLogger();
+               ~HeartRateLogger();
+
+               bool start();
+               void stop();
+               void flushCache(bool force = false);
+
+       protected:
+               bool onTimerExpired(int timerId);
+               void onEvent(sensor_data_t *eventData);
+
+       private:
+               void __record(float heartrate, uint64_t eventTime);
+
+               TimerManager *__timerMgr;
+               int __timerId;
+               int __timerInterval;
+               uint64_t __expiredTime;
+       };
+}
+
+#endif /* __CONTEXT_HEARTRATE_LOGGER_H__ */
diff --git a/src/sensor/heartrate/HeartRateQuerier.cpp b/src/sensor/heartrate/HeartRateQuerier.cpp
new file mode 100644 (file)
index 0000000..1bae5a6
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sqlite3.h>
+#include <SensorRecorderTypes.h>
+#include "../TypesInternal.h"
+#include "HeartRateQuerier.h"
+
+#define PROJECTION \
+       KEY_HEART_RATE ", " \
+       KEY_UNIV_TIME " AS " KEY_START_TIME ", " \
+       KEY_UNIV_TIME " AS " KEY_END_TIME
+
+using namespace ctx;
+
+HeartRateQuerier::HeartRateQuerier(ContextProvider *provider, Json option) :
+       Querier(provider, option)
+{
+}
+
+HeartRateQuerier::~HeartRateQuerier()
+{
+}
+
+int HeartRateQuerier::queryRaw(int startTime, int endTime)
+{
+       return query(startTime, endTime);
+}
+
+int HeartRateQuerier::query(int startTime, int endTime)
+{
+       char *sql = sqlite3_mprintf(
+                       "SELECT " PROJECTION \
+                       " FROM " HEART_RATE_RECORD \
+                       " WHERE " KEY_UNIV_TIME " > %llu AND " KEY_UNIV_TIME " <= %llu",
+                       SEC_TO_MS(static_cast<uint64_t>(startTime)), SEC_TO_MS(static_cast<uint64_t>(endTime)));
+
+       int ret = Querier::query(sql);
+       sqlite3_free(sql);
+
+       return ret;
+}
diff --git a/src/sensor/heartrate/HeartRateQuerier.h b/src/sensor/heartrate/HeartRateQuerier.h
new file mode 100644 (file)
index 0000000..335d902
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONTEXT_HEARTRATE_QUERIER_H__
+#define __CONTEXT_HEARTRATE_QUERIER_H__
+
+#include "../Querier.h"
+
+namespace ctx {
+
+       class HeartRateQuerier : public Querier {
+       public:
+               HeartRateQuerier(ContextProvider *provider, Json option);
+               ~HeartRateQuerier();
+
+               int queryRaw(int startTime, int endTime);
+               int query(int startTime, int endTime);
+       };
+}
+
+#endif /* __CONTEXT_HEARTRATE_QUERIER_H__ */