From: Tomasz Marciniak Date: Tue, 19 Jul 2016 11:14:54 +0000 (+0200) Subject: [HAM] Added recording functionality. X-Git-Tag: submit/tizen/20160808.053811~4^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9e34abf8c7412659d6a8bb65c20dc9c19f67792f;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [HAM] Added recording functionality. [Verification] Code compiles. TCT pass rate did not change. Change-Id: Ib1e0475547f8fc094f647065afc129e84d8bcaac Signed-off-by: Tomasz Marciniak --- diff --git a/src/humanactivitymonitor/humanactivitymonitor_api.js b/src/humanactivitymonitor/humanactivitymonitor_api.js index d9c3bf0..2d2d65e 100755 --- a/src/humanactivitymonitor/humanactivitymonitor_api.js +++ b/src/humanactivitymonitor/humanactivitymonitor_api.js @@ -33,6 +33,10 @@ function SetReadOnlyProperty(obj, n, v) { } var ACCUMULATIVE_PEDOMETER_DATA = 'ACCUMULATIVE_PEDOMETER_DATA'; +var MIN_OPTION_INTERVAL = 0; +var MIN_OPTION_RETENTION_PERIOD = 1; +var MIN_QUERY_TIME = 0; +var MIN_QUERY_INTERVAL = 0; var HumanActivityType = { PEDOMETER: 'PEDOMETER', @@ -42,6 +46,13 @@ var HumanActivityType = { SLEEP_MONITOR: 'SLEEP_MONITOR' }; +var HumanActivityRecorderType = { + PEDOMETER: 'PEDOMETER', + HRM: 'HRM', + SLEEP_MONITOR: 'SLEEP_MONITOR', + PRESSURE: 'PRESSURE' +}; + var PedometerStepStatus = { NOT_MOVING: 'NOT_MOVING', WALKING: 'WALKING', @@ -90,6 +101,39 @@ function convertActivityData(type, data) { } } +function createRecorderData(func, data) { + var array = []; + + data.forEach(function (d) { + array.push(new func(d)); + }); + + return array; +} + +function convertActivityRecorderData(type, data) { + var func = undefined; + switch (type) { + case HumanActivityRecorderType.PEDOMETER: + func = HumanActivityRecorderPedometerData; + break; + case HumanActivityRecorderType.HRM: + func = HumanActivityRecorderHRMData; + break; + case HumanActivityRecorderType.SLEEP_MONITOR: + func = HumanActivityRecorderSleepMonitorData; + break; + case HumanActivityRecorderType.PRESSURE: + func = HumanActivityRecorderPressureData; + break; + default: + console.error('Uknown human activity recorder type: ' + type); + return; + } + + return createRecorderData(func, data); +} + function ActivityRecognitionListenerManager() { this.listeners = {}; this.nextId = 1; @@ -386,6 +430,87 @@ HumanActivityMonitorManager.prototype.removeActivityRecognitionListener = functi activityRecognitionListener.removeListener(args.watchId); }; +HumanActivityMonitorManager.prototype.startRecorder = function() { + var args = validator_.validateArgs(arguments, [ + {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityRecorderType)}, + {name: 'options', type : types_.DICTIONARY, optional: true, nullable: false} + ]); + + var callArgs = {}; + + if (args.options) { + if (MIN_OPTION_INTERVAL > args.options.interval || + MIN_OPTION_RETENTION_PERIOD > args.options.interval) { + throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid option value'); + } + + callArgs.options = args.options; + } + + callArgs.type = args.type; + + var result = native_.callSync('HumanActivityMonitorManager_startRecorder', callArgs); + + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } +}; + +HumanActivityMonitorManager.prototype.stopRecorder = function() { + var args = validator_.validateArgs(arguments, [ + {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityRecorderType)}, + ]); + + var callArgs = {}; + callArgs.type = args.type; + + var result = native_.callSync('HumanActivityMonitorManager_stopRecorder', callArgs); + + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } +}; + +HumanActivityMonitorManager.prototype.readRecorderData = function() { + var args = validator_.validateArgs(arguments, [ + {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityRecorderType)}, + {name: 'query', type : types_.DICTIONARY, optional: false, nullable: true}, + {name: 'successCallback', type: types_.FUNCTION}, + {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true} + ]); + + var callArgs = {}; + + if (args.query) { + if ((args.query.startTime && MIN_QUERY_TIME > args.query.startTime) || + (args.query.endTime && MIN_QUERY_TIME > args.query.endTime) || + (args.query.anchorTime && MIN_QUERY_TIME > args.query.anchorTime) || + (args.query.interval && MIN_QUERY_INTERVAL > args.query.interval) || + (args.query.startTime && args.query.endTime && args.query.startTime > args.query.endTime)) { + throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid query value'); + } + } + + callArgs.options = args.options; + callArgs.type = args.type; + callArgs.query = args.query; + + var callback = function(result) { + if (native_.isFailure(result)) { + native_.callIfPossible(args.errorCallback, native_.getErrorObject(result)); + } else { + var array = convertActivityRecorderData(args.type, native_.getResultObject(result)); + args.successCallback(array); + } + }; + + var result = native_.call('HumanActivityMonitorManager_readRecorderData', callArgs, callback); + + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } +}; + function StepDifference(data) { SetReadOnlyProperty(this, 'stepCountDifference', data.stepCountDifference); SetReadOnlyProperty(this, 'timestamp', data.timestamp); @@ -480,4 +605,50 @@ function HumanActivitySleepMonitorData(data) { HumanActivitySleepMonitorData.prototype = new HumanActivityData(); HumanActivitySleepMonitorData.prototype.constructor = HumanActivitySleepMonitorData; +//Recorded data +function HumanActivityRecorderData(data) { + if (data) { + SetReadOnlyProperty(this, 'startTime', data.startTime); + SetReadOnlyProperty(this, 'endTime', data.endTime); + } +} + +function HumanActivityRecorderPedometerData(data) { + HumanActivityRecorderData.call(this, data); + SetReadOnlyProperty(this, 'distance', data.distance); + SetReadOnlyProperty(this, 'calorie', data.calorie); + SetReadOnlyProperty(this, 'totalStepCount', data.totalStepCount); + SetReadOnlyProperty(this, 'walkStepCount', data.walkStepCount); + SetReadOnlyProperty(this, 'runStepCount', data.runStepCount); +} + +HumanActivityRecorderPedometerData.prototype = new HumanActivityRecorderData(); +HumanActivityRecorderPedometerData.prototype.constructor = HumanActivityRecorderPedometerData; + +function HumanActivityRecorderHRMData(data) { + HumanActivityRecorderData.call(this, data); + SetReadOnlyProperty(this, 'heartRate', data.heartRate); +} + +HumanActivityRecorderHRMData.prototype = new HumanActivityRecorderData(); +HumanActivityRecorderHRMData.prototype.constructor = HumanActivityRecorderHRMData; + +function HumanActivityRecorderSleepMonitorData(data) { + HumanActivityRecorderData.call(this, data); + SetReadOnlyProperty(this, 'status', data.status); +} + +HumanActivityRecorderSleepMonitorData.prototype = new HumanActivityRecorderData(); +HumanActivityRecorderSleepMonitorData.prototype.constructor = HumanActivityRecorderSleepMonitorData; + +function HumanActivityRecorderPressureData(data) { + HumanActivityRecorderData.call(this, data); + SetReadOnlyProperty(this, 'max', data.max); + SetReadOnlyProperty(this, 'min', data.min); + SetReadOnlyProperty(this, 'average', data.average); +} + +HumanActivityRecorderPressureData.prototype = new HumanActivityRecorderData(); +HumanActivityRecorderPressureData.prototype.constructor = HumanActivityRecorderPressureData; + exports = new HumanActivityMonitorManager(); diff --git a/src/humanactivitymonitor/humanactivitymonitor_instance.cc b/src/humanactivitymonitor/humanactivitymonitor_instance.cc index d572ba3..5000cb4 100755 --- a/src/humanactivitymonitor/humanactivitymonitor_instance.cc +++ b/src/humanactivitymonitor/humanactivitymonitor_instance.cc @@ -35,6 +35,8 @@ namespace { const std::string kPrivilegeHealthInfo = "http://tizen.org/privilege/healthinfo"; const std::string kPrivilegeLocation = "http://tizen.org/privilege/location"; +const int DEFAULT_HRM_INTERVAL = 1440; // 1440 (1 day) default value for HRM's interval +const int DEFAULT_RETENTION_PERIOD = 1; // 1 hour default value for retention period } // namespace using common::PlatformResult; @@ -58,6 +60,12 @@ HumanActivityMonitorInstance::HumanActivityMonitorInstance() { HumanActivityMonitorManagerAddActivityRecognitionListener); REGISTER_SYNC("HumanActivityMonitorManager_removeActivityRecognitionListener", HumanActivityMonitorManagerRemoveActivityRecognitionListener); + REGISTER_SYNC("HumanActivityMonitorManager_startRecorder", + HumanActivityMonitorManagerStartRecorder); + REGISTER_SYNC("HumanActivityMonitorManager_stopRecorder", + HumanActivityMonitorManagerStopRecorder); + REGISTER_SYNC("HumanActivityMonitorManager_readRecorderData", + HumanActivityMonitorManagerReadRecorderData); #undef REGISTER_SYNC } @@ -261,6 +269,111 @@ void HumanActivityMonitorInstance::HumanActivityMonitorManagerRemoveActivityReco } } +void HumanActivityMonitorInstance::HumanActivityMonitorManagerStartRecorder( + const picojson::value& args, picojson::object& out) { + LoggerD("Enter"); + + CHECK_PRIVILEGE_ACCESS(kPrivilegeHealthInfo, &out); + CHECK_EXIST(args, "type", out) + + const auto& type = args.get("type").get(); + + PlatformResult result = Init(); + if (!result) { + LogAndReportError(result, &out, ("Failed: Init()")); + return; + } + + int interval = DEFAULT_HRM_INTERVAL; + int retention_period = DEFAULT_RETENTION_PERIOD; + + if (args.contains("options")) { + const auto& options = args.get("options"); + auto& js_interval = options.get("interval"); + auto& js_retention_period = options.get("retentionPeriod"); + + if (js_interval.is()) { + interval = js_interval.get(); + } + + if (js_retention_period.is()) { + retention_period = js_retention_period.get(); + } + } + + LoggerD("interval: %d retentionPeriod: %d", interval, retention_period); + + result = manager_->StartDataRecorder(type, interval, retention_period); + if (result) { + ReportSuccess(out); + } else { + LogAndReportError(result, &out, ("Failed: manager_->StartDataRecorder()")); + } +} + +void HumanActivityMonitorInstance::HumanActivityMonitorManagerStopRecorder( + const picojson::value& args, picojson::object& out) { + LoggerD("Enter"); + CHECK_EXIST(args, "type", out) + + const auto& type = args.get("type").get(); + + PlatformResult result = Init(); + if (!result) { + LogAndReportError(result, &out, ("Failed: Init()")); + return; + } + + result = manager_->StopDataRecorder(type); + if (result) { + ReportSuccess(out); + } else { + LogAndReportError(result, &out, ("Failed: manager_->StopDataRecorder()")); + } +} + +void HumanActivityMonitorInstance::HumanActivityMonitorManagerReadRecorderData( + const picojson::value& args, picojson::object& out) { + LoggerD("Enter"); + CHECK_EXIST(args, "type", out) + CHECK_EXIST(args, "query", out) + + const auto& type = args.get("type").get(); + const auto& query = args.get("query"); + + PlatformResult result = Init(); + if (!result) { + LogAndReportError(result, &out, ("Failed: Init()")); + return; + } + + const auto callback_id = args.get("callbackId").get(); + + auto get = [this, type, query, callback_id]() -> void { + picojson::value response = picojson::value(picojson::object()); + picojson::object& response_obj = response.get(); + response_obj["callbackId"] = picojson::value(callback_id); + + //picojson::value data = picojson::value(); + picojson::value array_value{picojson::array{}}; + auto* array = &array_value.get(); + + PlatformResult result = manager_->ReadRecorderData(type, array, query); + + if (result) { + ReportSuccess(array_value, response_obj); + } else { + LogAndReportError(result, &response_obj, ("Failed: manager_->ReadRecorderData()")); + } + + Instance::PostMessage(this, response.serialize().c_str()); + }; + + TaskQueue::GetInstance().Async(get); + + ReportSuccess(out); +} + #undef CHECK_EXIST } // namespace humanactivitymonitor diff --git a/src/humanactivitymonitor/humanactivitymonitor_instance.h b/src/humanactivitymonitor/humanactivitymonitor_instance.h index 07f0e1a..1ab6829 100755 --- a/src/humanactivitymonitor/humanactivitymonitor_instance.h +++ b/src/humanactivitymonitor/humanactivitymonitor_instance.h @@ -42,6 +42,12 @@ class HumanActivityMonitorInstance : public common::ParsedInstance { const picojson::value& args, picojson::object& out); void HumanActivityMonitorManagerRemoveActivityRecognitionListener( const picojson::value& args, picojson::object& out); + void HumanActivityMonitorManagerStartRecorder( + const picojson::value& args, picojson::object& out); + void HumanActivityMonitorManagerStopRecorder( + const picojson::value& args, picojson::object& out); + void HumanActivityMonitorManagerReadRecorderData( + const picojson::value& args, picojson::object& out); std::shared_ptr manager_; common::PlatformResult Init(); diff --git a/src/humanactivitymonitor/humanactivitymonitor_manager.cc b/src/humanactivitymonitor/humanactivitymonitor_manager.cc index 284a686..387220f 100755 --- a/src/humanactivitymonitor/humanactivitymonitor_manager.cc +++ b/src/humanactivitymonitor/humanactivitymonitor_manager.cc @@ -22,11 +22,13 @@ #include #include #include +#include #include "common/logger.h" #include "common/optional.h" #include "common/picojson.h" #include "common/tools.h" +#include "common/scope_exit.h" namespace extension { namespace humanactivitymonitor { @@ -36,12 +38,16 @@ using common::ErrorCode; using common::tools::ReportError; using common::tools::ReportSuccess; +typedef std::map SensorRecorderDataMap; +typedef std::map SensorRecorderQueryMap; + namespace { const std::string kActivityTypePedometer = "PEDOMETER"; const std::string kActivityTypeWristUp = "WRIST_UP"; const std::string kActivityTypeHrm = "HRM"; const std::string kActivityTypeSleepMonitor = "SLEEP_MONITOR"; +const std::string kActivityTypePressure = "PRESSURE"; const std::string kSleepStateAwake = "AWAKE"; const std::string kSleepStateAsleep = "ASLEEP"; @@ -70,6 +76,46 @@ const std::string kAccumulativeTotalStepCount = "accumulativeTotalStepCount"; const std::string kAccumulativeWalkStepCount = "accumulativeWalkStepCount"; const std::string kAccumulativeRunStepCount = "accumulativeRunStepCount"; +const std::string kRecordedStartTime = "startTime"; +const std::string kRecordedEndTime = "endTime"; +const std::string kRecordedHeartRate = "heartRate"; + +const std::string kRecordedDistance = "distance"; +const std::string kRecordedCalorie = "calorie"; +const std::string kRecordedTotalStepCount = "totalStepCount"; +const std::string kRecordedWalkStepCount = "walkStepCount"; +const std::string kRecordedRunStepCount = "runStepCount"; + +const std::string kRecordedMin = "min"; +const std::string kRecordedMax = "max"; +const std::string kRecordedAverage = "average"; + +const std::string kRecordedAnchorTime = "anchorTime"; +const std::string kRecordedInterval = "interval"; + +ErrorCode getErrorCode (const int errorCode) { + ScopeLogger(); + switch (errorCode) { + case SENSOR_ERROR_IO_ERROR: + return ErrorCode::IO_ERR; + case SENSOR_ERROR_NOT_SUPPORTED: + return ErrorCode::NOT_SUPPORTED_ERR; + case SENSOR_ERROR_PERMISSION_DENIED: + return ErrorCode::PERMISSION_DENIED_ERR; + case SENSOR_ERROR_NOT_AVAILABLE: + return ErrorCode::SERVICE_NOT_AVAILABLE_ERR; + case SENSOR_ERROR_NO_DATA: + return ErrorCode::NOT_FOUND_ERR; + case SENSOR_ERROR_INVALID_PARAMETER: + return ErrorCode::INVALID_VALUES_ERR; + case SENSOR_ERROR_OUT_OF_MEMORY: + case SENSOR_ERROR_OPERATION_FAILED: + case SENSOR_ERROR_NOT_NEED_CALIBRATION: + default: + return ErrorCode::ABORT_ERR; + } +} + // helper structure, allows easier access to data values struct PedometerDataWrapper : public sensor_pedometer_data_t { inline float steps() const { @@ -155,6 +201,66 @@ std::string FromSensorPedometerState(sensor_pedometer_state_e e) { } } +PlatformResult ConvertRecordedTime(void* data, picojson::object* obj) { + ScopeLogger("convert_recorded_time"); + + time_t start_time, end_time; + + int ret = sensor_recorder_data_get_time(data, &start_time, &end_time); + if (SENSOR_ERROR_NONE != ret) { + return LogAndCreateResult(getErrorCode(ret), + "Failed to get time", + ("Failed to get time, error: %d (%s)", ret, get_error_message(ret))); + } + + obj->insert(std::make_pair(kRecordedStartTime, picojson::value(static_cast(start_time)))); + obj->insert(std::make_pair(kRecordedEndTime, picojson::value(static_cast(end_time)))); + + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult ConvertRecordedInt(void* data, picojson::object* obj, + const SensorRecorderDataMap& map) { + ScopeLogger(); + + int ret = SENSOR_ERROR_NONE; + int tmp = 0; + + for (auto& it : map) { + ret = sensor_recorder_data_get_int(data, it.first, &tmp); + if (SENSOR_ERROR_NONE != ret) { + return LogAndCreateResult(getErrorCode(ret), + "Failed to get int value", + ("Failed to get int value, error: %d (%s)", ret, get_error_message(ret))); + } + + obj->insert(std::make_pair(it.second, picojson::value(static_cast(tmp)))); + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult ConvertRecordedDouble(void* data, picojson::object* obj, + const SensorRecorderDataMap& map) { + ScopeLogger(); + + int ret = SENSOR_ERROR_NONE; + double tmp = 0; + + for (auto& it : map) { + ret = sensor_recorder_data_get_double(data, it.first, &tmp); + if (SENSOR_ERROR_NONE != ret) { + return LogAndCreateResult(getErrorCode(ret), + "Failed to get double value", + ("Failed to get double value, error: %d (%s)", ret, get_error_message(ret))); + } + + obj->insert(std::make_pair(it.second, picojson::value(static_cast(tmp)))); + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + } // namespace const std::string kActivityTypeGps = "GPS"; @@ -227,6 +333,34 @@ class HumanActivityMonitorManager::Monitor { return GetDataImpl(data); } + PlatformResult StartDataRecorder(int interval, int retention_period) { + ScopeLogger(type()); + + auto result = IsSupported(); + if (!result) { + return result; + } + + return StartDataRecorderImpl(interval, retention_period); + } + + PlatformResult StopDataRecorder() { + ScopeLogger(type()); + + return StopDataRecorderImpl(); + } + + PlatformResult ReadRecorderData(picojson::array* data, const picojson::value& query) { + ScopeLogger(type()); + + auto result = IsSupported(); + if (!result) { + return result; + } + + return ReadRecorderDataImpl(data, query); + } + protected: virtual PlatformResult IsSupportedImpl(bool* supported) const { ScopeLogger(type()); @@ -249,6 +383,21 @@ class HumanActivityMonitorManager::Monitor { return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR,"NOT_SUPPORTED_ERR"); } + virtual PlatformResult StartDataRecorderImpl(int interval, int retention_period) const { + ScopeLogger(type()); + return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR,"NOT_SUPPORTED_ERR"); + } + + virtual PlatformResult StopDataRecorderImpl() const { + ScopeLogger(type()); + return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR,"NOT_SUPPORTED_ERR"); + } + + virtual PlatformResult ReadRecorderDataImpl(picojson::array* data, const picojson::value& query) { + ScopeLogger(type()); + return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR,"NOT_SUPPORTED_ERR"); + } + private: PlatformResult IsSupported() { ScopeLogger(type()); @@ -383,8 +532,10 @@ class HumanActivityMonitorManager::Monitor::GestureMonitor : public HumanActivit class HumanActivityMonitorManager::Monitor::SensorMonitor : public HumanActivityMonitorManager::Monitor { public: using SensorEventConverter = std::function; + using SensorRecordedConverter = std::function; - SensorMonitor(const std::string& t, sensor_type_e s, const SensorEventConverter& c) : Monitor(t), sensor_(s), handle_(nullptr), converter_(c) { + SensorMonitor(const std::string& t, sensor_type_e s, const SensorEventConverter& c, const SensorRecordedConverter& r) + : Monitor(t), sensor_(s), handle_(nullptr), converter_(c), converter_recorded_(r), recorded_data_(nullptr) { ScopeLogger(type()); } @@ -522,6 +673,90 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor : public HumanActivity return PlatformResult(ErrorCode::NO_ERROR); } + virtual PlatformResult StartDataRecorderImpl(int interval, int retention_period) const override { + ScopeLogger(type()); + + sensor_recorder_option_h option = nullptr; + + int ret = sensor_recorder_create_option(&option); + if (SENSOR_ERROR_NONE != ret) { + return LogAndCreateResult(getErrorCode(ret), + "Failed to create recorder option", + ("Failed to create (%d) recorder option, error: %d (%s)", sensor_, ret, get_error_message(ret))); + } + + SCOPE_EXIT { + sensor_recorder_destroy_option(option); + }; + + auto result = SetOptions(&option, interval, retention_period); + if (!result) { + return result; + } + + ret = sensor_recorder_start(sensor_, option); + if (SENSOR_ERROR_NONE != ret) { + return LogAndCreateResult(getErrorCode(ret), + "Failed to start recording", + ("Failed to start (%d) recording, error: %d (%s)", sensor_, ret, get_error_message(ret))); + } + + return PlatformResult(ErrorCode::NO_ERROR); + } + + virtual PlatformResult StopDataRecorderImpl() const override { + ScopeLogger(type()); + + int ret = sensor_recorder_stop(sensor_); + if (SENSOR_ERROR_NONE != ret) { + return LogAndCreateResult(getErrorCode(ret), + "Failed to stop recording", + ("Failed to stop (%d) recording, error: %d (%s)", sensor_, ret, get_error_message(ret))); + } + + return PlatformResult(ErrorCode::NO_ERROR); + } + + virtual PlatformResult ReadRecorderDataImpl(picojson::array* data, const picojson::value& query) override { + ScopeLogger(type()); + + std::lock_guard lock(mutex_); + this->recorded_data_ = data; + + sensor_recorder_query_h query_h = nullptr; + int ret = sensor_recorder_create_query(&query_h); + if (SENSOR_ERROR_NONE != ret) { + return LogAndCreateResult(getErrorCode(ret), + "Failed to create query", + ("Failed to create (%d) query, error: %d (%s)", sensor_, ret, get_error_message(ret))); + } + + SCOPE_EXIT { + sensor_recorder_destroy_query(query_h); + }; + + if (!query.is()) { + auto result = SetQuery(&query_h, query); + if (!result) { + return result; + } + } + + ret = sensor_recorder_read_sync(sensor_, query_h, SensorRecordedDataCb, static_cast(this)); + if (SENSOR_ERROR_NONE != ret) { + return LogAndCreateResult(getErrorCode(ret), + "Failed to read recorded data", + ("Failed to read (%d) recorded data, error: %d (%s)", sensor_, ret, get_error_message(ret))); + } + + return PlatformResult(ErrorCode::NO_ERROR); + } + + void addRecordedData(picojson::value* data) { + ScopeLogger(); + recorded_data_->push_back(*data); + } + private: static void OnSensorEvent(sensor_h, sensor_event_s* event, void* user_data) { ScopeLogger(); @@ -545,9 +780,89 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor : public HumanActivity callback(&sensor_data); } + static bool SensorRecordedDataCb(sensor_type_e type, void* data, int remains, + sensor_error_e error, void* user_data) { + ScopeLogger(); + + auto monitor = static_cast(user_data); + + picojson::value val = picojson::value(picojson::object()); + picojson::object* obj = &val.get(); + + auto result = monitor->converter_recorded_(data, obj); + if (result) { + monitor->addRecordedData(&val); + } + + return true; // continue + } + + PlatformResult SetOptions(sensor_recorder_option_h *option, + int interval, int retention_period) const { + ScopeLogger(); + + int ret = SENSOR_ERROR_NONE; + + if (SENSOR_HRM == sensor_) { + ret = sensor_recorder_option_set_int( + *option, SENSOR_RECORDER_OPTION_INTERVAL, interval); + + if (SENSOR_ERROR_NONE != ret) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, + "Failed to set recorder option", + ("Failed to set (%d) recorder option, error: %d (%s)", sensor_, ret, get_error_message(ret))); + } + } + + ret = sensor_recorder_option_set_int( + *option, SENSOR_RECORDER_OPTION_RETENTION_PERIOD, retention_period); + if (SENSOR_ERROR_NONE != ret) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, + "Failed to set recorder option", + ("Failed to set (%d) recorder option, error: %d (%s)", sensor_, ret, get_error_message(ret))); + } + + return PlatformResult(ErrorCode::NO_ERROR); + } + + PlatformResult SetQuery(sensor_recorder_query_h *query_h, + const picojson::value& query) const { + ScopeLogger(); + + SensorRecorderQueryMap map_query { + {SENSOR_RECORDER_QUERY_START_TIME, kRecordedStartTime}, + {SENSOR_RECORDER_QUERY_END_TIME, kRecordedEndTime}, + }; + + if (SENSOR_HUMAN_PEDOMETER == sensor_ || SENSOR_PRESSURE == sensor_) { + map_query.insert(std::make_pair(SENSOR_RECORDER_QUERY_ANCHOR_TIME, kRecordedAnchorTime)); + map_query.insert(std::make_pair(SENSOR_RECORDER_QUERY_TIME_INTERVAL, kRecordedInterval)); + } + + for (auto& it : map_query) { + int val = -1; + if (query.get(it.second).is()) { + val = query.get(it.second).get(); + if (0 <= val) { + int ret = sensor_recorder_query_set_time(query_h, it.first, val); + if (SENSOR_ERROR_NONE != ret) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, + "Failed to set query parameter", + ("Failed to set (%d) query parameter, error: %d (%s)", sensor_, ret, get_error_message(ret))); + } + } + } + } + + return PlatformResult(ErrorCode::NO_ERROR); + } + sensor_type_e sensor_; sensor_listener_h handle_; SensorEventConverter converter_; + SensorRecordedConverter converter_recorded_; + picojson::array* recorded_data_; + std::mutex mutex_; }; class HumanActivityMonitorManager::Monitor::GpsMonitor : public HumanActivityMonitorManager::Monitor { @@ -1089,11 +1404,86 @@ HumanActivityMonitorManager::HumanActivityMonitorManager() return PlatformResult(ErrorCode::NO_ERROR); }; - monitors_.insert(std::make_pair(kActivityTypePedometer, std::make_shared(kActivityTypePedometer, SENSOR_HUMAN_PEDOMETER, convert_pedometer))); + auto convert_recorded_pedometer = [](void* data, picojson::object* obj) -> PlatformResult { + ScopeLogger("convert_recorded_pedometer"); + + SensorRecorderDataMap map_int { + {SENSOR_RECORDER_DATA_STEPS, kRecordedTotalStepCount}, + {SENSOR_RECORDER_DATA_WALK_STEPS, kRecordedWalkStepCount}, + {SENSOR_RECORDER_DATA_RUN_STEPS, kRecordedRunStepCount} + }; + + SensorRecorderDataMap map_double { + {SENSOR_RECORDER_DATA_DISTANCE, kRecordedDistance}, + {SENSOR_RECORDER_DATA_CALORIE, kRecordedCalorie} + }; + + auto result = ConvertRecordedInt(data, obj, map_int); + if (!result) { + return result; + } + + result = ConvertRecordedDouble(data, obj, map_double); + if (!result) { + return result; + } + + return ConvertRecordedTime(data, obj); + }; + + auto convert_recorded_hrm = [](void* data, picojson::object* obj) -> PlatformResult { + ScopeLogger("convert_recorded_hrm"); + + SensorRecorderDataMap map_int { + {SENSOR_RECORDER_DATA_HEART_RATE, kRecordedHeartRate}, + }; + + auto result = ConvertRecordedInt(data, obj, map_int); + if (!result) { + return result; + } + + return ConvertRecordedTime(data, obj); + }; + + auto convert_recorded_sleep_monitor = [](void* data, picojson::object* obj) -> PlatformResult { + ScopeLogger("convert_recorded_sleep_monitor"); + + SensorRecorderDataMap map_int { + {SENSOR_RECORDER_DATA_SLEEP_STATE, kStatus} + }; + + auto result = ConvertRecordedInt(data, obj, map_int); + if (!result) { + return result; + } + + return ConvertRecordedTime(data, obj); + }; + + auto convert_recorded_pressure = [](void* data, picojson::object* obj) -> PlatformResult { + ScopeLogger("convert_recorded_pressure"); + + SensorRecorderDataMap map_double { + {SENSOR_RECORDER_DATA_MAX_PRESSURE, kRecordedMax}, + {SENSOR_RECORDER_DATA_MIN_PRESSURE, kRecordedMin}, + {SENSOR_RECORDER_DATA_AVERAGE_PRESSURE, kRecordedAverage} + }; + + auto result = ConvertRecordedDouble(data, obj, map_double); + if (!result) { + return result; + } + + return ConvertRecordedTime(data, obj); + }; + + monitors_.insert(std::make_pair(kActivityTypePedometer, std::make_shared(kActivityTypePedometer, SENSOR_HUMAN_PEDOMETER, convert_pedometer, convert_recorded_pedometer))); monitors_.insert(std::make_pair(kActivityTypeWristUp, std::make_shared(kActivityTypeWristUp))); - monitors_.insert(std::make_pair(kActivityTypeHrm, std::make_shared(kActivityTypeHrm, SENSOR_HRM, convert_hrm))); + monitors_.insert(std::make_pair(kActivityTypeHrm, std::make_shared(kActivityTypeHrm, SENSOR_HRM, convert_hrm, convert_recorded_hrm))); monitors_.insert(std::make_pair(kActivityTypeGps, std::make_shared(kActivityTypeGps))); - monitors_.insert(std::make_pair(kActivityTypeSleepMonitor, std::make_shared(kActivityTypeSleepMonitor, SENSOR_HUMAN_SLEEP_MONITOR, convert_sleep))); + monitors_.insert(std::make_pair(kActivityTypeSleepMonitor, std::make_shared(kActivityTypeSleepMonitor, SENSOR_HUMAN_SLEEP_MONITOR, convert_sleep, convert_recorded_sleep_monitor))); + monitors_.insert(std::make_pair(kActivityTypePressure, std::make_shared(kActivityTypePressure, SENSOR_PRESSURE, nullptr, convert_recorded_pressure))); } HumanActivityMonitorManager::~HumanActivityMonitorManager() { @@ -1135,6 +1525,23 @@ PlatformResult HumanActivityMonitorManager::RemoveActivityRecognitionListener(co return activity_recognition_->RemoveListener(watch_id); } +PlatformResult HumanActivityMonitorManager::StartDataRecorder(const std::string& type, + int interval, int retention_period) { + ScopeLogger(); + return GetMonitor(type)->StartDataRecorder(interval, retention_period); +} + +PlatformResult HumanActivityMonitorManager::StopDataRecorder(const std::string& type) { + ScopeLogger(); + return GetMonitor(type)->StopDataRecorder(); +} + +PlatformResult HumanActivityMonitorManager::ReadRecorderData( + const std::string& type, picojson::array* data, const picojson::value& query) { + ScopeLogger(); + return GetMonitor(type)->ReadRecorderData(data, query); +} + std::shared_ptr HumanActivityMonitorManager::GetMonitor(const std::string& type) { ScopeLogger(); diff --git a/src/humanactivitymonitor/humanactivitymonitor_manager.h b/src/humanactivitymonitor/humanactivitymonitor_manager.h index ffa858f..caca7a3 100755 --- a/src/humanactivitymonitor/humanactivitymonitor_manager.h +++ b/src/humanactivitymonitor/humanactivitymonitor_manager.h @@ -49,6 +49,12 @@ class HumanActivityMonitorManager { JsonCallback callback, long* watch_id); common::PlatformResult RemoveActivityRecognitionListener(const long watchId); + common::PlatformResult StartDataRecorder(const std::string& type, + int interval, int retention_period); + common::PlatformResult StopDataRecorder(const std::string& type); + common::PlatformResult ReadRecorderData(const std::string& type, + picojson::array* data, + const picojson::value& query); private: class Monitor;