Skip to content
Snippets Groups Projects
Commit 72d5a0e9 authored by Shawn S's avatar Shawn S
Browse files

Updated ledflasher sample to use trait/component model

 - light schema onOff trait
 - dynamically add components based on available LEDs from lights HAL
 - custom trait _ledInfo to save lights HAL LED names

BUG:26798554
Change-Id: I4c1dd0cdb2f3479703e9082fea152a713178e65c
parent a64e4e0a
No related branches found
No related tags found
No related merge requests found
......@@ -17,7 +17,10 @@
package brillo.examples.ledflasher;
interface ILEDService {
int getLEDCount();
void setLED(int ledIndex, boolean on);
boolean getLED(int ledIndex);
boolean[] getAllLEDs();
String[] getAllLEDNames();
void setAllLEDs(boolean on);
}
......@@ -25,6 +25,10 @@ Animation::Animation(
android::sp<brillo::examples::ledflasher::ILEDService> led_service,
const base::TimeDelta& step_duration)
: led_service_{led_service}, step_duration_{step_duration} {
int led_count;
led_service_->getLEDCount(&led_count);
num_leds = static_cast<size_t>(led_count);
step_duration_ /= num_leds;
}
Animation::~Animation() {
......
......@@ -39,9 +39,9 @@ class Animation {
const std::string& type,
const base::TimeDelta& duration);
static const size_t num_leds = 4;
protected:
size_t num_leds;
virtual void DoAnimationStep() = 0;
bool GetLED(size_t index) const;
......
......@@ -20,8 +20,7 @@ AnimationMarquee::AnimationMarquee(
android::sp<brillo::examples::ledflasher::ILEDService> led_service,
const base::TimeDelta& duration,
Direction direction)
: Animation{led_service, duration / num_leds}, direction_{direction} {
}
: Animation{led_service, duration}, direction_{direction} {}
void AnimationMarquee::DoAnimationStep() {
SetAllLEDs(false);
......
{
"_ledflasher": {
"commands": {
"set": {
"minimalRole": "user",
"parameters": {
"led": {
"type": "integer",
"minimum": 1,
"maximum": 4
},
"on": { "type": "boolean" }
}
},
"toggle": {
"minimalRole": "user",
"parameters": {
"led": {
"type": "integer",
"minimum": 1,
"maximum": 4
}
}
},
"animate": {
"minimalRole": "user",
"parameters": {
......@@ -41,10 +20,34 @@
"status": {
"type": "string",
"enum": [ "idle", "animating" ]
},
"leds": {
"type": "array",
"items": { "type": "boolean" }
}
}
},
"onOff": {
"commands": {
"setConfig": {
"minimalRole": "user",
"parameters": {
"state": {
"type": "string",
"enum": [ "on", "off" ]
}
}
}
},
"state": {
"state": {
"isRequired": true,
"type": "string",
"enum": [ "on", "off" ]
}
}
},
"_ledInfo": {
"state": {
"name": {
"isRequired": true,
"type": "string"
}
}
}
......
......@@ -31,11 +31,16 @@
#include "binder_constants.h"
#include "brillo/examples/ledflasher/ILEDService.h"
using android::String16;
namespace {
const char kWeaveComponent[] = "ledflasher";
const char kWeaveTrait[] = "_ledflasher";
const char kLedFlasherComponent[] = "ledflasher";
const char kLedFlasherTrait[] = "_ledflasher";
const char kBaseComponent[] = "base";
const char kBaseTrait[] = "base";
const char kLedComponentPrefix[] = "led";
const char kOnOffTrait[] = "onOff";
const char kLedInfoTrait[] = "_ledInfo";
} // anonymous namespace
using brillo::examples::ledflasher::ILEDService;
......@@ -52,10 +57,10 @@ class Daemon final : public brillo::Daemon {
void ConnectToLEDService();
void OnLEDServiceDisconnected();
void OnPairingInfoChanged(const weaved::Service::PairingInfo* pairing_info);
void CreateLedComponentsIfNeeded();
// Particular command handlers for various commands.
void OnSet(std::unique_ptr<weaved::Command> command);
void OnToggle(std::unique_ptr<weaved::Command> command);
void OnSetConfig(size_t led_index, std::unique_ptr<weaved::Command> command);
void OnAnimate(std::unique_ptr<weaved::Command> command);
void OnIdentify(std::unique_ptr<weaved::Command> command);
......@@ -80,6 +85,8 @@ class Daemon final : public brillo::Daemon {
brillo::BinderWatcher binder_watcher_;
std::unique_ptr<weaved::Service::Subscription> weave_service_subscription_;
bool led_components_added_{false};
base::WeakPtrFactory<Daemon> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(Daemon);
};
......@@ -111,15 +118,12 @@ void Daemon::OnWeaveServiceConnected(
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->AddComponent(
kLedFlasherComponent, {kLedFlasherTrait}, nullptr);
weave_service->AddCommandHandler(
kWeaveComponent, kWeaveTrait, "toggle",
base::Bind(&Daemon::OnToggle, weak_ptr_factory_.GetWeakPtr()));
weave_service->AddCommandHandler(
kWeaveComponent, kWeaveTrait, "animate",
kLedFlasherComponent,
kLedFlasherTrait,
"animate",
base::Bind(&Daemon::OnAnimate, weak_ptr_factory_.GetWeakPtr()));
weave_service->AddCommandHandler(
kBaseComponent, kBaseTrait, "identify",
......@@ -129,6 +133,8 @@ void Daemon::OnWeaveServiceConnected(
base::Bind(&Daemon::OnPairingInfoChanged,
weak_ptr_factory_.GetWeakPtr()));
led_components_added_ = false;
CreateLedComponentsIfNeeded();
UpdateDeviceState();
}
......@@ -147,61 +153,92 @@ void Daemon::ConnectToLEDService() {
base::Bind(&Daemon::OnLEDServiceDisconnected,
weak_ptr_factory_.GetWeakPtr()));
led_service_ = android::interface_cast<ILEDService>(binder);
CreateLedComponentsIfNeeded();
UpdateDeviceState();
}
void Daemon::CreateLedComponentsIfNeeded() {
if (led_components_added_ || !led_service_.get())
return;
auto weave_service = weave_service_.lock();
if (!weave_service)
return;
std::vector<bool> leds;
std::vector<String16> ledNames;
if (!led_service_->getAllLEDs(&leds).isOk())
return;
if (!led_service_->getAllLEDNames(&ledNames).isOk())
return;
for (size_t led_index = 0; led_index < leds.size(); led_index++) {
std::string led_name = android::String8{ledNames[led_index]}.string();
std::string component_name =
kLedComponentPrefix + std::to_string(led_index + 1);
if (weave_service->AddComponent(
component_name, {kOnOffTrait, kLedInfoTrait}, nullptr)) {
weave_service->AddCommandHandler(
component_name,
kOnOffTrait,
"setConfig",
base::Bind(
&Daemon::OnSetConfig, weak_ptr_factory_.GetWeakPtr(), led_index));
weave_service->SetStateProperty(
component_name,
kOnOffTrait,
"state",
*brillo::ToValue(leds[led_index] ? "on" : "off"),
nullptr);
weave_service->SetStateProperty(component_name,
kLedInfoTrait,
"name",
*brillo::ToValue(led_name),
nullptr);
}
}
led_components_added_ = true;
}
void Daemon::OnLEDServiceDisconnected() {
animation_.reset();
led_service_ = nullptr;
ConnectToLEDService();
}
void Daemon::OnSet(std::unique_ptr<weaved::Command> command) {
void Daemon::OnSetConfig(size_t led_index,
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);
auto state = command->GetParameter<std::string>("state");
bool on = (state == "on");
android::binder::Status status = led_service_->setLED(led_index, 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;
if (animation_) {
animation_.reset();
status_ = "idle";
UpdateDeviceState();
}
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;
auto weave_service = weave_service_.lock();
if (weave_service) {
std::string component_name =
kLedComponentPrefix + std::to_string(led_index + 1);
weave_service->SetStateProperty(component_name,
kOnOffTrait,
"state",
*brillo::ToValue(on ? "on" : "off"),
nullptr);
}
animation_.reset();
status_ = "idle";
UpdateDeviceState();
command->Complete({}, nullptr);
}
......@@ -263,21 +300,15 @@ void Daemon::StopAnimation() {
}
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;
base::DictionaryValue state_change;
state_change.SetString("_ledflasher.status", status_);
state_change.Set("_ledflasher.leds", brillo::ToValue(leds).release());
weave_service->SetStateProperties(kWeaveComponent, state_change, nullptr);
weave_service->SetStateProperty(kLedFlasherComponent,
kLedFlasherTrait,
"status",
*brillo::ToValue(status_),
nullptr);
}
int main(int argc, char* argv[]) {
......
......@@ -29,8 +29,15 @@
#include "brillo/examples/ledflasher/BnLEDService.h"
#include "ledstatus.h"
using android::String16;
class LEDService : public brillo::examples::ledflasher::BnLEDService {
public:
android::binder::Status getLEDCount(int32_t* count) override {
*count = leds_.GetLedCount();
return android::binder::Status::ok();
}
android::binder::Status setLED(int32_t ledIndex, bool on) override {
leds_.SetLedStatus(ledIndex, on);
return android::binder::Status::ok();
......@@ -46,6 +53,19 @@ class LEDService : public brillo::examples::ledflasher::BnLEDService {
return android::binder::Status::ok();
}
android::binder::Status getAllLEDNames(std::vector<String16>* leds) override {
std::vector<std::string> ledNames = leds_.GetNames();
for (const std::string& name : ledNames) {
leds->push_back(String16{name.c_str()});
}
return android::binder::Status::ok();
}
android::binder::Status setAllLEDs(bool on) override {
leds_.SetAllLeds(on);
return android::binder::Status::ok();
}
private:
LedStatus leds_;
};
......
......@@ -30,7 +30,6 @@
namespace {
brillo::StreamPtr GetLEDDataStream(size_t index, bool write) {
CHECK(index < LedStatus::num_leds);
std::string led_path;
if( index == 3 ) {
led_path = "/sys/class/leds/boot/brightness";
......@@ -48,7 +47,7 @@ brillo::StreamPtr GetLEDDataStream(size_t index, bool write) {
} // anonymous namespace
LedStatus::LedStatus() {
// Try to open the lights hal.
// Try to open the lights HAL.
int ret = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, &lights_hal_);
if (ret) {
LOG(ERROR) << "Failed to load the lights HAL.";
......@@ -57,14 +56,12 @@ LedStatus::LedStatus() {
CHECK(lights_hal_);
LOG(INFO) << "Loaded lights HAL.";
// If we can open the hal, then we map each number from 1 - 4 to one of the
// leds available on the board. Note, multiple numbers could be mapped to the
// same led.
// If we can open the HAL, then we map each number to one of the LEDs
// available on the board.
const std::initializer_list<const char*> kLogicalLights = {
LIGHT_ID_BACKLIGHT, LIGHT_ID_KEYBOARD, LIGHT_ID_BUTTONS, LIGHT_ID_BATTERY,
LIGHT_ID_NOTIFICATIONS, LIGHT_ID_ATTENTION, LIGHT_ID_BLUETOOTH,
LIGHT_ID_WIFI};
size_t led_index = 0;
for (const char* light_name : kLogicalLights) {
light_device_t* light_device = nullptr;
ret = lights_hal_->methods->open(
......@@ -74,41 +71,39 @@ LedStatus::LedStatus() {
if (ret || !light_device) {
continue;
}
hal_led_map_.emplace(led_index, light_name);
led_index++;
if (led_index == num_leds) {
// We have already mapped all num_leds LEDs.
break;
}
hal_leds_.push_back(light_name);
hal_led_status_.push_back(false);
}
// If the size of the map is zero, then the lights hal doesn't have any valid
// If the size of the map is zero, then the lights HAL doesn't have any valid
// leds.
if (hal_led_map_.empty()) {
LOG(ERROR) << "Unable to open any light devices using the hal.";
if (hal_leds_.empty()) {
LOG(INFO) << "Unable to open any light devices using the HAL.";
lights_hal_ = nullptr;
return;
}
}
// If not all 4 numbers have been mapped, then we map them to the first led
// mapped.
for (size_t i = hal_led_map_.size(); i < num_leds; i++) {
hal_led_map_.emplace(i, hal_led_map_[0]);
}
hal_led_status_.resize(num_leds);
size_t LedStatus::GetLedCount() const {
return lights_hal_ ? hal_leds_.size() : 1;
}
std::vector<bool> LedStatus::GetStatus() const {
if (lights_hal_)
return hal_led_status_;
std::vector<bool> leds(num_leds);
for (size_t index = 0; index < num_leds; index++)
std::vector<bool> leds(GetLedCount());
for (size_t index = 0; index < GetLedCount(); index++)
leds[index] = IsLedOn(index);
return leds;
}
std::vector<std::string> LedStatus::GetNames() const {
return lights_hal_ ? hal_leds_ : std::vector<std::string>(GetLedCount());
}
bool LedStatus::IsLedOn(size_t index) const {
CHECK(index < GetLedCount());
if (lights_hal_)
return hal_led_status_[index];
......@@ -132,6 +127,7 @@ bool LedStatus::IsLedOn(size_t index) const {
}
void LedStatus::SetLedStatus(size_t index, bool on) {
CHECK(index < GetLedCount());
if (lights_hal_) {
light_state_t state = {};
state.color = on;
......@@ -141,23 +137,24 @@ void LedStatus::SetLedStatus(size_t index, bool on) {
state.brightnessMode = BRIGHTNESS_MODE_USER;
light_device_t* light_device = nullptr;
int rc = lights_hal_->methods->open(
lights_hal_, hal_led_map_[index].c_str(),
lights_hal_,
hal_leds_[index].c_str(),
reinterpret_cast<hw_device_t**>(&light_device));
if (rc) {
LOG(ERROR) << "Unable to open " << hal_led_map_[index];
LOG(ERROR) << "Unable to open " << hal_leds_[index];
return;
}
CHECK(light_device);
rc = light_device->set_light(light_device, &state);
if (rc) {
LOG(ERROR) << "Unable to set " << hal_led_map_[index];
LOG(ERROR) << "Unable to set " << hal_leds_[index];
return;
}
hal_led_status_[index] = on;
light_device->common.close(
reinterpret_cast<hw_device_t*>(light_device));
if (rc) {
LOG(ERROR) << "Unable to close " << hal_led_map_[index];
LOG(ERROR) << "Unable to close " << hal_leds_[index];
return;
}
return;
......@@ -170,3 +167,8 @@ void LedStatus::SetLedStatus(size_t index, bool on) {
std::string brightness = on ? "255" : "0";
stream->WriteAllBlocking(brightness.data(), brightness.size(), nullptr);
}
void LedStatus::SetAllLeds(bool on) {
for (size_t i = 0; i < GetLedCount(); i++)
SetLedStatus(i, on);
}
......@@ -17,7 +17,7 @@
#ifndef LEDFLASHER_SRC_LEDSERVICE_LEDSTATUS_H_
#define LEDFLASHER_SRC_LEDSERVICE_LEDSTATUS_H_
#include <map>
#include <string>
#include <vector>
#include <base/macros.h>
......@@ -28,17 +28,17 @@ class LedStatus final {
LedStatus();
std::vector<bool> GetStatus() const;
std::vector<std::string> GetNames() const;
bool IsLedOn(size_t index) const;
void SetLedStatus(size_t index, bool on);
static const size_t num_leds = 4;
void SetAllLeds(bool on);
size_t GetLedCount() const;
private:
const hw_module_t* lights_hal_{nullptr};
// Maps the lights available to the hal to numbers 1 - 4. It is possible for
// multiple numbers to be mapped to the same led on the board.
std::map<size_t, std::string> hal_led_map_;
// Since the hal doesn't have a way to track the led status, we maintain that
// Contains the names of LEDs in the HAL for each of supported LEDs.
std::vector<std::string> hal_leds_;
// Since the HAL doesn't have a way to track the led status, we maintain that
// info here.
std::vector<bool> hal_led_status_;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment