fix(battery): Proper handling of charge animation

Closes jaagr/lemonbuddy#3
This commit is contained in:
Michael Carlberg 2016-05-26 11:35:09 +02:00
parent 925469fec1
commit 23b2cc69dd
4 changed files with 95 additions and 83 deletions

View File

@ -3,7 +3,6 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <mutex>
#include "modules/base.hpp" #include "modules/base.hpp"
#include "drawtypes/animation.hpp" #include "drawtypes/animation.hpp"
@ -13,47 +12,42 @@
namespace modules namespace modules
{ {
enum BatteryState
{
UNKNOWN = 1 << 1,
CHARGING = 1 << 2,
DISCHARGING = 1 << 4,
FULL = 1 << 8,
};
DefineModule(BatteryModule, InotifyModule) DefineModule(BatteryModule, InotifyModule)
{ {
const char *FORMAT_CHARGING = "format:charging"; public:
const char *FORMAT_DISCHARGING = "format:discharging"; static const int STATE_UNKNOWN = 1;
const char *FORMAT_FULL = "format:full"; static const int STATE_CHARGING = 2;
static const int STATE_DISCHARGING = 3;
static const int STATE_FULL = 4;
const char *TAG_ANIMATION_CHARGING = "<animation:charging>"; protected:
const char *TAG_BAR_CAPACITY = "<bar:capacity>"; static constexpr auto FORMAT_CHARGING = "format:charging";
const char *TAG_RAMP_CAPACITY = "<ramp:capacity>"; static constexpr auto FORMAT_DISCHARGING = "format:discharging";
const char *TAG_LABEL_CHARGING = "<label:charging>"; static constexpr auto FORMAT_FULL = "format:full";
const char *TAG_LABEL_DISCHARGING = "<label:discharging>";
const char *TAG_LABEL_FULL = "<label:full>";
// std::mutex ev_mtx; static constexpr auto TAG_ANIMATION_CHARGING = "<animation:charging>";
// std::condition_variable cv; static constexpr auto TAG_BAR_CAPACITY = "<bar:capacity>";
static constexpr auto TAG_RAMP_CAPACITY = "<ramp:capacity>";
static constexpr auto TAG_LABEL_CHARGING = "<label:charging>";
static constexpr auto TAG_LABEL_DISCHARGING = "<label:discharging>";
static constexpr auto TAG_LABEL_FULL = "<label:full>";
std::unique_ptr<drawtypes::Animation> animation_charging; std::unique_ptr<drawtypes::Animation> animation_charging;
std::unique_ptr<drawtypes::Ramp> ramp_capacity; std::unique_ptr<drawtypes::Ramp> ramp_capacity;
std::unique_ptr<drawtypes::Bar> bar_capacity; std::unique_ptr<drawtypes::Bar> bar_capacity;
std::unique_ptr<drawtypes::Label> label_charging; std::unique_ptr<drawtypes::Label> label_charging;
std::unique_ptr<drawtypes::Label> label_charging_tokenized; std::unique_ptr<drawtypes::Label> label_charging_tokenized;
std::unique_ptr<drawtypes::Label> label_discharging; std::unique_ptr<drawtypes::Label> label_discharging;
std::unique_ptr<drawtypes::Label> label_discharging_tokenized; std::unique_ptr<drawtypes::Label> label_discharging_tokenized;
std::unique_ptr<drawtypes::Label> label_full; std::unique_ptr<drawtypes::Label> label_full;
std::unique_ptr<drawtypes::Label> label_full_tokenized; std::unique_ptr<drawtypes::Label> label_full_tokenized;
std::string battery, adapter; std::string battery, adapter;
concurrency::Atomic<int> state; concurrency::Atomic<int> state;
// std::atomic<int> state; concurrency::Atomic<int> percentage;
std::atomic<int> percentage; int full_at;
int full_at;
void animation_thread_runner(); void animation_thread_runner();
public: public:
BatteryModule(const std::string& name); BatteryModule(const std::string& name);

View File

@ -80,6 +80,12 @@ namespace concurrency
std::lock_guard<concurrency::SpinLock> lck(this->lock); std::lock_guard<concurrency::SpinLock> lck(this->lock);
return this->value; return this->value;
} }
bool operator==(T const& b)
{
std::lock_guard<concurrency::SpinLock> lck(this->lock);
return this->value == b;
}
}; };
template<typename T> template<typename T>
@ -111,5 +117,11 @@ namespace concurrency
std::lock_guard<concurrency::SpinLock> lck(this->lock); std::lock_guard<concurrency::SpinLock> lck(this->lock);
return this->value; return this->value;
} }
bool operator==(T const& b)
{
std::lock_guard<concurrency::SpinLock> lck(this->lock);
return this->value == b;
}
}; };
} }

