LINUX.ORG.RU

Патчим fbpanel #3 Пытаюсь добавить новую фичу

 , ,


0

1

В общем, в свободное от игрулек и праздников с выходными время, я таки родил такой код:

#if defined __linux__

#define BAT_PATH "/sys/class/power_supply/BAT0"
#define BAT_DCAP "/sys/class/power_supply/BAT0/charge_full_design"
#define BAT_RCAP "/sys/class/power_supply/BAT0/charge_now"
#define BAT_STAT "/sys/class/power_supply/BAT0/status"

static void
battery_update_os(battery_priv *c)
{
	gchar *buf;
	gboolean ret = FALSE, charging = FALSE;
	int dcap = 0, rcap = 0;
	
	ENTER;
	ret = g_file_test(BAT_PATH, G_FILE_TEST_EXISTS);
	if (!ret) 
		goto exit;
		
	// Read designed capcity
	ret = g_file_get_contents(BAT_DCAP, &buf, 0, NULL);
	if (!ret) 
		goto exit;
	sscanf(buf, "%d", &dcap);
	g_free(buf);
	
	// Read remaing capacity
	ret = g_file_get_contents(BAT_RCAP, &buf, 0, NULL);
	if (!ret) 
		goto exit;
	sscanf(buf, "%d", &rcap);
	g_free(buf);
	
	// Read battery status
	ret = g_file_get_contents(BAT_STAT, &buf, 0, NULL);
	if (!ret) 
		goto exit;
	charging = (strcmp(buf, "Charging\n") == 0);
	g_free(buf);
	
	// Set values
	c->exist = TRUE;
	c->level = (int) ((gfloat) rcap * 100 / (gfloat) dcap);
	c->charging = charging;
	
exit:
	RET(ret);
}

#else

static void
battery_update_os(battery_priv *c)
{
    c->exist = FALSE;
}

#endif

В нем еще можно добавить альтернативные имена для charge* (типа energy*), но это скучно. Как передавать батарею через конфиг - я еще не разобрался. Там механизм сложнее, чем кажется на первый взгляд.

Зато придумал, что нужно запилить полюбому - время работы от батареи и время до полной зарядки. Такая штука есть в тинте, но я не совсем разобрался, по этому и решил запостить вопрос:

//Здесь energy_full - /sys/class/power_supply/BATN/charge_full
//Здесь energy_now - /sys/class/power_supply/BATN/charge_now
//Здесь current_now - /sys/class/power_supply/BATN/current_now
if(current_now > 0) {
                switch(battery_state.state) {
                        case BATTERY_CHARGING:
                                seconds = 3600 * (energy_full - energy_now) / current_now;
                                break;
                        case BATTERY_DISCHARGING:
                                seconds = 3600 * energy_now / current_now;
                                break;
                        default:
                                seconds = 0;
                                break;
                }
        } else seconds = 0;
//... вычисляем время

Ну и вопросы:

  • 3600 - что же час времени?
  • Почему за energy_full берут charge_full, а не charge_full_design? Или в charge_full отражается деградация батареи?
  • Cамое главное - что такое current_now? Потребление энергии в данный момент времени?

Выручайте :)

Deleted

Последнее исправление: Bizun (всего исправлений: 1)

3600 - что же час времени?

Да.

Почему за energy_full берут charge_full, а не charge_full_design? Или в charge_full отражается деградация батареи?

Потому, что емкость батареи со временем уменьшается. Зная charge_full и charge_full_design можно узнать насколько упала емкость батареи.

Cамое главное - что такое current_now? Потребление энергии в данный момент времени?

Ток.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Зная charge_full и charge_full_design можно узнать насколько упала емкость батареи.

Я так и предпологал, спасибо.

Почти запилил фичу, в общем то. Единственный косяк - со временем наакосячил, получил «0:-17» %)

Deleted
()

#define ... BAT0

Пожалуйста, не делайте так. Не у всех и не всегда батарея зовётся «BAT0». И не факт, что она в системе будет одна. Мне попадалась пара ноутбуков с сумасшедшим ACPI, на которых многие батарейные апплеты сбоили именно по этой причине.

AITap ★★★★★
()
Ответ на: комментарий от AITap

Да-да, я знаю, меня ругали :)

Я писал, пока не разобрался с передачей параметра плагину, как разберусь, будет так:

battery {
    name: BAT0 # Или BAT1...
}

