// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "service-evtmgr/BatteryMessages.hpp" #include "service-evtmgr/EVMessages.hpp" #include "service-evtmgr/KbdMessage.hpp" #include "service-evtmgr/ScreenLightControlMessage.hpp" #include "service-evtmgr/Constants.hpp" #include "service-evtmgr/EventManager.hpp" #include "service-evtmgr/WorkerEvent.hpp" #include "battery-level-check/BatteryLevelCheck.hpp" #include "screen-light-control/ScreenLightControl.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr auto loggerDelayMs = 1000 * 60 * 5; constexpr auto loggerTimerName = "Logger"; } // namespace EventManager::EventManager(const std::string &name) : sys::Service(name, "", stackDepth), loggerTimer{sys::TimerFactory::createPeriodicTimer( this, loggerTimerName, std::chrono::milliseconds{loggerDelayMs}, [this](sys::Timer & /*timer*/) { dumpLogsToFile(); })}, Vibra(std::make_unique(this)) { LOG_INFO("[%s] Initializing", name.c_str()); alarmTimestamp = 0; alarmID = 0; bus.channels.push_back(sys::BusChannel::ServiceDBNotifications); loggerTimer.start(); } EventManager::~EventManager() { if (EventWorker != nullptr) { EventWorker->close(); } } // those static functions and variables will be replaced by Settings API static std::string tzSet; static void setSettingsTimeZone(const std::string &timeZone) { tzSet = timeZone; } std::string getSettingsTimeZone() { return tzSet; } // Invoked upon receiving data message sys::MessagePointer EventManager::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp) { bool handled = false; if (msgl->messageType == MessageType::DBServiceNotification) { auto *msg = dynamic_cast(msgl); if (msg != nullptr) { if (msg->interface == db::Interface::Name::Alarms) { alarmDBEmpty = false; alarmIsValid = false; handled = true; } } } else if (msgl->messageType == MessageType::EVM_GPIO) { LOG_DEBUG("EVM_GPIO msg"); } else if (msgl->messageType == MessageType::KBDKeyEvent && (msgl->sender == this->GetName() || msgl->sender == service::name::service_desktop)) { auto *msg = dynamic_cast(msgl); assert(msg); auto message = std::make_shared(); message->key = msg->key; if (message->key.state == RawKey::State::Pressed) { const auto code = message->key.key_code; if (code == bsp::KeyCodes::FnRight) { bus.sendUnicast(message, service::name::system_manager); } else if (code == bsp::KeyCodes::SSwitchUp || code == bsp::KeyCodes::SSwitchMid || code == bsp::KeyCodes::SSwitchDown) { const auto mode = sys::SystemManager::translateSliderState(message->key); bus.sendUnicast(std::make_shared(mode), service::name::system_manager); } if (keypadLightState == bsp::keypad_backlight::State::activeMode && !isKeypadLightInCallMode) { bsp::keypad_backlight::turnOnAll(); startKeypadLightTimer(); } } // send key to focused application if (!targetApplication.empty()) { bus.sendUnicast(message, targetApplication); } // notify application manager to prevent screen locking app::manager::Controller::preventBlockingDevice(this); handled = true; } else if (msgl->messageType == MessageType::EVMFocusApplication) { auto *msg = static_cast(msgl); if (msg->sender == "ApplicationManager") { targetApplication = msg->getApplication(); handled = true; LOG_INFO("Switching focus to %s", targetApplication.c_str()); } } else if (msgl->messageType == MessageType::EVMMinuteUpdated && msgl->sender == this->GetName()) { auto msg = static_cast(msgl); handleMinuteUpdate(msg->timestamp); handled = true; } else if (auto msg = dynamic_cast(msgl); msg) { AudioServiceAPI::SendEvent(this, msg->getEvent()); handled = true; } else if (!targetApplication.empty() && dynamic_cast(msgl) != nullptr) { bus.sendUnicast(std::make_shared(), targetApplication); } else if (msgl->messageType == MessageType::EVMGetBoard) { using namespace bsp; auto msg = std::make_shared(true); auto board = magnetometer::GetBoard(); msg->board = board; LOG_INFO("Board discovered: %s", c_str(board)); return msg; } else if (msgl->messageType == MessageType::EVMModemStatus) { if (auto msg = dynamic_cast(msgl)) { auto message = std::make_shared(MessageType::EVMModemStatus); message->state = msg->state; bus.sendUnicast(message, "ServiceCellular"); } handled = true; } else if (auto msg = dynamic_cast(msgl)) { if (msg->type == CellularMessage::Type::TimeUpdated) { if (auto msg = dynamic_cast(msgl)) { if (auto time = msg->getTime(); time) { LOG_INFO("RTC set by network time."); bsp::rtc_SetDateTime(&time.value()); } if (auto timeZoneOffset = msg->getTimeZoneOffset(); timeZoneOffset) { setSettingsTimeZone(msg->getTimeZoneString().value()); utils::time::Time::setTimeZoneOffset(msg->getTimeZoneOffset().value()); } auto notification = std::make_shared(MessageType::EVMTimeUpdated); bus.sendMulticast(notification, sys::BusChannel::ServiceEvtmgrNotifications); } } } else if (msgl->messageType == MessageType::EVMRingIndicator) { auto msg = std::make_shared(); bus.sendUnicast(std::move(msg), ServiceCellular::serviceName); } if (handled) { return std::make_shared(); } else { return std::make_shared(sys::ReturnCodes::Unresolved); } } // Invoked during initialization sys::ReturnCodes EventManager::InitHandler() { settings->init(service::ServiceProxy(shared_from_this())); screenLightControl = std::make_unique(settings, this); connect(sdesktop::developerMode::DeveloperModeRequest(), [&](sys::Message *msg) { using namespace sdesktop::developerMode; auto req = static_cast(msg); if (typeid(*req->event.get()) == typeid(AppFocusChangeEvent)) { auto event = std::make_unique(targetApplication); auto message = std::make_shared(std::move(event)); bus.sendUnicast(message, service::name::service_desktop); } return std::make_shared(); }); connect(app::AppInputEventMessage(gui::InputEvent(RawKey())), [&](sys::Message *msgl) { auto msg = static_cast(msgl); assert(msg); auto message = std::make_shared(msg->getEvent()); if (!targetApplication.empty()) { bus.sendUnicast(std::move(message), targetApplication); } return std::make_shared(); }); connect(sevm::KeypadBacklightMessage(bsp::keypad_backlight::Action::turnOff), [&](sys::Message *msgl) { auto request = static_cast(msgl); auto response = std::make_shared(); response->success = processKeypadBacklightRequest(request->action); return response; }); connect(sevm::BatterySetCriticalLevel(0), [&](sys::Message *msgl) { auto request = static_cast(msgl); battery_level_check::setBatteryCriticalLevel(request->criticalLevel); return std::make_shared(); }); connect(sevm::ScreenLightControlMessage(), [&](sys::Message *msgl) { auto *m = dynamic_cast(msgl); screenLightControl->processRequest(m->action, m->parameters); return std::make_shared(); }); connect(sevm::ScreenLightControlRequestParameters(), [&](sys::Message *msgl) { screen_light_control::Parameters params = {screenLightControl->getBrightnessValue()}; auto msg = std::make_shared( screenLightControl->getLightState(), screenLightControl->getAutoModeState(), params); return msg; }); connect(sevm::RtcUpdateTimeMessage(0), [&](sys::Message *msgl) { auto msg = static_cast(msgl); bsp::rtc_SetDateTimeFromTimestamp(msg->getTime()); bsp::rtc_SetMinuteAlarm(msg->getTime()); handleMinuteUpdate(msg->getTime()); return sys::msgHandled(); }); connect(sevm::BatteryStatusChangeMessage(), [&](sys::Message *msgl) { if (msgl->sender == this->GetName()) { LOG_INFO("Battery level: %d , charging: %d", Store::Battery::get().level, Store::Battery::get().state == Store::Battery::State::Charging); if (Store::Battery::get().state == Store::Battery::State::Discharging) { bus.sendUnicast(std::make_shared(), service::name::system_manager); } if (!targetApplication.empty()) { bus.sendUnicast(std::make_shared(), targetApplication); } } return std::make_shared(); }); connect(sevm::VibraMessage(bsp::vibrator::Action::stop), [&](sys::Message *msgl) { auto request = static_cast(msgl); processVibraRequest(request->action, request->repetitionTime); return std::make_shared(); }); connect(sevm::ToggleTorchOnOffMessage(), [&]([[maybe_unused]] sys::Message *msg) { toggleTorchOnOff(); return sys::MessageNone{}; }); connect(sevm::ToggleTorchColorMessage(), [&]([[maybe_unused]] sys::Message *msg) { toggleTorchColor(); return sys::MessageNone{}; }); connect(sevm::RequestPhoneModeForceUpdate(), [&]([[maybe_unused]] sys::Message *msg) { EventWorker->requestSliderPositionRead(); return sys::MessageNone{}; }); // initialize keyboard worker EventWorker = std::make_unique(this); using namespace std::string_literals; std::list list; list.emplace_back("qIrq"s, sizeof(uint8_t), 10); list.emplace_back("qHeadset"s, sizeof(uint8_t), 10); list.emplace_back("qBattery"s, sizeof(uint8_t), 10); list.emplace_back("qRTC"s, sizeof(uint8_t), 20); list.emplace_back("qSIM"s, sizeof(uint8_t), 5); list.emplace_back("qMagnetometer"s, sizeof(uint8_t), 5); list.emplace_back(WorkerEvent::MagnetometerNotifyQueue, sizeof(uint8_t), 1); list.emplace_back("qTorch"s, sizeof(uint8_t), 5); list.emplace_back("qLightSensor"s, sizeof(uint8_t), 5); list.emplace_back("qChargerDetect"s, sizeof(uint8_t), 5); EventWorker->init(list, settings); EventWorker->run(); return sys::ReturnCodes::Success; } sys::ReturnCodes EventManager::DeinitHandler() { settings->deinit(); EventWorker->close(); EventWorker.reset(); EventWorker = nullptr; return sys::ReturnCodes::Success; } void EventManager::ProcessCloseReason(sys::CloseReason closeReason) { bsp::torch::turn(bsp::torch::State::off); sendCloseReadyMessage(this); } sys::ReturnCodes EventManager::SwitchPowerModeHandler(const sys::ServicePowerMode mode) { LOG_FATAL("[ServiceEvtMgr] PowerModeHandler: %s", c_str(mode)); switch (mode) { case sys::ServicePowerMode ::Active: break; case sys::ServicePowerMode ::SuspendToRAM: case sys::ServicePowerMode ::SuspendToNVM: break; } return sys::ReturnCodes::Success; } bool EventManager::messageSetApplication(sys::Service *sender, const std::string &applicationName) { auto msg = std::make_shared(applicationName); return sender->bus.sendUnicast(msg, service::name::evt_manager); } void EventManager::dumpLogsToFile() { const auto logPath = purefs::dir::getUserDiskPath() / LOG_FILE_NAME; const bool dumpLog = !(std::filesystem::exists(logPath) && std::filesystem::file_size(logPath) > MAX_LOG_FILE_SIZE); if (dumpLog) { const auto &logs = Log::Logger::get().getLogs(); std::fstream logFile(logPath, std::fstream::out | std::fstream::app); logFile.write(logs.data(), logs.size()); } } void EventManager::handleMinuteUpdate(time_t timestamp) { if (!targetApplication.empty()) { auto message = std::make_shared(MessageType::EVMMinuteUpdated); message->timestamp = timestamp; bus.sendUnicast(message, targetApplication); } } bool EventManager::processKeypadBacklightRequest(bsp::keypad_backlight::Action action) { bool response = false; switch (action) { case bsp::keypad_backlight::Action::turnOn: if (keypadLightState == bsp::keypad_backlight::State::activeMode) { keypadLightTimer.stop(); } keypadLightState = bsp::keypad_backlight::State::on; response = bsp::keypad_backlight::turnOnAll(); break; case bsp::keypad_backlight::Action::turnOff: if (keypadLightState == bsp::keypad_backlight::State::activeMode) { keypadLightTimer.stop(); } keypadLightState = bsp::keypad_backlight::State::off; response = bsp::keypad_backlight::shutdown(); break; case bsp::keypad_backlight::Action::checkState: response = bsp::keypad_backlight::checkState(); break; case bsp::keypad_backlight::Action::turnOnActiveMode: keypadLightState = bsp::keypad_backlight::State::activeMode; response = bsp::keypad_backlight::turnOnAll(); startKeypadLightTimer(); break; case bsp::keypad_backlight::Action::turnOnCallMode: if (keypadLightTimer.isActive()) { keypadLightTimer.stop(); } isKeypadLightInCallMode = true; response = bsp::keypad_backlight::turnOnFunctionKeysBacklight(); break; case bsp::keypad_backlight::Action::turnOffCallMode: isKeypadLightInCallMode = false; restoreKeypadLightState(); break; } return response; } void EventManager::restoreKeypadLightState() { switch (keypadLightState) { case bsp::keypad_backlight::State::off: processKeypadBacklightRequest(bsp::keypad_backlight::Action::turnOff); break; case bsp::keypad_backlight::State::on: processKeypadBacklightRequest(bsp::keypad_backlight::Action::turnOn); break; case bsp::keypad_backlight::State::activeMode: processKeypadBacklightRequest(bsp::keypad_backlight::Action::turnOnActiveMode); break; } } void EventManager::startKeypadLightTimer() { keypadLightTimer = sys::TimerFactory::createSingleShotTimer( this, keypadLightTimerName, keypadLightTimerTimeout, [this](sys::Timer &) { bsp::keypad_backlight::shutdown(); }); keypadLightTimer.start(); } bool EventManager::processVibraRequest(bsp::vibrator::Action act, std::chrono::milliseconds RepetitionTime) { switch (act) { case bsp::vibrator::Action::pulse: Vibra->Pulse(); break; case bsp::vibrator::Action::pulseRepeat: Vibra->PulseRepeat(RepetitionTime); break; case bsp::vibrator::Action::pulseRepeatInfinite: Vibra->PulseRepeat(); break; case bsp::vibrator::Action::stop: Vibra->PulseRepeatStop(); break; } return true; } void EventManager::toggleTorchOnOff() { auto state = bsp::torch::getState(); auto newState = (state.second == bsp::torch::State::off) ? bsp::torch::State::on : bsp::torch::State::off; bsp::torch::turn(newState, bsp::torch::ColourTemperature::coldest); } void EventManager::toggleTorchColor() { auto state = bsp::torch::getState(); if (state.second == bsp::torch::State::on) { auto color = bsp::torch::getColorTemp(); auto newColor = (color == bsp::torch::ColourTemperature::coldest) ? bsp::torch::ColourTemperature::warmest : bsp::torch::ColourTemperature::coldest; bsp::torch::turn(bsp::torch::State::on, newColor); } }