// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "service-bluetooth/ServiceBluetooth.hpp" #include "service-bluetooth/BluetoothMessage.hpp" #include #include #include #include #include #include #include "service-bluetooth/messages/AudioVolume.hpp" #include "service-bluetooth/messages/Connect.hpp" #include #include "service-bluetooth/messages/Disconnect.hpp" #include "service-bluetooth/messages/Status.hpp" #include "service-bluetooth/messages/SetStatus.hpp" #include "service-bluetooth/messages/BondedDevices.hpp" #include "service-bluetooth/messages/Unpair.hpp" #include "service-bluetooth/messages/SetDeviceName.hpp" #include "service-bluetooth/BluetoothDevicesModel.hpp" #include "service-bluetooth/messages/BluetoothModeChanged.hpp" #include "service-bluetooth/messages/RequestStatusIndicatorData.hpp" #include "system/messages/SentinelRegistrationMessage.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr auto BluetoothServiceStackDepth = 1024 * 3; inline constexpr auto connectionTimeout = std::chrono::minutes{10}; inline constexpr auto btRestartDelay = std::chrono::milliseconds{500}; } // namespace ServiceBluetooth::ServiceBluetooth() : sys::Service(service::name::bluetooth, "", BluetoothServiceStackDepth) { LOG_INFO("[ServiceBluetooth] Initializing"); bus.channels.push_back(sys::BusChannel::ServiceCellularNotifications); } ServiceBluetooth::~ServiceBluetooth() { LOG_INFO("[ServiceBluetooth] Cleaning resources"); } sys::ReturnCodes ServiceBluetooth::InitHandler() { auto settings = std::make_unique(); settings->init(service::ServiceProxy(shared_from_this())); settingsHolder = std::make_shared(std::move(settings)); bluetoothDevicesModel = std::make_shared(this); bluetooth::KeyStorage::settings = settingsHolder; bus.channels.push_back(sys::BusChannel::BluetoothNotifications); bus.channels.push_back(sys::BusChannel::ServiceCellularNotifications); worker = std::make_unique(this); worker->run(); cpuSentinel = std::make_shared(service::name::bluetooth, this); auto sentinelRegistrationMsg = std::make_shared(cpuSentinel); bus.sendUnicast(sentinelRegistrationMsg, service::name::system_manager); connectionTimeoutTimer = sys::TimerFactory::createSingleShotTimer(this, "btTimeoutTimer", connectionTimeout, [this](sys::Timer &_) { LOG_INFO("Turning off Bluetooth due to inactivity timeout"); handleTurnOff(); }); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); settingsHolder->onStateChange = [this]() { auto initialState = std::visit(bluetooth::IntVisitor(), settingsHolder->getValue(bluetooth::Settings::State)); if (static_cast(initialState) == BluetoothStatus::State::On) { settingsHolder->setValue(bluetooth::Settings::State, static_cast(BluetoothStatus::State::Off)); } }; return sys::ReturnCodes::Success; } sys::ReturnCodes ServiceBluetooth::DeinitHandler() { settingsHolder->deinit(); worker->closeWorker(); worker.reset(); return sys::ReturnCodes::Success; } void ServiceBluetooth::ProcessCloseReason(sys::CloseReason closeReason) { sendWorkerCommand(std::make_unique()); sendWorkerCommand(std::make_unique()); } sys::MessagePointer ServiceBluetooth::DataReceivedHandler([[maybe_unused]] sys::DataMessage *msg, [[maybe_unused]] sys::ResponseMessage *resp) { return std::make_shared(); } sys::ReturnCodes ServiceBluetooth::SwitchPowerModeHandler(const sys::ServicePowerMode mode) { LOG_ERROR("TODO"); return sys::ReturnCodes::Success; } auto ServiceBluetooth::handle(BluetoothAudioStartMessage *msg) -> std::shared_ptr { worker->setAudioDevice(msg->getAudioDevice()); return std::make_shared(); } auto ServiceBluetooth::handle([[maybe_unused]] message::bluetooth::RequestBondedDevices *msg) -> std::shared_ptr { auto bondedDevicesStr = std::visit(bluetooth::StringVisitor(), this->settingsHolder->getValue(bluetooth::Settings::BondedDevices)); bluetoothDevicesModel->mergeDevicesList(SettingsSerializer::fromString(bondedDevicesStr)); bus.sendMulticast( std::make_shared(bluetoothDevicesModel->getDevices(), ""), sys::BusChannel::BluetoothNotifications); return sys::MessageNone{}; } auto ServiceBluetooth::handle([[maybe_unused]] message::bluetooth::RequestStatus *msg) -> std::shared_ptr { auto state = std::visit(bluetooth::IntVisitor(), settingsHolder->getValue(bluetooth::Settings::State)); auto visibility = std::visit(bluetooth::BoolVisitor(), settingsHolder->getValue(bluetooth::Settings::Visibility)); BluetoothStatus status{static_cast(state), status.visibility = visibility}; bus.sendMulticast(std::make_shared(status), sys::BusChannel::BluetoothNotifications); return sys::MessageNone{}; } auto ServiceBluetooth::handle(message::bluetooth::SetStatus *msg) -> std::shared_ptr { auto newBtStatus = msg->getStatus(); switch (newBtStatus.state) { case BluetoothStatus::State::On: { handleTurnOn(); auto bondedDevicesStr = std::visit(bluetooth::StringVisitor(), this->settingsHolder->getValue(bluetooth::Settings::BondedDevices)); bluetoothDevicesModel->mergeDevicesList(SettingsSerializer::fromString(bondedDevicesStr)); bluetoothDevicesModel->syncDevicesWithApp(); startTimeoutTimer(); } break; case BluetoothStatus::State::Off: stopTimeoutTimer(); handleTurnOff(); break; default: break; } if (newBtStatus.visibility) { sendWorkerCommand(std::make_unique()); } else { sendWorkerCommand(std::make_unique()); } return sys::MessageNone{}; } auto ServiceBluetooth::handle(BluetoothPairMessage *msg) -> std::shared_ptr { auto device = msg->getDevice(); bluetoothDevicesModel->removeDevice(device); sendWorkerCommand(std::make_unique(device)); device.deviceState = DeviceState::Pairing; bluetoothDevicesModel->insertDevice(device); bluetoothDevicesModel->syncDevicesWithApp(); return sys::MessageNone{}; } auto ServiceBluetooth::handle(BluetoothPairResultMessage *msg) -> std::shared_ptr { auto device = msg->getDevice(); if (msg->isSucceed()) { bluetoothDevicesModel->mergeDevicesList(device); bluetoothDevicesModel->setInternalDeviceState(device, DeviceState::Paired); } else { bluetoothDevicesModel->removeDevice(device); } bluetoothDevicesModel->syncDevicesWithApp(); /// TODO error code handing added in next PRs bus.sendMulticast(std::make_shared(msg->getDevice(), msg->isSucceed()), sys::BusChannel::BluetoothNotifications); return sys::MessageNone{}; } void ServiceBluetooth::sendWorkerCommand(std::unique_ptr command) { if (workerQueue != nullptr) { workerQueue->push(bluetooth::Command{std::move(command)}); } } auto ServiceBluetooth::handle(message::bluetooth::Unpair *msg) -> std::shared_ptr { sendWorkerCommand(std::make_unique(msg->getDevice())); bluetoothDevicesModel->removeDevice(msg->getDevice()); return sys::MessageNone{}; } auto ServiceBluetooth::handle([[maybe_unused]] message::bluetooth::RequestDeviceName *msg) -> std::shared_ptr { auto deviceNameString = std::visit(bluetooth::StringVisitor(), this->settingsHolder->getValue(bluetooth::Settings::DeviceName)); bus.sendMulticast(std::make_shared(std::move(deviceNameString)), sys::BusChannel::BluetoothNotifications); return sys::MessageNone{}; } auto ServiceBluetooth::handle(message::bluetooth::SetDeviceName *msg) -> std::shared_ptr { auto newName = msg->getName(); bluetooth::set_name(newName); settingsHolder->setValue(bluetooth::Settings::DeviceName, newName); sendWorkerCommand(std::make_unique()); btRestartTimer = sys::TimerFactory::createSingleShotTimer(this, "btRestartTimer", btRestartDelay, [this](sys::Timer &_) { sendWorkerCommand(std::make_unique()); }); btRestartTimer.start(); return sys::MessageNone{}; } auto ServiceBluetooth::handle(message::bluetooth::Connect *msg) -> std::shared_ptr { auto device = msg->getDevice(); sendWorkerCommand(std::make_unique(device)); bluetoothDevicesModel->setInternalDeviceState(device, DeviceState::Connecting); bluetoothDevicesModel->syncDevicesWithApp(); return sys::MessageNone{}; } auto convertDeviceStateIntoBluetoothState(const DeviceState &state) -> sys::bluetooth::BluetoothMode { switch (state) { case DeviceState::ConnectedVoice: return sys::bluetooth::BluetoothMode::ConnectedVoice; case DeviceState::ConnectedAudio: return sys::bluetooth::BluetoothMode::ConnectedAudio; case DeviceState::ConnectedBoth: return sys::bluetooth::BluetoothMode::ConnectedBoth; default: return sys::bluetooth::BluetoothMode::Enabled; } } auto ServiceBluetooth::handle(message::bluetooth::ConnectResult *msg) -> std::shared_ptr { if (msg->getResult() == message::bluetooth::ConnectResult::Result::Success) { auto device = msg->getDevice(); bluetoothDevicesModel->mergeInternalDeviceState(device); settingsHolder->setValue(bluetooth::Settings::ConnectedDevice, bd_addr_to_str(device.address)); auto deviceState = bluetoothDevicesModel->getDeviceByAddress(device.address)->get().deviceState; bus.sendMulticast( std::make_shared(convertDeviceStateIntoBluetoothState(deviceState)), sys::BusChannel::BluetoothModeChanges); stopTimeoutTimer(); } for (auto &device : bluetoothDevicesModel->getDevices()) { if (device.deviceState == DeviceState::Connecting) { device.deviceState = DeviceState::Paired; } } bluetoothDevicesModel->syncDevicesWithApp(); bus.sendMulticast(std::make_shared(*msg), sys::BusChannel::BluetoothNotifications); return sys::MessageNone{}; } auto ServiceBluetooth::handle([[maybe_unused]] message::bluetooth::Disconnect *msg) -> std::shared_ptr { sendWorkerCommand(std::make_unique()); return sys::MessageNone{}; } auto ServiceBluetooth::handle(message::bluetooth::DisconnectResult *msg) -> std::shared_ptr { auto deviceAddr = std::visit(bluetooth::StringVisitor(), this->settingsHolder->getValue(bluetooth::Settings::ConnectedDevice)); auto device = bluetoothDevicesModel->getDeviceByAddress(deviceAddr); if (device.has_value()) { device.value().get().deviceState = DeviceState::Paired; } bluetoothDevicesModel->syncDevicesWithApp(); settingsHolder->setValue(bluetooth::Settings::ConnectedDevice, std::string()); if (auto btOn = std::visit(bluetooth::BoolVisitor(), settingsHolder->getValue(bluetooth::Settings::State)); btOn) { bus.sendMulticast( std::make_shared(sys::bluetooth::BluetoothMode::Enabled), sys::BusChannel::BluetoothModeChanges); startTimeoutTimer(); } bus.sendMulticast(std::make_shared(msg->getDevice()), sys::BusChannel::BluetoothNotifications); return sys::MessageNone{}; } auto ServiceBluetooth::handle(message::bluetooth::ResponseAuthenticatePin *msg) -> std::shared_ptr { /// TODO to be added in next PRs auto pin = msg->getPin(); bluetooth::GAP::respondPinCode(pin, msg->getDevice()); return sys::MessageNone{}; } auto ServiceBluetooth::handle(message::bluetooth::ResponseAuthenticatePasskey *msg) -> std::shared_ptr { auto passKey = msg->getPasskey(); bluetooth::GAP::respondPinCode(passKey, msg->getDevice()); return sys::MessageNone{}; } auto ServiceBluetooth::handle(message::bluetooth::ResponseAuthenticatePairCancel *msg) -> std::shared_ptr { auto accepted = msg->getPairApproved(); bluetooth::GAP::finishCodeComparison(accepted, msg->getDevice()); return sys::MessageNone{}; } auto ServiceBluetooth::handle(BluetoothMessage *msg) -> std::shared_ptr { LOG_INFO("Bluetooth request!"); switch (msg->req) { case BluetoothMessage::Scan: sendWorkerCommand(std::make_unique()); break; case BluetoothMessage::StopScan: sendWorkerCommand(std::make_unique()); break; case BluetoothMessage::getDevicesAvailable: sendWorkerCommand(std::make_unique()); break; case BluetoothMessage::Visible: { auto visibility = not std::visit(bluetooth::BoolVisitor(), settingsHolder->getValue(bluetooth::Settings::Visibility)); if (visibility) { sendWorkerCommand(std::make_unique()); } else { sendWorkerCommand(std::make_unique()); } } break; case BluetoothMessage::Play: sendWorkerCommand(std::make_unique()); break; case BluetoothMessage::Disconnect: sendWorkerCommand(std::make_unique()); break; case BluetoothMessage::Stop: sendWorkerCommand(std::make_unique()); break; default: break; } return std::make_shared(); } auto ServiceBluetooth::handle(BluetoothAddrMessage *msg) -> std::shared_ptr { sendWorkerCommand(std::make_unique(msg->device)); return std::make_shared(); } auto ServiceBluetooth::handle(sdesktop::developerMode::DeveloperModeRequest *msg) -> std::shared_ptr { if (typeid(*msg->event) == typeid(sdesktop::bluetooth::GetAvailableDevicesEvent)) { sendWorkerCommand(std::make_unique()); } return sys::MessageNone{}; } auto ServiceBluetooth::handle(message::bluetooth::A2DPVolume *msg) -> std::shared_ptr { using namespace message::bluetooth; AudioServiceAPI::BluetoothA2DPVolumeChanged(this, msg->getVolume()); return sys::MessageNone{}; } auto ServiceBluetooth::handle(message::bluetooth::HSPVolume *msg) -> std::shared_ptr { using namespace message::bluetooth; AudioServiceAPI::BluetoothHSPVolumeChanged(this, msg->getVolume()); return sys::MessageNone{}; } auto ServiceBluetooth::handle(message::bluetooth::HFPVolume *msg) -> std::shared_ptr { using namespace message::bluetooth; AudioServiceAPI::BluetoothHFPVolumeChanged(this, msg->getVolume()); return sys::MessageNone{}; } auto ServiceBluetooth::handle(cellular::SignalStrengthUpdateNotification *msg) -> std::shared_ptr { auto signalStrength = Store::GSM::get()->getSignalStrength(); LOG_DEBUG("Bluetooth: RSSI %d/5", static_cast(signalStrength.rssiBar)); sendWorkerCommand(std::make_unique(signalStrength)); return std::make_shared(); } auto ServiceBluetooth::handle(cellular::CurrentOperatorNameNotification *msg) -> std::shared_ptr { auto opName = msg->getCurrentOperatorName(); LOG_DEBUG("Bluetooth: Operator name: %s", opName.c_str()); sendWorkerCommand(std::make_unique(opName)); return std::make_shared(); } void ServiceBluetooth::startTimeoutTimer() { if (connectionTimeoutTimer.isValid()) { connectionTimeoutTimer.start(); } } void ServiceBluetooth::stopTimeoutTimer() { if (connectionTimeoutTimer.isValid()) { connectionTimeoutTimer.stop(); } } void ServiceBluetooth::handleTurnOff() { sendWorkerCommand(std::make_unique()); // NOTE: This should be in bluetooth state machine cpuSentinel->ReleaseMinimumFrequency(); bus.sendMulticast(std::make_shared(sys::bluetooth::BluetoothMode::Disabled), sys::BusChannel::BluetoothModeChanges); } void ServiceBluetooth::handleTurnOn() { cpuSentinel->HoldMinimumFrequency(bsp::CpuFrequencyMHz::Level_3); sendWorkerCommand(std::make_unique()); bus.sendMulticast(std::make_shared(sys::bluetooth::BluetoothMode::Enabled), sys::BusChannel::BluetoothModeChanges); } auto ServiceBluetooth::handle(message::bluetooth::RequestStatusIndicatorData *msg) -> std::shared_ptr { bus.sendUnicast(std::make_shared(), cellular::service::name); // just to execute proper handle method and sending it back to worker bus.sendUnicast(std::make_shared(), service::name::bluetooth); bus.sendUnicast(std::make_shared(), service::name::bluetooth); bus.sendUnicast(std::make_shared(), service::name::bluetooth); return sys::MessageNone{}; } auto ServiceBluetooth::handle(sevm::BatteryStatusChangeMessage *msg) -> std::shared_ptr { auto batteryLevel = Store::Battery::get().level; LOG_DEBUG("Bluetooth: Battery level %d", batteryLevel); sendWorkerCommand(std::make_unique(batteryLevel)); return sys::MessageNone{}; } auto ServiceBluetooth::handle(cellular::NetworkStatusUpdateNotification *msg) -> std::shared_ptr { auto status = Store::GSM::get()->getNetwork().status; LOG_DEBUG("Bluetooth: Network status %s", magic_enum::enum_name(status).data()); sendWorkerCommand(std::make_unique(status)); return sys::MessageNone{}; } auto ServiceBluetooth::handle(cellular::CallerIdMessage *msg) -> std::shared_ptr { auto number = msg->number; auto btOn = std::visit(bluetooth::BoolVisitor(), settingsHolder->getValue(bluetooth::Settings::State)); LOG_DEBUG("Received caller ID msg! "); if (btOn) { LOG_DEBUG("Sending to profile!"); sendWorkerCommand(std::make_unique(number)); } return sys::MessageNone{}; } auto ServiceBluetooth::handle(cellular::IncomingCallMessage *msg) -> std::shared_ptr { sendWorkerCommand(std::make_unique()); return sys::MessageNone{}; } auto ServiceBluetooth::handle(cellular::CallStartedNotification *msg) -> std::shared_ptr { if (!msg->isCallIncoming()) { auto evt = std::make_unique(msg->getNumber()); sendWorkerCommand(std::move(evt)); } return sys::MessageNone{}; } auto ServiceBluetooth::handle(cellular::CallOutgoingAccepted *msg) -> std::shared_ptr { LOG_DEBUG("Outgoing call accepted"); sendWorkerCommand(std::make_unique()); return sys::MessageNone{}; } auto ServiceBluetooth::handle(cellular::CallActiveNotification *msg) -> std::shared_ptr { LOG_DEBUG("Incoming call accepted"); sendWorkerCommand(std::make_unique()); return sys::MessageNone{}; } auto ServiceBluetooth::handle(cellular::CallEndedNotification *msg) -> std::shared_ptr { sendWorkerCommand(std::make_unique()); return sys::MessageNone{}; } auto ServiceBluetooth::handle(cellular::CallMissedNotification *msg) -> std::shared_ptr { sendWorkerCommand(std::make_unique()); return sys::MessageNone{}; }