/* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "animation.h" #include "binder_constants.h" #include "brillo/examples/ledflasher/ILEDService.h" namespace { const char kWeaveComponent[] = "ledflasher"; const char kWeaveTrait[] = "_ledflasher"; } // anonymous namespace using brillo::examples::ledflasher::ILEDService; class Daemon final : public brillo::Daemon { public: Daemon() = default; protected: int OnInit() override; private: void OnWeaveServiceConnected(const std::weak_ptr& service); void ConnectToLEDService(); void OnLEDServiceDisconnected(); // Particular command handlers for various commands. void OnSet(std::unique_ptr command); void OnToggle(std::unique_ptr command); void OnAnimate(std::unique_ptr command); // Helper methods to propagate device state changes to Buffet and hence to // the cloud server or local clients. void UpdateDeviceState(); std::weak_ptr weave_service_; // Device state variables. std::string status_{"idle"}; // LED service interface. android::sp led_service_; // Current animation; std::unique_ptr animation_; brillo::BinderWatcher binder_watcher_; std::unique_ptr weave_service_subscription_; base::WeakPtrFactory weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(Daemon); }; int Daemon::OnInit() { int return_code = brillo::Daemon::OnInit(); if (return_code != EX_OK) return return_code; android::BinderWrapper::Create(); if (!binder_watcher_.Init()) return EX_OSERR; weave_service_subscription_ = weaved::Service::Connect( brillo::MessageLoop::current(), base::Bind(&Daemon::OnWeaveServiceConnected, weak_ptr_factory_.GetWeakPtr())); ConnectToLEDService(); LOG(INFO) << "Waiting for commands..."; return EX_OK; } void Daemon::OnWeaveServiceConnected( const std::weak_ptr& service) { LOG(INFO) << "Daemon::OnWeaveServiceConnected"; weave_service_ = service; auto weave_service = weave_service_.lock(); if (!weave_service) return; weave_service->AddComponent(kWeaveComponent, {kWeaveTrait}, nullptr); weave_service->AddCommandHandler( kWeaveComponent, kWeaveTrait, "set", base::Bind(&Daemon::OnSet, weak_ptr_factory_.GetWeakPtr())); weave_service->AddCommandHandler( kWeaveComponent, kWeaveTrait, "toggle", base::Bind(&Daemon::OnToggle, weak_ptr_factory_.GetWeakPtr())); weave_service->AddCommandHandler( kWeaveComponent, kWeaveTrait, "animate", base::Bind(&Daemon::OnAnimate, weak_ptr_factory_.GetWeakPtr())); UpdateDeviceState(); } void Daemon::ConnectToLEDService() { android::BinderWrapper* binder_wrapper = android::BinderWrapper::Get(); auto binder = binder_wrapper->GetService(ledservice::kBinderServiceName); if (!binder.get()) { brillo::MessageLoop::current()->PostDelayedTask( base::Bind(&Daemon::ConnectToLEDService, weak_ptr_factory_.GetWeakPtr()), base::TimeDelta::FromSeconds(1)); return; } binder_wrapper->RegisterForDeathNotifications( binder, base::Bind(&Daemon::OnLEDServiceDisconnected, weak_ptr_factory_.GetWeakPtr())); led_service_ = android::interface_cast(binder); UpdateDeviceState(); } void Daemon::OnLEDServiceDisconnected() { animation_.reset(); led_service_ = nullptr; ConnectToLEDService(); } void Daemon::OnSet(std::unique_ptr command) { if (!led_service_.get()) { command->Abort("_system_error", "ledservice unavailable", nullptr); return; } int index = command->GetParameter("led"); if(index < 1 || index > 4) { command->Abort("_invalid_parameter", "Invalid parameter value", nullptr); return; } bool on = command->GetParameter("on"); android::binder::Status status = led_service_->setLED(index - 1, on); if (!status.isOk()) { command->AbortWithCustomError(status, nullptr); return; } animation_.reset(); status_ = "idle"; UpdateDeviceState(); command->Complete({}, nullptr); } void Daemon::OnToggle(std::unique_ptr command) { if (!led_service_.get()) { command->Abort("_system_error", "ledservice unavailable", nullptr); return; } int index = command->GetParameter("led"); if(index < 1 || index > 4) { command->Abort("_invalid_parameter", "Invalid parameter value", nullptr); return; } index--; bool on = false; android::binder::Status status = led_service_->getLED(index, &on); if (status.isOk()) status = led_service_->setLED(index, !on); if(!status.isOk()) { command->AbortWithCustomError(status, nullptr); return; } animation_.reset(); status_ = "idle"; UpdateDeviceState(); command->Complete({}, nullptr); } void Daemon::OnAnimate(std::unique_ptr command) { if (!led_service_.get()) { command->Abort("_system_error", "ledservice unavailable", nullptr); return; } double duration = command->GetParameter("duration"); if(duration <= 0.0) { command->Abort("_invalid_parameter", "Invalid parameter value", nullptr); return; } std::string type = command->GetParameter("type"); animation_ = Animation::Create(led_service_, type, base::TimeDelta::FromSecondsD(duration)); if (animation_) { status_ = "animating"; animation_->Start(); } else { status_ = "idle"; } UpdateDeviceState(); command->Complete({}, nullptr); } void Daemon::UpdateDeviceState() { if (!led_service_.get()) return; std::vector leds; if (!led_service_->getAllLEDs(&leds).isOk()) return; auto weave_service = weave_service_.lock(); if (!weave_service) return; brillo::VariantDictionary state_change{ {"_ledflasher.status", status_}, {"_ledflasher.leds", leds}, }; weave_service->SetStateProperties(kWeaveComponent, state_change, nullptr); } int main(int argc, char* argv[]) { base::CommandLine::Init(argc, argv); brillo::InitLog(brillo::kLogToSyslog | brillo::kLogHeader); Daemon daemon; return daemon.Run(); }