Deleted
()

Забыл в прошлой теме предложить - а в чём проблема автодетектить батарею?

Для начала - простейшая реализация: в /sys/class/power_supply делается readdir и берётся первая попавшаяся батарея. Это позволит работать из коробки независимо от имени батареи и избавить пользователя от явного её указания.

Далее улучшения:

  • проводится маленькое исследование среди пользователей у которых батарей > 1. Предполагаю что обычно батарея всё-таки одна, а вторая - это виртуальный от кривых прошивок. Фейки можно научится определять и фильтровать (например, у них будет нулевая или отрицательная ёмкость или кривой статус)
  • в конфиге вводится blacklist, чтобы пользователь мог отключать ненужные батареи по своему усмотрению - это поможет выбрать нужную батарею для мониторинга даже если это фейк который не получится отфильтровать или у пользователя таки несколько реальных батарей
  • понятно что на последний случай можно предусмотреть мониторинг нескольких батарей сразу
slovazap ★★★★★
()
Последнее исправление: slovazap (всего исправлений: 1)
Ответ на: комментарий от andreyu

Как вариант, можно добавить два параметра - просто имя батареи и твой вариант.

Не всем оно надо, полный путь писать.

Deleted
()
Ответ на: комментарий от slovazap

Про авто-определение много думал, но ни чего хорошего не вышло.

В тинте, например, есть авто-определение или что то, на него похожее. Там просто берётся первая батарея, остальное игнорируется.

Проще прописать параметр, и готово.

Deleted
()

в свободное от игрулек и праздников с выходными время

Сказал бы просто - каникулы

anonymous
()
Ответ на: комментарий от Deleted

Ага, только их два дня осталось.

Ну так готовься, собирай портфель. Седьмой класс - это очень важный этап в жизни ребёнка.

anonymous
()
Ответ на: комментарий от Deleted

А то, блин, отправят ещё в армию...

Ага, будешь «сыном полка»

anonymous
()
Ответ на: комментарий от slovazap

Ну дык, сделай лучше.

Я же говорю, в том же tint2 говнокода не меньше моего. Там тупо берётся одна, первая батарея и все.

Хочешь сказать, это решение лучше, чем возможность заменить дефолтную BAT0 на BATN?

А тинт я взял по тому, что он довольно популярен и ни кто не жалуется.

Deleted
()

Breaking News

Тупил два дня с подсчётом времени - оказалось не помещается в 32 бита.

Это подстава. Нужно перепроверить другие панели, ибо в них, на сколько я помню, используют тоже 32 бинтные значения и не ловят переполнения.

Deleted
()

Новости с фронта №3

Я таки сделал отображение времени до разряда/заряда. Было много проблем с типами переменных, я просто афигел. Числа большие, сначала просто не знал на сколько и юзал int. Потом заметил переполнение - стал использовать int64_t. Но потом получился конфликт типов из за неявного преобразования, я его так и не нашел. Переписал заново, подсмотрев кое-что в исходниках tint2, все стало збс!

Патчик, пока не доведенный до красивого состояния:

#define BAT_PATH "/sys/class/power_supply/BAT0"
#define BAT_CHARGE_FULL "/sys/class/power_supply/BAT0/charge_full"
#define BAT_CHARGE_NOW "/sys/class/power_supply/BAT0/charge_now"
#define BAT_STATUS "/sys/class/power_supply/BAT0/status"
#define BAT_CURRENT_NOW "/sys/class/power_supply/BAT0/current_now"

