| /* |
| * 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 <string> |
| #include <sysexits.h> |
| |
| #include <base/bind.h> |
| #include <base/command_line.h> |
| #include <base/macros.h> |
| #include <base/memory/weak_ptr.h> |
| #include <binderwrapper/binder_wrapper.h> |
| #include <brillo/binder_watcher.h> |
| #include <brillo/daemons/daemon.h> |
| #include <brillo/syslog_logging.h> |
| #include <libweaved/service.h> |
| |
| #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<weaved::Service>& service); |
| void ConnectToLEDService(); |
| void OnLEDServiceDisconnected(); |
| |
| // Particular command handlers for various commands. |
| void OnSet(std::unique_ptr<weaved::Command> command); |
| void OnToggle(std::unique_ptr<weaved::Command> command); |
| void OnAnimate(std::unique_ptr<weaved::Command> command); |
| |
| // Helper methods to propagate device state changes to Buffet and hence to |
| // the cloud server or local clients. |
| void UpdateDeviceState(); |
| |
| std::weak_ptr<weaved::Service> weave_service_; |
| |
| // Device state variables. |
| std::string status_{"idle"}; |
| |
| // LED service interface. |
| android::sp<ILEDService> led_service_; |
| |
| // Current animation; |
| std::unique_ptr<Animation> animation_; |
| |
| brillo::BinderWatcher binder_watcher_; |
| std::unique_ptr<weaved::Service::Subscription> weave_service_subscription_; |
| |
| base::WeakPtrFactory<Daemon> 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<weaved::Service>& 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<ILEDService>(binder); |
| UpdateDeviceState(); |
| } |
| |
| void Daemon::OnLEDServiceDisconnected() { |
| animation_.reset(); |
| led_service_ = nullptr; |
| ConnectToLEDService(); |
| } |
| |
| void Daemon::OnSet(std::unique_ptr<weaved::Command> command) { |
| if (!led_service_.get()) { |
| command->Abort("_system_error", "ledservice unavailable", nullptr); |
| return; |
| } |
| |
| int index = command->GetParameter<int>("led"); |
| if(index < 1 || index > 4) { |
| command->Abort("_invalid_parameter", "Invalid parameter value", nullptr); |
| return; |
| } |
| bool on = command->GetParameter<bool>("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<weaved::Command> command) { |
| if (!led_service_.get()) { |
| command->Abort("_system_error", "ledservice unavailable", nullptr); |
| return; |
| } |
| |
| int index = command->GetParameter<int>("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<weaved::Command> command) { |
| if (!led_service_.get()) { |
| command->Abort("_system_error", "ledservice unavailable", nullptr); |
| return; |
| } |
| |
| double duration = command->GetParameter<double>("duration"); |
| if(duration <= 0.0) { |
| command->Abort("_invalid_parameter", "Invalid parameter value", nullptr); |
| return; |
| } |
| std::string type = command->GetParameter<std::string>("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<bool> 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(); |
| } |