// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
/*
* EventManager.cpp
*
* Created on: 22 maj 2019
* Author: robert
*/
#include "EventManager.hpp"
#include "log/log.hpp"
#include "bsp/keyboard/keyboard.hpp"
#include "WorkerEvent.hpp"
#include "messages/EVMessages.hpp"
#include "vfs.hpp"
#include "bsp/battery-charger/battery_charger.hpp"
#include "service-appmgr/ApplicationManager.hpp"
#include "service-db/api/DBServiceAPI.hpp"
#include "service-db/messages/DBNotificationMessage.hpp"
#include "AudioServiceAPI.hpp"
#include "bsp/harness/bsp_harness.hpp"
#include "harness/Parser.hpp"
#include "harness/events/AtResponse.hpp"
#include "harness/events/FocusApp.hpp"
#include <service-cellular/messages/CellularMessage.hpp>
#include <service-evtmgr/Constants.hpp>
#include <cassert>
#include "bsp/magnetometer/magnetometer.hpp"
#include "bsp/cellular/bsp_cellular.hpp"
#include "bsp/common.hpp"
#include "bsp/rtc/rtc.hpp"
#include <cassert>
EventManager::EventManager(const std::string &name) : sys::Service(name)
{
LOG_INFO("[%s] Initializing", name.c_str());
alarmTimestamp = 0;
alarmID = 0;
busChannels.push_back(sys::BusChannels::ServiceDBNotifications);
}
EventManager::~EventManager()
{
if (EventWorker != nullptr) {
EventWorker->close();
}
}
// Invoked upon receiving data message
sys::Message_t EventManager::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp)
{
bool handled = false;
if (auto msg = dynamic_cast<cellular::RawCommandResp *>(resp)) {
bsp::harness::emit(harness::AtResponse(msg->response).encode());
handled = true;
}
if (msgl->messageType == MessageType::DBServiceNotification) {
auto *msg = dynamic_cast<db::NotificationMessage *>(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()) {
auto *msg = dynamic_cast<sevm::KbdMessage *>(msgl);
assert(msg);
auto message = std::make_shared<sevm::KbdMessage>();
message->key = msg->key;
if (suspended && (message->key.state == RawKey::State::Pressed)) {
suspended = false;
sys::SystemManager::ResumeSystem(this);
}
if (message->key.state == RawKey::State::Pressed && message->key.key_code == bsp::KeyCodes::FnRight) {
// and state == ShutDown
sys::Bus::SendUnicast(message, service::name::system_manager, this);
}
// send key to focused application
if (targetApplication.empty() == false) {
sys::Bus::SendUnicast(message, targetApplication, this);
}
// notify application manager to prevent screen locking
sapm::ApplicationManager::messagePreventBlocking(this);
handled = true;
}
else if (msgl->messageType == MessageType::EVMFocusApplication) {
auto *msg = reinterpret_cast<sevm::EVMFocusApplication *>(msgl);
if (msg->sender == "ApplicationManager") {
targetApplication = msg->getApplication();
handled = true;
LOG_INFO("Switching focus to %s", targetApplication.c_str());
bsp::harness::emit(harness::FocusApp(targetApplication).encode());
}
}
else if (msgl->messageType == MessageType::EVMBatteryLevel && msgl->sender == this->GetName()) {
sevm::BatteryLevelMessage *msg = reinterpret_cast<sevm::BatteryLevelMessage *>(msgl);
if (suspended) {
suspended = false;
sys::SystemManager::ResumeSystem(this);
}
auto message = std::make_shared<sevm::BatteryLevelMessage>();
message->levelPercents = msg->levelPercents;
message->fullyCharged = msg->fullyCharged;
if (targetApplication.empty() == false) {
sys::Bus::SendUnicast(message, targetApplication, this);
}
handled = true;
}
else if (msgl->messageType == MessageType::EVMChargerPlugged && msgl->sender == this->GetName()) {
sevm::BatteryPlugMessage *msg = reinterpret_cast<sevm::BatteryPlugMessage *>(msgl);
if (suspended) {
suspended = false;
sys::SystemManager::ResumeSystem(this);
}
auto message = std::make_shared<sevm::BatteryPlugMessage>();
message->plugged = msg->plugged;
if (!message->plugged) {
sys::Bus::SendUnicast(message, service::name::system_manager, this);
}
if (targetApplication.empty() == false) {
sys::Bus::SendUnicast(message, targetApplication, this);
}
handled = true;
}
else if (msgl->messageType == MessageType::EVMMinuteUpdated && msgl->sender == this->GetName()) {
// resume system first
if (suspended) {
// suspended = false;
// sys::SystemManager::ResumeSystem(this);
}
// HandleAlarmTrigger(msgl);
handled = true;
}
else if (auto msg = dynamic_cast<AudioEventRequest *>(msgl); msg && msgl->sender == this->GetName()) {
AudioServiceAPI::SendEvent(this, msg->getEvent());
handled = true;
}
else if (!targetApplication.empty() && dynamic_cast<sevm::SIMMessage *>(msgl) != nullptr) {
sys::Bus::SendUnicast(std::make_shared<sevm::SIMMessage>(), targetApplication, this);
}
else if (msgl->messageType == MessageType::EVMGetBoard) {
using namespace bsp;
auto msg = std::make_shared<sevm::EVMBoardResponseMessage>(true);
auto board = magnetometer::GetBoard();
msg->board = board;
LOG_INFO("Board discovered: %s", c_str(board));
return msg;
}
else if (msgl->messageType == MessageType::EVMModemStatus) {
auto msg = dynamic_cast<sevm::StatusStateMessage *>(msgl);
if (msg != nullptr) {
auto message = std::make_shared<sevm::StatusStateMessage>(MessageType::EVMModemStatus);
message->state = msg->state;
sys::Bus::SendUnicast(message, "ServiceCellular", this);
}
handled = true;
}
else if (msgl->messageType == MessageType::EVMTorchStateMessage) {
auto msg = dynamic_cast<sevm::TorchStateMessage *>(msgl);
if (msg != nullptr) {
auto message = std::make_shared<sevm::TorchStateResultMessage>(msg->action);
switch (msg->action) {
case bsp::torch::Action::getState:
std::tie(message->success, message->state) = bsp::torch::getState();
message->colourTemp = bsp::torch::getColorTemp();
break;
case bsp::torch::Action::setState:
message->success = bsp::torch::turn(msg->state, msg->colourTemp);
break;
case bsp::torch::Action::toggle:
message->success = bsp::torch::toggle();
break;
}
return message;
}
}
else if (msgl->messageType == MessageType::CellularTimeUpdated) {
auto msg = dynamic_cast<CellularTimeNotificationMessage *>(msgl);
if (msg != nullptr) {
auto time = msg->getTime();
bsp::rtc_SetDateTime(&time);
LOG_INFO("RTC set by network time.");
auto notification = std::make_shared<sys::DataMessage>(MessageType::EVMTimeUpdated);
sys::Bus::SendMulticast(notification, sys::BusChannels::ServiceEvtmgrNotifications, this);
}
}
else if (msgl->messageType == MessageType::EVMRingIndicator) {
sys::SystemManager::ResumeSystem(this);
}
if (handled)
return std::make_shared<sys::ResponseMessage>();
else
return std::make_shared<sys::ResponseMessage>(sys::ReturnCodes::Unresolved);
}
// Invoked during initialization
sys::ReturnCodes EventManager::InitHandler()
{
// initialize keyboard worker
EventWorker = std::make_unique<WorkerEvent>(this);
// create queues for worker
// keyboard irq queue
sys::WorkerQueueInfo qIrq = {"qIrq", sizeof(uint8_t), 10};
// headset irq queue
sys::WorkerQueueInfo qHeadset = {"qHeadset", sizeof(uint8_t), 10};
// battery manager queue
sys::WorkerQueueInfo qBattery = {"qBattery", sizeof(uint8_t), 10};
// RTC irq queue
sys::WorkerQueueInfo qRTC = {"qRTC", sizeof(uint8_t), 20};
// test harness queue
sys::WorkerQueueInfo qHarness = {"qHarness", sizeof(uint8_t), 3};
// sim tray queue
sys::WorkerQueueInfo qSIM = {"qSIM", sizeof(uint8_t), 5};
// magnetometer queue
sys::WorkerQueueInfo qMagnetometer = {"qMagnetometer", sizeof(uint8_t), 5};
// torch driver queue
sys::WorkerQueueInfo qTorch = {"qTorch", sizeof(uint8_t), 5};
std::list<sys::WorkerQueueInfo> list;
list.push_back(qIrq);
list.push_back(qHeadset);
list.push_back(qBattery);
list.push_back(qRTC);
list.push_back(qHarness);
list.push_back(qSIM);
list.push_back(qMagnetometer);
list.push_back(qTorch);
EventWorker->init(list);
EventWorker->run();
return sys::ReturnCodes::Success;
}
sys::ReturnCodes EventManager::DeinitHandler()
{
EventWorker->close();
EventWorker.reset();
EventWorker = nullptr;
return sys::ReturnCodes::Success;
}
sys::ReturnCodes EventManager::SwitchPowerModeHandler(const sys::ServicePowerMode mode)
{
LOG_FATAL("[ServiceEvtMgr] PowerModeHandler: %s", c_str(mode));
suspended = true;
switch (mode) {
case sys::ServicePowerMode ::Active:
suspended = false;
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<sevm::EVMFocusApplication>(applicationName);
return sys::Bus::SendUnicast(msg, service::name::evt_manager, sender);
}