static void
battery_update_os(battery_priv *c)
{
	gchar *buf;
	gboolean exist, ret, charging;
	int64_t current_now = 0, energy_now = 0, energy_full = 0;
	
	ENTER;
	ret = g_file_test(BAT_PATH, G_FILE_TEST_EXISTS);
	if (!ret) goto exit;
		
	// Read designed capcity
	ret = g_file_get_contents(BAT_CHARGE_FULL, &buf, 0, NULL);
	if (!ret) goto exit;
	energy_full = atoi(buf);
	g_free(buf);
	
	// Read remaing capacity
	ret = g_file_get_contents(BAT_CHARGE_NOW, &buf, 0, NULL);
	if (!ret) goto exit;
	energy_now = atoi(buf);
	g_free(buf);
	
	// Read current power 
	ret = g_file_get_contents(BAT_CURRENT_NOW, &buf, 0, NULL);
	if (!ret) goto exit;
	current_now = atoi(buf);
	g_free(buf);
	
	// Read battery status
	ret = g_file_get_contents(BAT_STATUS, &buf, 0, NULL);
	if (!ret) goto exit;
	charging = (strcmp(buf, "Charging\n") == 0);
	g_free(buf);
	
	// Set values
	c->exist = TRUE;
	c->level = (int) (energy_now * 100 / energy_full);
	c->charging = charging;
	
	//Set time
	int hours, minutes, seconds;
	if (charging) {
		seconds = 3600 * (energy_full - energy_now) / current_now;
	} else {
		seconds = 3600 * energy_now / current_now;
	}
	//DBG2("\n\ndcap:%d\nrcap:%d\ncnow:%d\nsec:%d", energy_full, energy_now, current_now, seconds);
	hours = seconds / 3600;
        seconds -= 3600 * hours;
        minutes = seconds / 60;
        seconds -= 60 * minutes;
	g_snprintf(c->time, sizeof(c->time), "%d:%d:%d", hours, minutes, seconds);
	
exit:
	RET(ret);
}

Deleted
()
Ответ на: комментарий от dib2

Чем лучше то? Инфа одна и та же.

Кстати, acpi же не всегда в поставке дистра, или я ошибаюсь? /sys/ же есть всегда.

Deleted
()
Ответ на: комментарий от Deleted

тем что не нужно #define BAT_PATH (у меня например не работает), независимость от формата содержимого файлов в /sys (это я про 3600 к примеру), ну и юниксвейно - консольная утилитка без зависимостей и GUI к ней.
кроме того, тут же - кулеры и их состояние.

dib2 ★★★★★
()
Ответ на: комментарий от dib2

Хм, удобно, да.

Ответьте мне на один вопрос - acpi идет во всех дистрах по дефолту? Если да, то переделаю. Если нет, то зачем? В том же тинте чтение файлов, например. Ни кто не жалуется.

Deleted
()
Ответ на: комментарий от Deleted

не в курсе. но всегда пользуюсь, для правдивой оценки состояния батареи (лучше чем про /sys лазить), а KDE в этом плане зело глючит

dib2 ★★★★★
()
Ответ на: комментарий от dib2

Эм, а что там не так?

Сори за тупняк, да.

Deleted
()
Ответ на: комментарий от Deleted

Я тебе уже написал как сделать лучше. Да, лучше, потому что пользователю не придётся лезть в конфиг чтобы рассказать программе про то про что она сама может узнать, конфиг же остаётся _только_ для совсем сложных случаев.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

Посмотри исходники tint2. Он берет первую установленную батарею. В 90% случаев это бат0. В остальных все сложнее, и этот код все равно не спасёт:

while ((entryname=g_dir_read_name(directory))) {
                        if (strncmp(entryname,"AC", 2) == 0) continue;

                        char *path1 = g_build_filename("/sys/class/power_supply", entryname, "present", NULL);
                        if (g_file_test (path1, G_FILE_TEST_EXISTS)) {
                                g_free(path1);
                                battery_dir = g_build_filename("/sys/class/power_supply", entryname, NULL);
                                break;
                        }
                        g_free(path1);
                }

Deleted
()

На выходных хочу выложить панельку, чтобы вы потестили.

Вопрос - исходники же всех устроят? Я не умею собирать пакеты ни для одного из существующих дистрибутивов =)

Deleted
()
Ответ на: комментарий от slovazap

А знаешь, так и придётся сделать. Но не по тому, что тебе так хочется, а по тому, что нех%р пихать в код дефайны дефайнов, в которых чёрт ногу сломит.

В общем, я не разобрался как заставить плагин читать инфу из конфига.

Deleted
()
Ответ на: комментарий от Deleted

Мне так не «хочется» - я в жизни эту fbpanel не видел и скорее всего никогда не увижу. Я просто сказал как правильно - чтобы это самому понять надо было всего лишь чуть-чуть логики и базового представления о юзабилити.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

юзабилити

Ок, мне всегда говорили, что я очень странно себе это юзабилити представляю. Отсюда, быть может, все и вытикает.

А вообще, явное лучше не явного, для меня. Чем автоматически пытаться найти нужную батарею, лучше прописать руками. Но это моё мнение, да. Я таки сделаю автоопределение, а указание батареи позже, как один из вариантов.

Deleted
()
Последнее исправление: Bizun (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.