View File

@ -179,7 +179,7 @@ int main(int argc, char **argv)
eventloop->wait(); eventloop->wait();
} catch (Exception &e) { } catch (Exception &e) {
logger->fatal(e.what()); logger->error(e.what());
} }
eventloop->stop(); eventloop->stop();

View File

@ -11,12 +11,20 @@
using namespace modules; using namespace modules;
const int modules::BatteryModule::STATE_UNKNOWN;
const int modules::BatteryModule::STATE_CHARGING;
const int modules::BatteryModule::STATE_DISCHARGING;
const int modules::BatteryModule::STATE_FULL;
BatteryModule::BatteryModule(const std::string& name_) : InotifyModule(name_) BatteryModule::BatteryModule(const std::string& name_) : InotifyModule(name_)
{ {
this->battery = config::get<std::string>(name(), "battery", "BAT0"); this->battery = config::get<std::string>(name(), "battery", "BAT0");
this->adapter = config::get<std::string>(name(), "adapter", "ADP1"); this->adapter = config::get<std::string>(name(), "adapter", "ADP1");
this->full_at = config::get<int>(name(), "full_at", 100); this->full_at = config::get<int>(name(), "full_at", 100);
this->state = STATE_UNKNOWN;
this->percentage = 0;
this->formatter->add(FORMAT_CHARGING, TAG_LABEL_CHARGING, this->formatter->add(FORMAT_CHARGING, TAG_LABEL_CHARGING,
{ TAG_BAR_CAPACITY, TAG_RAMP_CAPACITY, TAG_ANIMATION_CHARGING, TAG_LABEL_CHARGING }); { TAG_BAR_CAPACITY, TAG_RAMP_CAPACITY, TAG_ANIMATION_CHARGING, TAG_LABEL_CHARGING });
@ -45,44 +53,54 @@ BatteryModule::BatteryModule(const std::string& name_) : InotifyModule(name_)
this->label_full = drawtypes::get_optional_config_label( this->label_full = drawtypes::get_optional_config_label(
name(), get_tag_name(TAG_LABEL_FULL), "%percentage%"); name(), get_tag_name(TAG_LABEL_FULL), "%percentage%");
this->watch(string::replace(PATH_BATTERY_CAPACITY, "%battery%", this->battery)); this->watch(string::replace(PATH_BATTERY_CAPACITY, "%battery%", this->battery), InotifyEvent::ACCESSED);
this->watch(string::replace(PATH_ADAPTER_STATUS, "%adapter%", this->adapter)); this->watch(string::replace(PATH_ADAPTER_STATUS, "%adapter%", this->adapter), InotifyEvent::ACCESSED);
if (this->animation_charging) { if (this->animation_charging)
this->threads.emplace_back(std::thread(&BatteryModule::animation_thread_runner, this)); this->threads.emplace_back(std::thread(&BatteryModule::animation_thread_runner, this));
}
} }
void BatteryModule::animation_thread_runner() void BatteryModule::animation_thread_runner()
{ {
while (this->enabled()) { std::this_thread::yield();
// std::unique_lock<std::mutex> lck(this->ev_mtx);
auto state = this->state(); const auto dur = std::chrono::duration<double>(
float(this->animation_charging->get_framerate()) / 1000.0f);
if (state & CHARGING && !(state & FULL)) { int retries = 5;
this->broadcast();
// else while (retries-- > 0)
// this->cv.wait(lck, [&]{ return this->state & CHARGING && ~this->state & FULL; }); {
std::this_thread::sleep_for(std::chrono::duration<double>( while (this->enabled()) {
float(this->animation_charging->get_framerate()) / 1000)); std::unique_lock<concurrency::SpinLock> lck(this->broadcast_lock);
} else {
std::this_thread::sleep_for(1s); if (retries > 0)
retries = 0;
if (this->state == STATE_CHARGING) {
lck.unlock();
this->broadcast();
} else {
log_trace("state != charging");
}
std::this_thread::sleep_for(dur);
} }
std::this_thread::sleep_for(500ms);
} }
} }
bool BatteryModule::on_event(InotifyEvent *event) bool BatteryModule::on_event(InotifyEvent *event)
{ {
// std::unique_lock<std::mutex> lck(this->ev_mtx);
if (event != nullptr) if (event != nullptr)
log_trace(event->filename); log_trace(event->filename);
int state = STATE_UNKNOWN;
auto path_capacity = string::replace(PATH_BATTERY_CAPACITY, "%battery%", this->battery); auto path_capacity = string::replace(PATH_BATTERY_CAPACITY, "%battery%", this->battery);
auto path_status = string::replace(PATH_ADAPTER_STATUS, "%adapter%", this->adapter); auto path_status = string::replace(PATH_ADAPTER_STATUS, "%adapter%", this->adapter);
auto status = io::file::get_contents(path_status); auto status = io::file::get_contents(path_status);
int state = UNKNOWN;
if (status.empty()) { if (status.empty()) {
log_error("Failed to read "+ path_status); log_error("Failed to read "+ path_status);
@ -96,20 +114,18 @@ bool BatteryModule::on_event(InotifyEvent *event)
return false; return false;
} }
this->percentage = (int) math::cap<float>(std::atof(capacity.c_str()), 0, 100) + 0.5; int percentage = (int) math::cap<float>(std::atof(capacity.c_str()), 0, 100) + 0.5;
switch (status[0]) { switch (status[0]) {
case '0': state = DISCHARGING; break; case '0': state = STATE_DISCHARGING; break;
case '1': state = CHARGING; break; case '1': state = STATE_CHARGING; break;
} }
if (this->state() & CHARGING && this->percentage >= this->full_at) if ((state == STATE_CHARGING) && percentage >= this->full_at)
this->percentage = 100; percentage = 100;
if (this->percentage == 100) if (percentage == 100)
state |= FULL; state = STATE_FULL;
this->state = state;
if (!this->label_charging_tokenized) if (!this->label_charging_tokenized)
this->label_charging_tokenized = this->label_charging->clone(); this->label_charging_tokenized = this->label_charging->clone();
@ -118,31 +134,28 @@ bool BatteryModule::on_event(InotifyEvent *event)
if (!this->label_full_tokenized) if (!this->label_full_tokenized)
this->label_full_tokenized = this->label_full->clone(); this->label_full_tokenized = this->label_full->clone();
auto percentage_str = std::to_string(this->percentage) + "%";
this->label_charging_tokenized->text = this->label_charging->text; this->label_charging_tokenized->text = this->label_charging->text;
this->label_charging_tokenized->replace_token("%percentage%", percentage_str); this->label_charging_tokenized->replace_token("%percentage%", std::to_string(percentage) + "%");
this->label_discharging_tokenized->text = this->label_discharging->text; this->label_discharging_tokenized->text = this->label_discharging->text;
this->label_discharging_tokenized->replace_token("%percentage%", std::to_string(this->percentage) +"%"); this->label_discharging_tokenized->replace_token("%percentage%", std::to_string(percentage) + "%");
this->label_full_tokenized->text = this->label_full->text; this->label_full_tokenized->text = this->label_full->text;
this->label_full_tokenized->replace_token("%percentage%", percentage_str); this->label_full_tokenized->replace_token("%percentage%", std::to_string(percentage) + "%");
// lck.unlock(); this->state = state;
// this->percentage = percentage;
// this->cv.notify_all();
return true; return true;
} }
std::string BatteryModule::get_format() std::string BatteryModule::get_format()
{ {
auto state = this->state(); int state = this->state();
if (state & FULL) if (state == STATE_FULL)
return FORMAT_FULL; return FORMAT_FULL;
else if (state & CHARGING) else if (state == STATE_CHARGING)
return FORMAT_CHARGING; return FORMAT_CHARGING;
else else
return FORMAT_DISCHARGING; return FORMAT_DISCHARGING;
@ -153,16 +166,9 @@ bool BatteryModule::build(Builder *builder, const std::string& tag)
if (tag == TAG_ANIMATION_CHARGING) if (tag == TAG_ANIMATION_CHARGING)
builder->node(this->animation_charging); builder->node(this->animation_charging);
else if (tag == TAG_BAR_CAPACITY) { else if (tag == TAG_BAR_CAPACITY) {
builder->node(this->bar_capacity, this->percentage); builder->node(this->bar_capacity, this->percentage());
// builder->node(this->bar_capacity, 10);
// builder->space(5);
// builder->node(this->bar_capacity, 50);
// builder->space(5);
// builder->node(this->bar_capacity, 90);
// builder->space(5);
// builder->node(this->bar_capacity, 100);
} else if (tag == TAG_RAMP_CAPACITY) } else if (tag == TAG_RAMP_CAPACITY)
builder->node(this->ramp_capacity, this->percentage); builder->node(this->ramp_capacity, this->percentage());
else if (tag == TAG_LABEL_CHARGING) else if (tag == TAG_LABEL_CHARGING)
builder->node(this->label_charging_tokenized); builder->node(this->label_charging_tokenized);
else if (tag == TAG_LABEL_DISCHARGING) else if (tag == TAG_LABEL_DISCHARGING)