diff options
Diffstat (limited to 'src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/mobile/set_interior_vehicle_data_request.cc')
-rw-r--r-- | src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/mobile/set_interior_vehicle_data_request.cc | 592 |
1 files changed, 592 insertions, 0 deletions
diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/mobile/set_interior_vehicle_data_request.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/mobile/set_interior_vehicle_data_request.cc new file mode 100644 index 0000000000..17a492b5aa --- /dev/null +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/mobile/set_interior_vehicle_data_request.cc @@ -0,0 +1,592 @@ +/* + Copyright (c) 2018, Ford Motor Company + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following + disclaimer in the documentation and/or other materials provided with the + distribution. + + Neither the name of the Ford Motor Company nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rc_rpc_plugin/commands/mobile/set_interior_vehicle_data_request.h" +#include "rc_rpc_plugin/rc_module_constants.h" +#include "rc_rpc_plugin/rc_rpc_plugin.h" +#include "rc_rpc_plugin/rc_helpers.h" +#include "smart_objects/enum_schema_item.h" +#include "utils/macro.h" +#include "json/json.h" +#include "utils/helpers.h" +#include "interfaces/MOBILE_API.h" + +namespace rc_rpc_plugin { +namespace commands { + +using namespace json_keys; +using namespace message_params; + +namespace { +std::vector<std::string> GetModuleReadOnlyParams( + const std::string& module_type) { + std::vector<std::string> module_ro_params; + if (enums_value::kClimate == module_type) { + module_ro_params.push_back(kCurrentTemperature); + } else if (enums_value::kRadio == module_type) { + module_ro_params.push_back(kRdsData); + module_ro_params.push_back(kAvailableHDs); + module_ro_params.push_back(kSignalStrength); + module_ro_params.push_back(kSignalChangeThreshold); + module_ro_params.push_back(kState); + module_ro_params.push_back(kSisData); + } + return module_ro_params; +} + +const std::map<std::string, std::string> GetModuleDataToCapabilitiesMapping() { + std::map<std::string, std::string> mapping; + // climate + mapping["fanSpeed"] = "fanSpeedAvailable"; + mapping["currentTemperature"] = "currentTemperatureAvailable"; + mapping["desiredTemperature"] = "desiredTemperatureAvailable"; + mapping["acEnable"] = "acEnableAvailable"; + mapping["circulateAirEnable"] = "circulateAirEnableAvailable"; + mapping["autoModeEnable"] = "autoModeEnableAvailable"; + mapping["defrostZone"] = "defrostZoneAvailable"; + mapping["dualModeEnable"] = "dualModeEnableAvailable"; + mapping["acMaxEnable"] = "acMaxEnableAvailable"; + mapping["ventilationMode"] = "ventilationModeAvailable"; + mapping["heatedSteeringWheelEnable"] = "heatedSteeringWheelAvailable"; + mapping["heatedWindshieldEnable"] = "heatedWindshieldAvailable"; + mapping["heatedMirrorsEnable"] = "heatedMirrorsAvailable"; + mapping["heatedRearWindowEnable"] = "heatedRearWindowAvailable"; + + // radio + mapping["band"] = "radioBandAvailable"; + mapping["frequencyInteger"] = "radioFrequencyAvailable"; + mapping["frequencyFraction"] = "radioFrequencyAvailable"; + mapping["rdsData"] = "rdsDataAvailable"; + mapping["availableHDs"] = "availableHDsAvailable"; + mapping["hdChannel"] = "availableHDsAvailable"; + mapping["hdRadioEnable"] = "hdRadioEnableAvailable"; + mapping["signalStrength"] = "signalStrengthAvailable"; + mapping["signalChangeThreshold"] = "signalChangeThresholdAvailable"; + mapping["radioEnable"] = "radioEnableAvailable"; + mapping["state"] = "stateAvailable"; + mapping["sisData"] = "sisDataAvailable"; + + // seat + mapping["heatingEnabled"] = "heatingEnabledAvailable"; + mapping["coolingEnabled"] = "coolingEnabledAvailable"; + mapping["heatingLevel"] = "heatingLevelAvailable"; + mapping["coolingLevel"] = "coolingLevelAvailable"; + mapping["horizontalPosition"] = "horizontalPositionAvailable"; + mapping["verticalPosition"] = "verticalPositionAvailable"; + mapping["frontVerticalPosition"] = "frontVerticalPositionAvailable"; + mapping["backVerticalPosition"] = "backVerticalPositionAvailable"; + mapping["backTiltAngle"] = "backTiltAngleAvailable"; + mapping["headSupportHorizontalPosition"] = + "headSupportHorizontalPositionAvailable"; + mapping["headSupportVerticalPosition"] = + "headSupportVerticalPositionAvailable"; + mapping["massageEnabled"] = "massageEnabledAvailable"; + mapping["massageMode"] = "massageModeAvailable"; + mapping["massageCushionFirmness"] = "massageCushionFirmnessAvailable"; + mapping["memory"] = "memoryAvailable"; + // audio + mapping["source"] = "sourceAvailable"; + mapping["keepContext"] = "keepContextAvailable"; + mapping["volume"] = "volumeAvailable"; + mapping["equalizerSettings"] = "equalizerAvailable"; + + // hmi settings + mapping["distanceUnit"] = "distanceUnitAvailable"; + mapping["temperatureUnit"] = "temperatureUnitAvailable"; + mapping["displayMode"] = "displayModeUnitAvailable"; + + return mapping; +} +} // namespace + +CREATE_LOGGERPTR_GLOBAL(logger_, "RemoteControlModule") + +SetInteriorVehicleDataRequest::SetInteriorVehicleDataRequest( + const app_mngr::commands::MessageSharedPtr& message, + const RCCommandParams& params) + : RCCommandRequest(message, params) {} + +SetInteriorVehicleDataRequest::~SetInteriorVehicleDataRequest() {} + +const std::string LightName(const smart_objects::SmartObject& light_name) { + const char* name; + const bool ok = NsSmartDeviceLink::NsSmartObjects:: + EnumConversionHelper<mobile_apis::LightName::eType>::EnumToCString( + static_cast<mobile_apis::LightName::eType>(light_name.asUInt()), + &name); + return ok ? name : "unknown"; +} + +bool CheckLightDataByCapabilities( + const smart_objects::SmartObject& capabilities, + const smart_objects::SmartObject& light_data) { + LOG4CXX_AUTO_TRACE(logger_); + std::map<std::string, std::string> lightCapsMapping = { + {message_params::kId, strings::kName}, + {message_params::kDensity, strings::kDensityAvailable}, + {message_params::kColor, strings::kRGBColorSpaceAvailable}}; + auto it = light_data.map_begin(); + for (; it != light_data.map_end(); ++it) { + if (message_params::kStatus == it->first || + message_params::kId == it->first) { + continue; + } + const std::string& caps_key = lightCapsMapping[it->first]; + LOG4CXX_DEBUG(logger_, + "Checking request parameter " + << it->first << " with capabilities. Appropriate key is " + << caps_key); + + if (!capabilities.keyExists(caps_key)) { + LOG4CXX_DEBUG(logger_, + "Capability " + << caps_key + << " is missed in RemoteControl capabilities"); + return false; + } + if (!capabilities[caps_key].asBool()) { + LOG4CXX_DEBUG(logger_, + "Capability " + << caps_key + << " is switched off in RemoteControl capabilities"); + return false; + } + } + return true; +} + +bool CheckLightNameByCapabilities( + const smart_objects::SmartObject& capabilities_status, + const smart_objects::SmartObject& light_data) { + LOG4CXX_AUTO_TRACE(logger_); + auto it = capabilities_status.asArray()->begin(); + for (; it != capabilities_status.asArray()->end(); ++it) { + const smart_objects::SmartObject& so = *it; + const int64_t current_id = so[message_params::kName].asInt(); + if (current_id == light_data[message_params::kId].asInt()) { + return CheckLightDataByCapabilities(so, light_data); + } + } + LOG4CXX_DEBUG(logger_, "There is no such light name in capabilities"); + return false; +} + +bool CheckRadioBandByCapabilities( + const smart_objects::SmartObject& capabilities_status, + const smart_objects::SmartObject& request_parameter) { + mobile_apis::RadioBand::eType radio_band = + static_cast<mobile_apis::RadioBand::eType>(request_parameter.asUInt()); + if (mobile_apis::RadioBand::XM == radio_band) { + if (!capabilities_status.keyExists(strings::kSiriusxmRadioAvailable)) { + LOG4CXX_DEBUG(logger_, + "Capability " + << strings::kSiriusxmRadioAvailable + << " is missed in RemoteControl capabilities"); + return false; + } + if (!capabilities_status[strings::kSiriusxmRadioAvailable].asBool()) { + LOG4CXX_DEBUG(logger_, + "Capability " + << strings::kSiriusxmRadioAvailable + << " is switched off in RemoteControl capabilities"); + return false; + } + } + return true; +} + +bool CheckControlDataByCapabilities( + const smart_objects::SmartObject& capabilities_status, + const smart_objects::SmartObject& control_data) { + LOG4CXX_AUTO_TRACE(logger_); + std::map<std::string, std::string> mapping = + GetModuleDataToCapabilitiesMapping(); + auto it = control_data.map_begin(); + for (; it != control_data.map_end(); ++it) { + const std::string& request_parameter = it->first; + if (message_params::kId == request_parameter) { + continue; + } + if (message_params::kLightState == request_parameter) { + auto light_data = control_data[request_parameter].asArray()->begin(); + for (; light_data != control_data[request_parameter].asArray()->end(); + ++light_data) { + if (!CheckLightNameByCapabilities( + capabilities_status[strings::kSupportedLights], *light_data)) { + return false; + } + } + return true; + } + const std::string& caps_key = mapping[request_parameter]; + LOG4CXX_DEBUG(logger_, + "Checking request parameter " + << request_parameter + << " with capabilities. Appropriate key is " << caps_key); + + if (!capabilities_status.keyExists(caps_key)) { + LOG4CXX_DEBUG(logger_, + "Capability " + << caps_key + << " is missed in RemoteControl capabilities"); + return false; + } + if (!capabilities_status[caps_key].asBool()) { + LOG4CXX_DEBUG(logger_, + "Capability " + << caps_key + << " is switched off in RemoteControl capabilities"); + return false; + } + if (message_params::kBand == request_parameter && + !CheckRadioBandByCapabilities(capabilities_status, + control_data[request_parameter])) { + return false; + } + } + return true; +} + +bool CheckIfModuleDataExistInCapabilities( + const smart_objects::SmartObject& rc_capabilities, + const smart_objects::SmartObject& module_data) { + LOG4CXX_AUTO_TRACE(logger_); + + const auto& all_module_types = RCHelpers::GetModulesList(); + const auto& get_module_data_key = RCHelpers::GetModuleTypeToDataMapping(); + const auto& get_capabilities_key = + RCHelpers::GetModuleTypeToCapabilitiesMapping(); + + bool is_module_data_valid = false; + for (const auto& module_type : all_module_types) { + const auto module_data_key = get_module_data_key(module_type); + const auto capabilities_key = get_capabilities_key(module_type); + if (module_data.keyExists(module_data_key)) { + if (!rc_capabilities.keyExists(capabilities_key)) { + LOG4CXX_DEBUG(logger_, module_data_key << " capabilities not present"); + return false; + } + const smart_objects::SmartObject& caps = + rc_capabilities[capabilities_key]; + if (message_params::kHmiSettingsControlData == module_data_key || + message_params::kLightControlData == module_data_key) { + is_module_data_valid = + CheckControlDataByCapabilities(caps, module_data[module_data_key]); + } else { + is_module_data_valid = CheckControlDataByCapabilities( + caps[0], module_data[module_data_key]); + } + } + } + return is_module_data_valid; +} + +bool isModuleTypeAndDataMatch(const std::string& module_type, + const smart_objects::SmartObject& module_data) { + LOG4CXX_AUTO_TRACE(logger_); + const auto& all_module_types = RCHelpers::GetModulesList(); + const auto& data_mapping = RCHelpers::GetModuleTypeToDataMapping(); + bool module_type_and_data_match = false; + for (const auto& type : all_module_types) { + if (type == module_type) { + module_type_and_data_match = module_data.keyExists(data_mapping(type)); + break; + } + } + return module_type_and_data_match; +} + +void SetInteriorVehicleDataRequest::Execute() { + LOG4CXX_AUTO_TRACE(logger_); + + smart_objects::SmartObject& module_data = + (*message_)[app_mngr::strings::msg_params][message_params::kModuleData]; + const std::string module_type = ModuleType(); + + if (isModuleTypeAndDataMatch(module_type, module_data)) { + const smart_objects::SmartObject* rc_capabilities = + hmi_capabilities_.rc_capability(); + if (rc_capabilities && + !CheckIfModuleDataExistInCapabilities(*rc_capabilities, module_data)) { + LOG4CXX_WARN(logger_, "Accessing not supported module data"); + SetResourceState(ModuleType(), ResourceState::FREE); + SendResponse(false, + mobile_apis::Result::UNSUPPORTED_RESOURCE, + "Accessing not supported module data"); + return; + } + if (AreAllParamsReadOnly(module_data)) { + LOG4CXX_WARN(logger_, "All request params in module type are READ ONLY!"); + SetResourceState(ModuleType(), ResourceState::FREE); + SendResponse(false, + mobile_apis::Result::READ_ONLY, + "All request params in module type are READ ONLY!"); + return; + } + if (AreReadOnlyParamsPresent(module_data)) { + LOG4CXX_DEBUG(logger_, "Request module type has READ ONLY parameters"); + LOG4CXX_DEBUG(logger_, "Cutting-off READ ONLY parameters... "); + CutOffReadOnlyParams(module_data); + } + application_manager_.RemoveHMIFakeParameters(message_); + + app_mngr::ApplicationSharedPtr app = + application_manager_.application(connection_key()); + (*message_)[app_mngr::strings::msg_params][app_mngr::strings::app_id] = + app->app_id(); + + const bool app_wants_to_set_audio_src = + module_data.keyExists(message_params::kAudioControlData) && + module_data[message_params::kAudioControlData].keyExists( + message_params::kSource); + + if (app_wants_to_set_audio_src && !app->IsAllowedToChangeAudioSource()) { + LOG4CXX_WARN(logger_, "App is not allowed to change audio source"); + SetResourceState(ModuleType(), ResourceState::FREE); + SendResponse(false, + mobile_apis::Result::REJECTED, + "App is not allowed to change audio source"); + return; + } + + SendHMIRequest(hmi_apis::FunctionID::RC_SetInteriorVehicleData, + &(*message_)[app_mngr::strings::msg_params], + true); + } else { + LOG4CXX_WARN(logger_, "Request module type & data mismatch!"); + SendResponse(false, + mobile_apis::Result::INVALID_DATA, + "Request module type & data mismatch!"); + } +} + +void SetInteriorVehicleDataRequest::on_event( + const app_mngr::event_engine::Event& event) { + LOG4CXX_AUTO_TRACE(logger_); + RCCommandRequest::on_event(event); + + if (hmi_apis::FunctionID::RC_SetInteriorVehicleData != event.id()) { + return; + } + + const smart_objects::SmartObject& hmi_response = event.smart_object(); + mobile_apis::Result::eType result_code = + GetMobileResultCode(static_cast<hmi_apis::Common_Result::eType>( + hmi_response[app_mngr::strings::params][app_mngr::hmi_response::code] + .asUInt())); + + bool result = + helpers::Compare<mobile_apis::Result::eType, helpers::EQ, helpers::ONE>( + result_code, + mobile_apis::Result::SUCCESS, + mobile_apis::Result::WARNINGS); + + smart_objects::SmartObject response_params; + if (result) { + response_params = hmi_response[app_mngr::strings::msg_params]; + if (enums_value::kAudio == ModuleType()) { + CheckAudioSource(( + *message_)[app_mngr::strings::msg_params][message_params::kModuleData] + [message_params::kAudioControlData]); + } + } + std::string info; + GetInfo(hmi_response, info); + SendResponse( + result, result_code, info.c_str(), result ? &response_params : nullptr); +} + +const smart_objects::SmartObject& SetInteriorVehicleDataRequest::ControlData( + const smart_objects::SmartObject& module_data) { + const std::string module_type = ModuleType(); + + const auto& all_module_types = RCHelpers::GetModulesList(); + const auto& data_mapping = RCHelpers::GetModuleTypeToDataMapping(); + for (const auto& type : all_module_types) { + if (type == module_type) { + return module_data[data_mapping(type)]; + } + } + NOTREACHED(); + return module_data[0]; +} + +void SetInteriorVehicleDataRequest::CheckAudioSource( + const smart_objects::SmartObject& audio_data) { + LOG4CXX_AUTO_TRACE(logger_); + const bool should_keep_context = + audio_data.keyExists(message_params::kKeepContext) && + audio_data[message_params::kKeepContext].asBool(); + const bool switch_source_from_app = + mobile_apis::PrimaryAudioSource::MOBILE_APP == + application_manager_.get_current_audio_source() && + mobile_apis::PrimaryAudioSource::MOBILE_APP != + audio_data[message_params::kSource].asInt(); + if (!should_keep_context && switch_source_from_app) { + app_mngr::ApplicationSharedPtr app = + application_manager_.application(connection_key()); + if (app->mobile_projection_enabled()) { + application_manager_.ChangeAppsHMILevel( + app->app_id(), mobile_apis::HMILevel::eType::HMI_LIMITED); + } else { + application_manager_.ChangeAppsHMILevel( + app->app_id(), mobile_apis::HMILevel::eType::HMI_BACKGROUND); + } + } + application_manager_.set_current_audio_source( + audio_data[message_params::kSource].asUInt()); +} + +bool SetInteriorVehicleDataRequest::AreAllParamsReadOnly( + const smart_objects::SmartObject& module_data) { + LOG4CXX_AUTO_TRACE(logger_); + const smart_objects::SmartObject& module_type_params = + ControlData(module_data); + auto it = module_type_params.map_begin(); + std::vector<std::string> ro_params = GetModuleReadOnlyParams(ModuleType()); + for (; it != module_type_params.map_end(); ++it) { + if (!helpers::in_range(ro_params, it->first)) { + return false; + } + } + return true; +} + +bool CheckReadOnlyParamsForAudio( + const smart_objects::SmartObject& module_type_params) { + if (module_type_params.keyExists(message_params::kEqualizerSettings)) { + const auto& equalizer_settings = + module_type_params[message_params::kEqualizerSettings]; + auto it = equalizer_settings.asArray()->begin(); + for (; it != equalizer_settings.asArray()->end(); ++it) { + if (it->keyExists(message_params::kChannelName)) { + LOG4CXX_DEBUG(logger_, + " READ ONLY parameter: " << message_params::kChannelName); + return true; + } + } + } + return false; +} + +bool SetInteriorVehicleDataRequest::AreReadOnlyParamsPresent( + const smart_objects::SmartObject& module_data) { + LOG4CXX_AUTO_TRACE(logger_); + const smart_objects::SmartObject& module_type_params = + ControlData(module_data); + auto it = module_type_params.map_begin(); + const std::string module_type = ModuleType(); + std::vector<std::string> ro_params = GetModuleReadOnlyParams(module_type); + if (enums_value::kAudio == module_type) { + return CheckReadOnlyParamsForAudio(module_type_params); + } + for (; it != module_type_params.map_end(); ++it) { + if (helpers::in_range(ro_params, it->first)) { + return true; + } + } + return false; +} + +void SetInteriorVehicleDataRequest::CutOffReadOnlyParams( + smart_objects::SmartObject& module_data) { + LOG4CXX_AUTO_TRACE(logger_); + const smart_objects::SmartObject& module_type_params = + ControlData(module_data); + const std::string module_type = ModuleType(); + std::vector<std::string> ro_params = GetModuleReadOnlyParams(module_type); + + for (auto& it : ro_params) { + if (module_type_params.keyExists(it)) { + if (enums_value::kClimate == module_type) { + module_data[message_params::kClimateControlData].erase(it); + LOG4CXX_DEBUG(logger_, "Cutting-off READ ONLY parameter: " << it); + } else if (enums_value::kRadio == module_type) { + module_data[message_params::kRadioControlData].erase(it); + LOG4CXX_DEBUG(logger_, "Cutting-off READ ONLY parameter: " << it); + } + } + } + + if (enums_value::kAudio == module_type) { + auto& equalizer_settings = module_data[message_params::kAudioControlData] + [message_params::kEqualizerSettings]; + auto it = equalizer_settings.asArray()->begin(); + for (; it != equalizer_settings.asArray()->end(); ++it) { + if (it->keyExists(message_params::kChannelName)) { + it->erase(message_params::kChannelName); + LOG4CXX_DEBUG(logger_, + "Cutting-off READ ONLY parameter: " + << message_params::kChannelName); + } + } + } +} + +std::string SetInteriorVehicleDataRequest::ModuleType() { + mobile_apis::ModuleType::eType module_type = + static_cast<mobile_apis::ModuleType::eType>( + (*message_)[app_mngr::strings::msg_params] + [message_params::kModuleData][message_params::kModuleType] + .asUInt()); + const char* str; + const bool ok = NsSmartDeviceLink::NsSmartObjects::EnumConversionHelper< + mobile_apis::ModuleType::eType>::EnumToCString(module_type, &str); + return ok ? str : "unknown"; +} + +AcquireResult::eType SetInteriorVehicleDataRequest::AcquireResource( + const app_mngr::commands::MessageSharedPtr& message) { + LOG4CXX_AUTO_TRACE(logger_); + const std::string module_type = ModuleType(); + app_mngr::ApplicationSharedPtr app = + application_manager_.application(CommandRequestImpl::connection_key()); + return resource_allocation_manager_.AcquireResource(module_type, + app->app_id()); +} + +bool SetInteriorVehicleDataRequest::IsResourceFree( + const std::string& module_type) const { + return resource_allocation_manager_.IsResourceFree(module_type); +} + +void SetInteriorVehicleDataRequest::SetResourceState( + const std::string& module_type, const ResourceState::eType state) { + LOG4CXX_AUTO_TRACE(logger_); + app_mngr::ApplicationSharedPtr app = + application_manager_.application(CommandRequestImpl::connection_key()); + resource_allocation_manager_.SetResourceState( + module_type, app->app_id(), state); +} + +} // namespace commands +} // namespace rc_rpc_plugin |