ibam-0.5.2/0000755000324400001440000000000011155244600011135 5ustar sfrusersibam-0.5.2/Makefile0000644000324400001440000000506511155244600012603 0ustar sfrusers# IBAM, the Intelligent Battery Monitor # Copyright (C) 2001-2003, Sebastian Ritterbusch (IBAM@Ritterbusch.de) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # IBAM_VERSION=0.5.2 CC=g++ CFLAGS=-O3 -DIBAM_VERSION=\"$(IBAM_VERSION)\" -Wall PREFIX=/usr INSTALL=install -m 755 RM=rm -f RMDIR=rm -rf INSTDIR=install -d all: ibam ibam: ibam.cpp ibam.inl ibam.hpp $(CC) $(CFLAGS) ibam.cpp -o ibam krell: ibam-krell.so ibam-krell.so: ibam-krell.o $(CC) $(CFLAGS) -fPIC -shared -Wl -o ibam-krell.so ibam-krell.o ibam-krell.o: ibam-krell.cpp ibam.hpp ibam.inl $(CC) $(CFLAGS) -fPIC `pkg-config gtk+-2.0 --cflags` `gdk-pixbuf-config --cflags` -c ibam-krell.cpp krell1: ibam-krell1.so ibam-krell1.so: ibam-krell1.o $(CC) $(CFLAGS) -shared -Wl -o ibam-krell1.so ibam-krell1.o ibam-krell1.o: ibam-krell1.cpp ibam.hpp ibam.inl $(CC) $(CFLAGS) -fPIC `gtk-config --cflags` `imlib-config --cflags-gdk` -c ibam-krell1.cpp install: ibam $(INSTALL) ./ibam $(PREFIX)/local/bin/ -$(INSTALL) ./ibam-krell.so $(PREFIX)/local/lib/gkrellm/plugins/ -$(INSTALL) ./ibam-krell1.so $(PREFIX)/local/lib/gkrellm/plugins/ source-archive: clean $(RMDIR) ibam-$(IBAM_VERSION) mkdir ibam-$(IBAM_VERSION) -cp -f * ibam-$(IBAM_VERSION) -$(RM) ibam-$(IBAM_VERSION).tar.gz tar cvfz ibam-$(IBAM_VERSION).tar.gz ibam-$(IBAM_VERSION) $(RMDIR) ibam-$(IBAM_VERSION) deb: source-archive @echo @echo "***************************************" @echo "THIS IS UNTESTED - HELP IS APPRECIATED!" @echo "***************************************" @echo "/me does not know debian... :)" dpkg-buildpackage -rfakeroot -us -uc ibam-$(IBAM_VERSION).tar.gz -$(RM) ibam-$(IBAM_VERSION).tar.gz rpm: source-archive rpm -ta --clean ibam-$(IBAM_VERSION).tar.gz -$(RM) ibam-$(IBAM_VERSION).tar.gz uninstall: $(RM) $(PREFIX)/local/bin/ibam $(RM) $(PREFIX)/local/lib/gkrellm/plugins/ibam-krell.so clean: $(RMDIR) core ibam ibam-krell.so ibam-krell1.so *.o *~ ibam-*.tar.gz ibam-*.rpm ibam-0.5.2/ibam-krell.cpp0000644000324400001440000001710311155244600013662 0ustar sfrusers/* demo2.c - requires GKrellM 1.2.0 or better | gcc -fPIC `gtk-config --cflags` `imlib-config --cflags-gdk` -c demo2.c | gcc -shared -Wl -o demo2.so demo2.o | gkrellm -p demo2.so */ #define IBAM_KRELL #include "ibam.hpp" extern "C" { #define private gkrell_private #include #include #include /* CONFIG_NAME would be the name in the configuration tree, but this demo | does not have a config. See demo1.c for that. */ #define CONFIG_NAME "Ibam" /* STYLE_NAME will be the theme subdirectory for custom images for this | plugin and it will be the gkrellmrc style name for custom settings. */ #define STYLE_NAME "ibam" /* This demo just makes up some data for the krell to show. */ #define KRELL_FULL_SCALE 30 static GkrellmMonitor *monitor; static GkrellmPanel *panel; static gint style_id; static GkrellmKrell *krell; static GkrellmDecal *decal_text; static void update_plugin() { if (GK.second_tick) { static ibam a; static char buffer[80]; char *l; static char *bat="Batt"; static char *charge="Char"; static char *full="Full"; static long lasttime=time(NULL); a.update(); if(a.valid()) { int updateadd=0; if(time(NULL)window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], panel->pixmap, ev->area.x, ev->area.y, ev->area.x, ev->area.y, ev->area.width, ev->area.height); return FALSE; } static void create_plugin(GtkWidget *vbox, gint first_create) { GkrellmStyle *style; GkrellmTextstyle *textstyle; GkrellmPiximage *krell_image; /* This create_plugin() routine is a create event routine which | will be called when GKrellM is re-built at every theme or horizontal | size change. The idea is to allocate data structures and do some | initialization only once (at first_create) and do decal and krell | creation and plugin local image loading each time so theme changes | will be picked up. | Before this routine is called during the re-build, all of the krells | and decals you previously created will have been destroyed. However, | for cases where a plugin wants to manage the decal and krell lists, | it is possible to prevent the automatic krell and decal destruction. */ if (first_create) panel = gkrellm_panel_new0(); /* Each plugin that has obtained a style_id (in init_plugin()) can use | a default krell that may have been custom themed. Additional custom | krells may be created, but here we just use the default krell. To | create a kell, use our style (which has information about the krell | depth, hot spot, and y offset into the panel), and our krell image. */ style = gkrellm_meter_style(style_id); krell_image = gkrellm_krell_meter_piximage(style_id); krell = gkrellm_create_krell(panel, krell_image, style); textstyle = gkrellm_meter_textstyle(style_id); decal_text = gkrellm_create_decal_text(panel, "IBAM", textstyle, style, -1, -1, -1); /* The default for GKrellM data update routines is to expect monotonically | increasing data values. So the real data values stored for display are | differences between successive data updates. But the data this demo | krell will measure will be values within a fixed range, so we must | turn off the monotonic mode. */ gkrellm_monotonic_krell_values(krell, FALSE); /* Set the kell full scale value and a krell scaling factor. The scaling | factor should almost always be 1. Only chart styled krells that have | a small full scale value might need a scaling factor greater than 1. */ gkrellm_set_krell_full_scale(krell, KRELL_FULL_SCALE, 1); /* Configuring a panel means to determine the height needed to accomodate | its label and all of the created decals and krells that it contains. | This is where we set the label on the panel to be "Plugin". Many | plugins will have panels with changing text or pixmap decals and will | not use a label at all. In those cases, just pass NULL for the label. | Some plugins may want to have a fixed panel height. Those should | call gkrellm_panel_configure_add_height() instead of this: */ gkrellm_panel_configure(panel, NULL , style); /* Finally create the panel. It will have a background image which will | be the theme default or plugin specific if created by the theme maker. */ gkrellm_panel_create(vbox, monitor, panel); gkrellm_draw_decal_text(panel,decal_text,"IBAM",-1); if (first_create) gtk_signal_connect(GTK_OBJECT (panel->drawing_area), "expose_event", (GtkSignalFunc) panel_expose_event, NULL); } /* The monitor structure tells GKrellM how to call the plugin routines. */ static GkrellmMonitor plugin_mon = { CONFIG_NAME, /* Title for config clist. */ 0, /* Id, 0 if a plugin */ create_plugin, /* The create function */ update_plugin, /* The update function */ NULL, /* The config tab create function */ NULL, /* Apply the config function */ NULL, /* Save user config */ NULL, /* Load user config */ NULL, /* config keyword */ NULL, /* Undefined 2 */ NULL, /* Undefined 1 */ NULL, /* private */ MON_MAIL, /* Insert plugin before this monitor */ NULL, /* Handle if a plugin, filled in by GKrellM */ NULL /* path if a plugin, filled in by GKrellM */ }; /* All GKrellM plugins must have one global routine named init_plugin() | which returns a pointer to a filled in monitor structure. */ GkrellmMonitor *gkrellm_init_plugin(void) { /* If this next call is made, the background and krell images for this | plugin can be custom themed by putting bg_meter.png or krell.png in the | subdirectory STYLE_NAME of the theme directory. Text colors (and | other things) can also be specified for the plugin with gkrellmrc | lines like: StyleMeter STYLE_NAME.textcolor orange black shadow | If no custom theming has been done, then all above calls using | style_id will be equivalent to style_id = DEFAULT_STYLE_ID. */ style_id = gkrellm_add_meter_style(&plugin_mon, STYLE_NAME); monitor = &plugin_mon; return &plugin_mon; } } ibam-0.5.2/ibam.spec0000644000324400001440000000174611155244600012731 0ustar sfrusers%define version 0.4 %define release 1 Summary: Intelligent Battery Monitor Name: ibam Version: %{version} Release: %{release} Copyright: GPL Group: Utilities/System Source: http://prdownloads.sourceforge.net/ibam/ibam-%{version}.tar.gz BuildRoot: /var/tmp/%{name}-buildroot %description IBAM is an advanced battery monitor for laptops, which uses statistical and adaptive linear methods to provide accurate estimations of minutes of battery left or of the time needed until full recharge. %prep %setup -q %build make RPM_OPT_FLAGS="$RPM_OPT_FLAGS" ibam krell %install install -m 0755 -d $RPM_BUILD_ROOT/usr install -m 0755 -d $RPM_BUILD_ROOT/usr/local install -m 0755 -d $RPM_BUILD_ROOT/usr/local/bin install -m 0755 -d $RPM_BUILD_ROOT/usr/local/lib install -m 0755 -d $RPM_BUILD_ROOT/usr/local/lib/gkrellm install -m 0755 -d $RPM_BUILD_ROOT/usr/local/lib/gkrellm/plugins make install PREFIX=$RPM_BUILD_ROOT/usr %files %defattr (-,root,root) /usr/local/bin/ibam /usr/local/lib/gkrellm/plugins ibam-0.5.2/ibam-krell1.cpp0000644000324400001440000001664511155244600013755 0ustar sfrusers/* demo2.c - requires GKrellM 1.2.0 or better | gcc -fPIC `gtk-config --cflags` `imlib-config --cflags-gdk` -c demo2.c | gcc -shared -Wl -o demo2.so demo2.o | gkrellm -p demo2.so */ #include "ibam.hpp" extern "C" { #define private gkrell_private #include /* CONFIG_NAME would be the name in the configuration tree, but this demo | does not have a config. See demo1.c for that. */ #define CONFIG_NAME "Ibam" /* STYLE_NAME will be the theme subdirectory for custom images for this | plugin and it will be the gkrellmrc style name for custom settings. */ #define STYLE_NAME "ibam" /* This demo just makes up some data for the krell to show. */ #define KRELL_FULL_SCALE 30 static Monitor *monitor; static Panel *panel; static gint style_id; static Krell *krell; static Decal *decal_text; static void update_plugin() { if (GK.second_tick) { static ibam a; static char buffer[80]; char *l; static char *bat="batt"; static char *charge="chrg"; static char *full="full"; static long lasttime=time(NULL); a.update(); if(a.valid()) { int updateadd=0; if(time(NULL)window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], panel->pixmap, ev->area.x, ev->area.y, ev->area.x, ev->area.y, ev->area.width, ev->area.height); return FALSE; } static void create_plugin(GtkWidget *vbox, gint first_create) { Style *style; TextStyle *textstyle; GdkImlibImage *krell_image; /* This create_plugin() routine is a create event routine which | will be called when GKrellM is re-built at every theme or horizontal | size change. The idea is to allocate data structures and do some | initialization only once (at first_create) and do decal and krell | creation and plugin local image loading each time so theme changes | will be picked up. | Before this routine is called during the re-build, all of the krells | and decals you previously created will have been destroyed. However, | for cases where a plugin wants to manage the decal and krell lists, | it is possible to prevent the automatic krell and decal destruction. */ if (first_create) panel = gkrellm_panel_new0(); /* Each plugin that has obtained a style_id (in init_plugin()) can use | a default krell that may have been custom themed. Additional custom | krells may be created, but here we just use the default krell. To | create a kell, use our style (which has information about the krell | depth, hot spot, and y offset into the panel), and our krell image. */ style = gkrellm_meter_style(style_id); krell_image = gkrellm_krell_meter_image(style_id); krell = gkrellm_create_krell(panel, krell_image, style); textstyle = gkrellm_meter_textstyle(style_id); decal_text = gkrellm_create_decal_text(panel, "IBAM", textstyle, style, -1, -1, -1); /* The default for GKrellM data update routines is to expect monotonically | increasing data values. So the real data values stored for display are | differences between successive data updates. But the data this demo | krell will measure will be values within a fixed range, so we must | turn off the monotonic mode. */ gkrellm_monotonic_krell_values(krell, FALSE); /* Set the kell full scale value and a krell scaling factor. The scaling | factor should almost always be 1. Only chart styled krells that have | a small full scale value might need a scaling factor greater than 1. */ gkrellm_set_krell_full_scale(krell, KRELL_FULL_SCALE, 1); /* Configuring a panel means to determine the height needed to accomodate | its label and all of the created decals and krells that it contains. | This is where we set the label on the panel to be "Plugin". Many | plugins will have panels with changing text or pixmap decals and will | not use a label at all. In those cases, just pass NULL for the label. | Some plugins may want to have a fixed panel height. Those should | call gkrellm_panel_configure_add_height() instead of this: */ gkrellm_panel_configure(panel, NULL , style); /* Finally create the panel. It will have a background image which will | be the theme default or plugin specific if created by the theme maker. */ gkrellm_panel_create(vbox, monitor, panel); gkrellm_draw_decal_text(panel,decal_text,"IBAM",-1); if (first_create) gtk_signal_connect(GTK_OBJECT (panel->drawing_area), "expose_event", (GtkSignalFunc) panel_expose_event, NULL); } /* The monitor structure tells GKrellM how to call the plugin routines. */ static Monitor plugin_mon = { CONFIG_NAME, /* Title for config clist. */ 0, /* Id, 0 if a plugin */ create_plugin, /* The create function */ update_plugin, /* The update function */ NULL, /* The config tab create function */ NULL, /* Apply the config function */ NULL, /* Save user config */ NULL, /* Load user config */ NULL, /* config keyword */ NULL, /* Undefined 2 */ NULL, /* Undefined 1 */ NULL, /* private */ MON_MAIL, /* Insert plugin before this monitor */ NULL, /* Handle if a plugin, filled in by GKrellM */ NULL /* path if a plugin, filled in by GKrellM */ }; /* All GKrellM plugins must have one global routine named init_plugin() | which returns a pointer to a filled in monitor structure. */ Monitor * init_plugin() { /* If this next call is made, the background and krell images for this | plugin can be custom themed by putting bg_meter.png or krell.png in the | subdirectory STYLE_NAME of the theme directory. Text colors (and | other things) can also be specified for the plugin with gkrellmrc | lines like: StyleMeter STYLE_NAME.textcolor orange black shadow | If no custom theming has been done, then all above calls using | style_id will be equivalent to style_id = DEFAULT_STYLE_ID. */ style_id = gkrellm_add_meter_style(&plugin_mon, STYLE_NAME); monitor = &plugin_mon; return &plugin_mon; } } ibam-0.5.2/README0000644000324400001440000002266311155244600012026 0ustar sfrusers IBAM, the Intelligent Battery Monitor http://ibam.sourceforge.net/ 1. Description IBAM is an advanced battery monitor for laptops, which uses statistical and adaptive linear methods to provide accurate estimations of minutes of battery left or of the time needed until full recharge. It is available as shell utility, gkrellm plugin and is included in pbbuttons.berlios.de . Your system needs to have a proc-filesystem and either apmd, acpi, pmu or sysfs to be installed. IBAM is a GPLed Open Source Project. You are coordinally invited to join! 2. Building the shell utility First steps with IBAM: To build IBAM simply enter: make Then you need to build initial statistics, so enter (*) watch -n10 ./ibam and unplug the power source from your laptop. IBAM will now save the time intervals between changes in battery status, by reading /proc/apm (or the acpi or the pmu interface). IBAM will already tell you about its estimations, but they will be as inaccurate as the information of the apmd or apm-bios. Wait and drink coffee. It should be noted that using one of the gkrellm-plugins is an alternative to using the watch-statement. As soon your battery is empty (hope you didn't lose any data.. ;), replug the power and let ibam continue recording the characteristics of your system. Meanwhile you may invoke ./ibam -ra --plot to get some statistics. The more often you run or watch ibam, the smoother the statistics will get and the more accurate ibam will be. If you enabled the additional profiling by "--profile", then you can also compare the statistics to the latest measurements, i.e. the last 10 samples (if there are that many): ./ibam -r --plot=10 IBAM assumes, that the BIOS will at least be able to report a remaining battery level percentage of 5 percent- for some laptops this is already the point of shutdown, so this will be taken into consideration via the so called "soft low limit". As soon IBAM sees a lower percentage, this "soft" limit decreses to the lowest seen (and therefore somewhat safe) value. If your laptop shuts down well above 5 percent, you may increase this soft limit using ./ibam --softlowlimit=10 but this will only work, if IBAM has not seen lower values before. But if IBAM is in error, or if you prefer staying away from such low value, you may set a hard limit for your lowest safe percentage via: ./ibam --hardlowlimit=10 To disable the limits, just specify a limit of 0%. 3.1. Building the gkrellm2 plugin If you have the appropriate libraries (gtk+-2, gkrellm-devel) installed, you may also build the krell-plugin of ibam by entering make krell You can test this plugin using gkrellm -p ibam-krell.so or copying the library ibam-krell.so into your ~/.gkrellm/plugins/ and enabling the plugin within gkrellm after you had restarted it. 3.2. Building the gkrellm1 plugin If you have the appropriate libraries (gtk, imllib, gkrellm-devel) installed, you may also build the krell-plugin of ibam by entering make krell1 You can test this plugin using gkrellm -p ibam-krell1.so or copying the library ibam-krell1.so into your ~/.gkrellm/plugins/ and enabling the plugin within gkrellm after you had restarted it. 3.3. Using the gkrellm-plugin On the plugin the marker will always show the battery percentage. When running on batteries, it will show "batt" and the adaptively computed time left. When charging it will show "chrg" and the adaptively computed time left until full charge. If the battery is full, the text will be "full" with the total battery time. The gkrell-plugin will read the current profile only once at start and update the profile when necessary. Thus you may also create the initial profile with this plugin. You can always use the ibam-command to get more detailed statistics. You can find gkrellm at: http://www.gkrellm.net/ 4. Installing You may install ibam using the make install command. This will install ibam into /usr/local/bin and the gkrellm-plugin in /usr/local/libs/gkrellm/plugins if you had built the plugin as well. You may also create a RPM with make rpm which can be installed as root using the rpm utility rpm -Uvh ibam-(VERSION)-1.i386.rpm It is planned to create a debian package by make deb "which will compile a debian package including debian source packages, all of them unsigned (-us unsigned source -uc unsigned compiled) using fakeroot as get_root_cmd. dpkg-buildpackage checks for build-depends, however fakeroot will not be in the build-depends since anyone is free to use su, sudo, super...."- the latter was contributed by Martin Wuertele. But yet it's untested and I don't know how to do it... ;) 5. File formats The file formats changed since 0.1, but you may import the old profiles using the --import option in the directory the 0.1 version was started in. IBAM will now save the profiles and other informations in the directory ~/.ibam where you will find the files ibam.rc, battery.rc and charge.rc. Thus if you plan to use the same statistics for different users, make sure that this directory is soft-linked to all participants and with appropriate permissions on it. Here are the current file structures: ibam.rc: (current ibam status) 0.5 1131300315 97 1.0523 2 2 1 23 0 1 5 0 The first number describes the version of IBAM that create this file. The next is the time-stamp when IBAM noticed the last change in APM status. The third number shows the last recorded APM battery percentage. The fourth number shows the current adaptivity factor, followed by the number of measurements that were taken into consideration. The sixth shows the last status (charging, on battery or undefined). The seventh number defines whether profiles should be recorded, followed by the number of the current profile and the next says if this profile is active right now. The last two numbers are the soft and hard lowest safe limits for battery percentages, zero if they are disabled. battery.rc and charge.rc: (battery and charge profiles) [...] 94 109.852 26.4915 25 93 109.992 26.3673 25 [...] Here you can see the average number in the second column of seconds per percentage unit in first column. The third column shows the standard derivation (sqrt(s^2)) the fourth the number of samples the statistics in these lines are based on. 6. ALPHA status This software is in alpha-status, please tell me about your experiences and send me your battery and charge profiles for further analysis. Thanks to profiles that were sent to me, it turned out that the accuracy can even be increased by more intelligent profiling. So far you may alread start creating the profiles by enabling the additional per cycle profiling, but yet this information will not be used by the current version, but hopefully in one of the future releases. 7. Future Plans and Optional Profiling Ibam gains its accuracy by collecting statistics about (dis)charge time for each percentage. You may visualize this as simple table where each percentage is mapped to a time period. Yet there are different "profiles" one cannot neglect, such as different power saving modes. Currently ibam tries to deal with this by means of linear adaption: On each percentage step the ratio of expected to estimated time is computed and averaged over the cycle so far. This averaged ratio is used as an adaption to different power demands- but as batteries are highly unlinear, this is just a rough estimate. The mathematical solution is to introduce statistics based on current percentage and history. The tables would grow huge, but may stay managable by means of compression of sparse matrices. Yet each estimate computation would yield up to a hundred matrix multiplications with approximately 100x100 cell matrices. This gets to a point where the measurement may even influence power consumption due to excessive cpu usage... ;) But looking at the sparsity of the matrices, which we should assume, we recognize the profiles mentioned before: These will be certain paths the (dis)charge will follow more or less accurately. Thus it's reasonable just to record a sufficiently high number of paths and compute the distance of the current measurements to the paths we saw before and take a "distance-weighted average" of our memory as an estimation. This method incorporates the advantages of the old method, but uses the information of the more general method, yet using far less computational power- limited by the number of profile-realizations we are keeping. Therefore enable (./ibam --profile) the additional profiling of ibam to already collect data for the next-generation ibam, which will then give you even far more accurate results than the current version. 8. Author and Contact address Sebastian Ritterbusch, IBAM@ritterbusch.de Special thanks go to: Mohanty Mitrabhanu for his scientific paper mentioning ibam Dan Egnor for his sweetcode article Martin Wuertele for the debian port Seth Golub for code improvements Misha Nasledov for the gkrellm2-patch Matthew Richardson for the gentoo support Florian Ragwitz for the PMU support Matthias Grimm for the extended PMU support and pbbuttons.berlios.de Peter Gaal for testing and the APM bugfix Brad Sawatzky for the same APM bugfix and all others for their motivating mails! :) 9. Footnote (*) On some RedHat and Mandrake Distributions (as of Aug 2001) "watch" shows redraw errors in the KDE terminal. You can prevent this from happening by changing the TERM variable before: export TERM=xterm-color ibam-0.5.2/ibam.cpp0000644000324400001440000004140411155244600012554 0ustar sfrusers// IBAM, the Intelligent Battery Monitor // Copyright (C) 2001-2005, Sebastian Ritterbusch (IBAM@Ritterbusch.de) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // #include "ibam.hpp" #include #include // for mkdir #include // for mkdir int no_HMS=0; class HMS { private: int secs; public: HMS(int s) : secs(s) { if(secs<0) secs=0; } friend ostream & operator <<(ostream & o,const HMS & a) { if(no_HMS) return (o << a.secs); o.fill(' '); o.width(2); o << a.secs/3600 << ':'; o.width(2); o.fill('0'); o << (a.secs/60)%60 << ':'; o.width(2); o.fill('0'); o << a.secs % 60; return o; } }; int main(int argc,char *argv[]) { ibam data; int show_minimal=1; int show_bios=0; int show_seconds_left_battery_bios=0; int show_seconds_left_battery=0; int show_seconds_left_battery_adaptive=0; int show_percent_battery_bios=0; int show_percent_battery=0; int show_seconds_left_charge=0; int show_seconds_left_charge_adaptive=0; int show_percent_charge=0; int show_seconds_battery_total=0; int show_seconds_battery_total_adaptive=0; int show_seconds_charge_total=0; int show_seconds_charge_total_adaptive=0; int show_profile_logging=0; int show_credits=0; int do_second_correction=0; int show_soft_low_limit=0; int show_hard_low_limit=0; int readonly = 0; string home(getenv("HOME")); if(home!="") home+="/"; while(1) { int option_index=0; static struct option long_options[] = { {"bios",0,0,'b'}, {"help",0,0,'h'}, {"batterybios",0,0,0}, {"battery",0,0,1}, {"batteryadaptive",0,0,2}, {"percentbios",0,0,3}, {"percentbattery",0,0,4}, {"charge",0,0,5}, {"chargeadaptive",0,0,6}, {"percentcharge",0,0,7}, {"totalbattery",0,0,8}, {"totalbatteryadaptive",0,0,9}, {"totalcharge",0,0,10}, {"totalchargeadaptive",0,0,11}, {"plot",optional_argument,0,12}, {"plotderivations",optional_argument,0,13}, {"import",0,0,14}, {"correctseconds",0,0,'c'}, {"seconds",0,0,'s'}, {"readonly",0,0,'r'}, {"all",0,0,'a'}, {"version",0,0,'v'}, {"profile",0,0,15}, {"noprofile",0,0,16}, {"credits",0,0,17}, {"softlowlimit",optional_argument,0,18}, {"hardlowlimit",optional_argument,0,19}, {0,0,0,0} }; int c=getopt_long(argc,argv,"avbhcsr",long_options,&option_index); if(c==-1) break; switch(c) { case 0: show_seconds_left_battery_bios=1; break; case 1: show_seconds_left_battery=1; break; case 2: show_seconds_left_battery_adaptive=1;break; case 3: show_percent_battery_bios=1;break; case 4: show_percent_battery=1;break; case 5: show_seconds_left_charge=1;break; case 6: show_seconds_left_charge_adaptive=1;break; case 7: show_percent_charge=1;break; case 8: show_seconds_battery_total=1;break; case 9: show_seconds_battery_total_adaptive=1;break; case 10: show_seconds_charge_total=1;break; case 11: show_seconds_charge_total_adaptive=1;break; case 12: { string command; command=string("echo \"plot \\\"") +home +string(".ibam/battery.rc\\\" using 1:2 title \\\"Battery\\\" with lines,\\\"") +home +string(".ibam/charge.rc\\\" using 1:2 title \\\"Charge\\\" with lines"); if (optarg) { int n=atoi(optarg); if(n>IBAM_MAXIMAL_PROFILES) n=IBAM_MAXIMAL_PROFILES; int p=data.current_profile_number(); for(;n>=0;n--) { string batname=data.profile_filename(p,1); string chrname=data.profile_filename(p,2); ifstream batteryprofile(batname.c_str()); if(!batteryprofile.fail()) { command+=", \\\""+batname+"\\\" using 1:2 notitle with lines 5"; } else { ifstream chargeprofile(chrname.c_str()); if(!chargeprofile.fail()) { command+=", \\\""+chrname+"\\\" using 1:2 notitle with lines 6"; } } p--; if(p<0) p+=IBAM_MAXIMAL_PROFILES; } } command+="\" | gnuplot -persist"; system(command.c_str()); } break; case 13: { string command; command=string("echo \"plot \\\"") +home +string(".ibam/battery.rc\\\" using 1:2 title \\\"Battery\\\" with lines 1, \\\"") +home +string(".ibam/battery.rc\\\" using 1:(\\$2+\\$3) notitle with lines 3, \\\"") +home +string(".ibam/battery.rc\\\" using 1:(\\$2-\\$3) notitle with lines 3,\\\"") +home +string(".ibam/charge.rc\\\" using 1:2 title \\\"Charge\\\" with lines 2, \\\"") +home +string(".ibam/charge.rc\\\" using 1:(\\$2+\\$3) notitle with lines 4, \\\"") +home +string(".ibam/charge.rc\\\" using 1:(\\$2-\\$3) notitle with lines 4"); if (optarg) { int n=atoi(optarg); if(n>IBAM_MAXIMAL_PROFILES) n=IBAM_MAXIMAL_PROFILES; int p=data.current_profile_number(); for(;n>=0;n--) { string batname=data.profile_filename(p,1); string chrname=data.profile_filename(p,2); ifstream batteryprofile(batname.c_str()); if(!batteryprofile.fail()) { command+=", \\\""+batname+"\\\" using 1:2 notitle with lines 5"; } else { ifstream chargeprofile(chrname.c_str()); if(!chargeprofile.fail()) { command+=", \\\""+chrname+"\\\" using 1:2 notitle with lines 6"; } } p--; if(p<0) p+=IBAM_MAXIMAL_PROFILES; } } command+="\" | gnuplot -persist"; system(command.c_str()); } break; case 14: data.import(); break; case 15: data.set_profile_logging(1); break; case 16: data.set_profile_logging(0); break; case 17: show_credits=1; break; case 'c': do_second_correction=1; break; case 'b': show_bios=1; break; case 's': no_HMS=1; break; case 'r': readonly=1; break; case 'a': show_soft_low_limit=show_hard_low_limit=show_profile_logging=show_seconds_left_battery_bios=show_seconds_left_battery=show_seconds_left_battery_adaptive=show_percent_battery_bios=show_percent_battery=show_seconds_left_charge=show_seconds_left_charge_adaptive=show_percent_charge=show_seconds_battery_total=show_seconds_battery_total_adaptive=show_seconds_charge_total=show_seconds_charge_total_adaptive=1; break; case 'v': cerr << "IBAM-" << IBAM_VERSION << " (C) 2001-2008 Sebastian Ritterbusch" << endl; break; case 'h': cout << "IBAM-" << IBAM_VERSION << ", the Intelligent Battery Monitor" << endl; cout << "(C) 2001-2008 Sebastian Ritterbusch" << endl << endl; cout << "Usage: ibam [options]" << endl; cout << endl; cout << "Options:" << endl; cout << " -h, --help displays this message" << endl; cout << " -v, --version displays software version" << endl; cout << " -b, --bios show bios apm guesses" << endl; cout << " -s, --seconds displays times in seconds" << endl; cout << " -c, --correctseconds displays changes in seconds" << endl; cout << " -r, --readonly no files will be updated" << endl; cout << " -a, --all show ALL information" << endl; cout << " --battery show battery time" << endl; cout << " --batteryadaptive show adaptive battery time" << endl; cout << " --batterybios show bios battery time guess" << endl; cout << " --percentbattery show battery percentage" << endl; cout << " --percentbios show bios percentage" << endl; cout << " --charge show charge time" << endl; cout << " --chargeadaptive show adaptive charge time" << endl; cout << " --percentcharge show charge percentage" << endl; cout << " --totalbattery show total battery time" << endl; cout << " --totalbatteryadaptive show adaptive total battery" << endl; cout << " --totalcharge show total charge time" << endl; cout << " --totalchargeadaptive show adaptive total charge" << endl; cout << " --hardlowlimit[=lim] show user defined hard lower percentage limit" << endl; cout << " [and set it to value or disable <0> it]" << endl; cout << " --softlowlimit[=lim] show automatic lower percentage limit" << endl; cout << " [and lower it to value or diable <0> it]" << endl; cout << " --plot[=profiles] use gnuplot to plot battery and charge graphs" << endl; cout << " and plot the last additional profiles" << endl; cout << " --plotderivations[=profiles] same as above plus standard derivations" << endl; cout << " --import import V0.1 data from current directory" << endl; cout << " --profile enable additional yet unused profiling" << endl; cout << " --noprofile disable additional profiling" << endl; cout << " --credits to everyone contributing to ibam"<=0) show_seconds_left_battery_bios=1; else show_percent_battery_bios=1; } if(show_percent_battery_bios) cout << "Bios percentage: " << data.percent_battery_bios() << " %" << endl; if(show_percent_battery) cout << "Battery percentage: " << data.percent_battery() << " %" << endl; if(show_soft_low_limit && data.get_soft_low_limit()>0) cout << "Soft low percentage limit: " << data.get_soft_low_limit() << " %" << endl; if(show_hard_low_limit && data.get_hard_low_limit()>0) cout << "Hard low percentage limit: " << data.get_hard_low_limit() << " %" << endl; if(show_percent_charge) cout << "Charge percentage: " << data.percent_charge() << " %" << endl; if(show_seconds_left_battery_bios && data.seconds_left_battery_bios()>=0) cout << "Bios time left: " << HMS(data.seconds_left_battery_bios()) << endl; if(show_seconds_left_battery && !do_second_correction) cout << "Battery time left: " << HMS(data.seconds_left_battery()) << endl; if(show_seconds_left_battery && do_second_correction) cout << "Battery time left: " << HMS(data.seconds_left_battery()+data.seconds_battery_correction()) << endl; if(show_seconds_left_battery_adaptive && !do_second_correction) cout << "Adapted battery time left: " << HMS(data.seconds_left_battery_adaptive()) << endl; if(show_seconds_left_battery_adaptive && do_second_correction) cout << "Adapted battery time left: " << HMS(data.seconds_left_battery_adaptive()+data.seconds_battery_correction_adaptive()) << endl; if(show_seconds_left_charge && !do_second_correction) cout << "Charge time left: " << HMS(data.seconds_left_charge()) << endl; if(show_seconds_left_charge && do_second_correction) cout << "Charge time left: " << HMS(data.seconds_left_charge()+data.seconds_charge_correction()) << endl; if(show_seconds_left_charge_adaptive && !do_second_correction) cout << "Adapted charge time left: " << HMS(data.seconds_left_charge_adaptive()) << endl; if(show_seconds_left_charge_adaptive && do_second_correction) cout << "Adapted charge time left: " << HMS(data.seconds_left_charge_adaptive()+data.seconds_charge_correction_adaptive()) << endl; if(show_seconds_battery_total) cout << "Total battery time: " << HMS(data.seconds_battery_total()) << endl; if(show_seconds_battery_total_adaptive) cout << "Adapted total battery time: " << HMS(data.seconds_battery_total_adaptive()) << endl; if(show_seconds_charge_total) cout << "Total charge time: " << HMS(data.seconds_charge_total()) << endl; if(show_seconds_charge_total_adaptive) cout << "Adapted total charge time: " << HMS(data.seconds_charge_total_adaptive()) << endl; if(show_profile_logging) { if(data.profile_logging_setting()) { cout << "Profile logging enabled." << endl; cout << "Current file: " << data.profile_filename( data.current_profile_number(), data.current_profile_type()) << endl; } else cout << "Profile logging disabled." << endl; } if(show_credits) { cout << endl; cout << "Special thanks go to:" << endl << endl; cout << "Mohanty Mitrabhanu for his scientific paper mentioning ibam"<< endl; cout << "Dan Egnor for his sweetcode article" << endl; cout << "Martin Wuertele for the debian port" << endl; cout << "Seth Golub for code improvements" << endl; cout << "Misha Nasledov for the gkrellm2-patch" << endl; cout << "Matthew Richardson for the gentoo support" << endl; cout << "Florian Ragwitz for the PMU support" << endl; cout << "Matthias Grimm for the extended PMU support and pbbuttons.berlios.de" << endl; cout << "Peter Gaal for testing and the APM bugfix" << endl; cout << "Brad Sawatzky for the same APM bugfix" << endl; } return 0; } ibam-0.5.2/CHANGES0000644000324400001440000000236111155244600012132 0ustar sfrusers0.5: o SYSFS support o added hard and soft limits for lowest safe battery percentage o improved seconds correction for ACPI and SYSFS systems o internal changes for improved pbbuttons.berlios.de compatibility o extended PMU support by Matthias Grimm o bugfix of APM support by Brad Sawatzky and Peter Gaal o cosmetic change of krell-strings 0.4: o PMU support for Apple computers by Florian Ragwitz o ACPI support o new improved adaptivity algorithm 0.3: o added "using namespace std" to ibam.hpp o added "make deb" to Makefile o additional profile-logging in .ibam/profile-NNN-battery/charge o plotting of additional profiles o forced same locale on load and save of data o added gkrellm2-support, old gkrellm1-plugin still available 0.2: o prevented continued second counts when battery is fully charged o data from future will now be discarded o prevented second glitches when bios information changed o from now on IBAM will only interpret the bios percentage information o data will now be saved in $HOME/.ibam/ o standard derivation included o import function for old data format o initial krell plugin o initial RPM support o switched from relative to absolute limits in plausibility check (see .hpp) 0.1: o Initial release ibam-0.5.2/REPORT0000644000324400001440000000574411155244600012105 0ustar sfrusersThis is an excerpt of the Project Report "Power Management For Laptops Running Linux: Using Linear Regression To Predict Battery Usage" of Mitrabhanu Mohanty at Texas A&M University. He kindly gave me his permission to publish the part of his report covering the theory behind ibam. In his project he also developed another battery monitor, called monx, which uses a different and also promising battery model. I would like to thank Mitrabhanu Mohanty for the interesting discussions we had and of course for mentioning ibam in the chapter about "Related Work". Sebastian Ritterbusch. -------------------------------------------------------------------------- [...] 2. Related Work Although there are several APM based battery monitoring utilities available [2, 3, 4, 5], most of them simply read the estimates provided by the apmd daemon and display it. Only IBAM uses statistical modeling techniques to improve the accuracy of the values provided by the apmd daemon. The basic idea behind IBAM is to record the time it takes for the charge percentage to move from one value to the other. From this, it calculates the delta changes and the remaining time estimate is determined by the summation of the delta changes. To be a little bit more specific, the underlying assumption in IBAM is that the time needed for a percentage step (T_c) is a continuous random variable with mean t_c and standard deviation d_c. It then uses the fact that the mean of all measured data for a percentage step change (say from 70% to 69%) is converging to the average of the normal distribution (i.e. T_70). Thus, to determine the time taken for the charge percentages to drop from say 70% to 65%, IBAM uses the random variable T = T_70 + T_69 + T_68 + T_67 + T_66 to determine the mean time needed to go from 70% charged to 65% charged. The accuracy of the estimates provided by IBAM depends on several factors. It assumes that the power supplied remains more or less constant with only some random fluctuations in the BIOS measurements. These days almost every laptop has power saving features available, and this introduces complications with the above assumption. In order to counter this, IBAM uses an additional linear model to improve the accuracy. The accuracy of IBAM improves as more data is collected from charging and discharging cycles of the battery. It was found that although the initial predictions of IBAM were almost the same as that provided by the BIOS, they improved considerably after a few charging/discharging cycles. [...] 8. References [...] [1] IBAM, S. Ritterbusch, Available at http://sourceforge.net/projects/ibam/, August 2001. [2] KBatt, J. Orosz, Available at http://sourceforge.net/projects/kbatt/, October 2001. [3] Battstat, J. Pehrson, Available at http://freshmeat.net/projects/battstatapplet/, July 2000. [4] wmapm, M.G. Henderson, Available at http://nis-www.lanl.gov/~mgh/, January 2000. [5] asapm, Tigr, Available at http://freshmeat.net/projects/asapm/, July 1998. [...] ibam-0.5.2/ibam.hpp0000644000324400001440000001517611155244600012570 0ustar sfrusers// IBAM, the Intelligent Battery Monitor // Copyright (C) 2001-2003, Sebastian Ritterbusch (IBAM@Ritterbusch.de) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // #define IBAM_IGNORE_DATA_AFTER_X_SECONDS 3600 #define IBAM_MINIMAL_SECONDS_PER_PERCENT 10 #define IBAM_MAXIMAL_SECONDS_PER_PERCENT 800 #define IBAM_ASSUME_DEFAULT_BATTERY_MIN 120 #define IBAM_MAXIMAL_PROFILES 500 #include #include #include #include #include #include #include #ifdef WITH_IBAM // pbbuttons detection #define NO_LOCALE_H #define NO_MKDIR #endif using namespace std; class battery_status { protected: int acLineStatus; int batteryStatus; int chargeStatus; int remainingBatteryPercent; float remainingBatterySubPercent; int remainingBatteryLifeSeconds; string Path; public: inline int onBattery(void) const; inline int charging(void) const; inline int percent(void) const; inline float subpercent(void) const; inline int seconds(void) const; virtual inline void update(void) = 0; inline battery_status(string path); virtual inline ~battery_status(void); }; class apm_status : public battery_status { public: inline void update(void); inline apm_status(string path="/proc/apm"); }; class pmu_status : public battery_status { public: inline void update(void); inline pmu_status(string path="/proc/pmu"); }; class acpi_status : public battery_status { public: inline void update(void); inline acpi_status(string path="/proc/acpi"); }; class sysfs_status : public battery_status { public: inline void update(void); inline sysfs_status(string path="/sys/class/power_supply/"); }; class percent_data { private: int maxpercents; double *time_for_percent; double *time_deriv_for_percent; int *time_samples; int soft_low_limit,hard_low_limit; inline void size_to(int newpercents); public: inline percent_data(void); inline ~percent_data(void); friend inline ostream & operator <<(ostream & o,const percent_data & a); inline double add_data(int percent,double time_for,int samples=1); inline double average(int a,int b); // average from a to b inline double average_derivation(int a,int b); // standard derivation from a to b inline double add_data(int percent,double time_for,double time_deriv_for,int samples=1); friend inline istream & operator >>(istream & i,percent_data &a); inline istream & import(istream & i); inline double remain(int percent); inline double inverted_remain(int percent); inline double total(void); inline int data_low_limit(void); inline void set_soft_low_limit(int); inline void set_hard_low_limit(int); }; class ibam { private: percent_data data; int data_changed; // 1 if save of ibam.rc demanded battery_status *apm; percent_data battery; int battery_loaded; int battery_changed; percent_data charge; int charge_loaded; int charge_changed; int profile_changed; unsigned long lasttime; int lastpercent; double lastratio; int lastratiocount; int laststatus; double last_sec_per_min; double last_sec_per_min_prediction; unsigned long currenttime; int currentpercent; int currentstatus; string home; int isvalid; int profile_logging; // 1 if cycle shall be logged for later analysis int profile_number; // number of profile (increased on each cycle change) int profile_active; // data has been written to current profile int soft_low_limit; // minimum percentage observed and therefore lowest safe value int hard_low_limit; // minimum percentage found safe by user public: #ifdef NO_MKDIR inline ibam(const string &); #else inline ibam(const string &a=""); #endif inline void import(void); inline void load_battery(void); inline void load_charge(void); inline void update_statistics(void); inline void ignore_statistics(void); inline void save(void); inline string profile_filename(int n,int type) const; inline int current_profile_number(void) const; inline int current_profile_type(void) const; inline void set_profile_logging(int); inline int profile_logging_setting(void) const; inline void set_soft_low_limit(int); inline int get_soft_low_limit(void) const; inline void set_hard_low_limit(int); inline int get_hard_low_limit(void) const; inline int seconds_left_battery_bios(void); inline int seconds_left_battery(void); inline int seconds_left_battery_adaptive(void); inline int percent_battery_bios(void); inline int percent_battery(void); inline int seconds_left_charge(void); inline int seconds_left_charge_adaptive(void); inline int percent_charge(void); inline int seconds_battery_total(void); inline int seconds_battery_total_adaptive(void); inline int seconds_charge_total(void); inline int seconds_charge_total_adaptive(void); inline int seconds_battery_correction(double ratio=1); inline int seconds_charge_correction(double ratio=1); inline int seconds_battery_correction_adaptive(void); inline int seconds_charge_correction_adaptive(void); inline int onBattery(void); inline int charging(void); inline int valid(void) const; inline void update(void); }; #include "ibam.inl" ibam-0.5.2/ibam.inl0000644000324400001440000012006011155244600012550 0ustar sfrusers// IBAM, the Intelligent Battery Monitor // Copyright (C) 2001-2003, Sebastian Ritterbusch (IBAM@Ritterbusch.de) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // #include #include #include #include #include #include #include #include #include #include // for acpi multiple batteries #ifndef NO_LOCALE_H #include // thus I may prevent evil krells to change to others.. #endif #ifndef NO_MKDIR #include // for mkdir #include // for mkdir #endif /* Arguments, with symbols from linux/apm_bios.h. Information is + from the Get Power Status (0x0a) call unless otherwise noted. + + 0) Linux driver version (this will change if format changes) + 1) APM BIOS Version. Usually 1.0 or 1.1. + 2) APM flags from APM Installation Check (0x00): + bit 0: APM_16_BIT_SUPPORT + bit 1: APM_32_BIT_SUPPORT + bit 2: APM_IDLE_SLOWS_CLOCK + bit 3: APM_BIOS_DISABLED + bit 4: APM_BIOS_DISENGAGED + 3) AC line status + 0x00: Off-line + 0x01: On-line + 0x02: On backup power (APM BIOS 1.1 only) + 0xff: Unknown + 4) Battery status + 0x00: High + 0x01: Low + 0x02: Critical + 0x03: Charging + 0xff: Unknown + 5) Battery flag + bit 0: High + bit 1: Low + bit 2: Critical + bit 3: Charging + bit 7: No system battery + 0xff: Unknown + 6) Remaining battery life (percentage of charge): + 0-100: valid + -1: Unknown + 7) Remaining battery life (time units): + Number of remaining minutes or seconds + -1: Unknown + 8) min = minutes; sec = seconds */ inline int battery_status::onBattery(void) const { return acLineStatus==0; } inline int battery_status::charging(void) const { return chargeStatus; } inline int battery_status::percent(void) const { return remainingBatteryPercent; } inline float battery_status::subpercent(void) const { return remainingBatterySubPercent; } inline int battery_status::seconds(void) const { return remainingBatteryLifeSeconds; } inline battery_status::battery_status(string path) { Path = path; remainingBatterySubPercent=-1; } inline battery_status::~battery_status(void) { } inline void battery_status::update(void) { cout << "battery_status::update() called. This should never happen!" << endl; } inline apm_status::apm_status(string path) : battery_status(path) { update(); } inline pmu_status::pmu_status(string path) : battery_status(path) { update(); } inline acpi_status::acpi_status(string path) : battery_status(path) { update(); } inline sysfs_status::sysfs_status(string path) : battery_status(path) { update(); } inline void apm_status::update(void) { ifstream in; int i; in.open(Path.c_str()); for(i=0;i<10 && in.fail();i++) in.open(Path.c_str()); if(in.fail()) { acLineStatus=0; batteryStatus=0; chargeStatus=0; remainingBatteryPercent=-1; remainingBatteryLifeSeconds=-1; return; } string driverVersion, biosVersion; int apmFlags, batteryFlag; char c,d; in >> driverVersion; in >> biosVersion; in >> c >> d; // 0x in >> c >> d; apmFlags=(c>'9'?c-'a'+10:c-'0')*16+(d>'9'?d-'a'+10:d-'0'); in >> c >> d; // 0x in >> c >> d; acLineStatus=(c>'9'?c-'a'+10:c-'0')*16+(d>'9'?d-'a'+10:d-'0'); in >> c >> d; // 0x in >> c >> d; batteryStatus=(c>'9'?c-'a'+10:c-'0')*16+(d>'9'?d-'a'+10:d-'0'); in >> c >> d; // 0x in >> c >> d; batteryFlag=(c>'9'?c-'a'+10:c-'0')*16+(d>'9'?d-'a'+10:d-'0'); chargeStatus = (batteryFlag&8)!=0; in >> remainingBatteryPercent >> c; // % string minsec; in >> remainingBatteryLifeSeconds >> minsec; if(minsec=="min") remainingBatteryLifeSeconds*=60; #ifdef IBAM_DEBUG cout << "Driver Version: " << driverVersion << endl; cout << "Bios Version: " << biosVersion << endl; cout << "APM Flags: " << apmFlags << endl; cout << "AC Line Status: " << acLineStatus << endl; cout << "Battery Status: " << batteryStatus << endl; cout << "Battery Flag: " << batteryFlag << endl; cout << "Remaining Percent: " << remainingBatteryPercent << endl; cout << "Remaining Seconds: " << remainingBatteryLifeSeconds << endl; #endif } // PMU File-format // // 2 batteries, running on battery // // /proc/pmu/info: // // PMU driver version : 2 // PMU firmware version : 0c // AC Power : 0 // Battery count : 2 // // 1) Note that there are systems where AC Power may falsely show 0 if the // computer booted without any batteries plugged in. The battery-flags // are reported to be more reliable in that case. // This is *not* yet taken into account by ibam. // // 2) The battery count only reflects the number of theoretically available // battery slots and not the number of batteries currently in the system. // // /proc/pmu/battery_0: // // flags : 00000011 // charge : 5788 // max_charge : 5789 // current : 0 // voltage : 12549 // time rem. : 0 // // /proc/pmu_battery_1: // // flags : 00000011 // charge : 518 // max_charge : 1112 // current : -1087 // voltage : 11324 // time rem. : 1715 // // case no battery: // // flags : 00000010 // charge : 0 // max_charge : 0 // current : 0 // voltage : 0 // time rem. : 0 // // 1) flags is to be read hexadeicmal (or binary perhaps?), bit 0 // denotes if this battery is present, bit 1 denotes reportingly // rather unreliable a charging state. // // 2) A positive current denotes charging more reliably. (unchecked) // This is *not* yet taken into account, because it's unclear how this // reading behaves with two batteries. // inline void pmu_status::update(void) { ifstream in; int i; in.open((Path+"/info").c_str()); if (in.fail()) { acLineStatus = 0; chargeStatus = 0; remainingBatteryLifeSeconds = -1; remainingBatteryPercent = -1; return; } stringbuf buf; char c; int d, cur_charge = 0, max_charge = 0; for (i = 0; i < 4; i++) { in.get(buf, ':'); in >> c >> d; if (i == 2) acLineStatus = d; } in.close(); in.open((Path+"/battery_0").c_str()); if (in.fail()) { acLineStatus = 0; chargeStatus = 0; remainingBatteryLifeSeconds = -1; remainingBatteryPercent = -1; return; } for (i = 0; i < 6; i++) { in.get(buf, ':'); in >> c >> d; if (i == 0) chargeStatus = (d&2)==0; if (i == 1) cur_charge = d; if (i == 2) max_charge = d; if (i == 5) remainingBatteryLifeSeconds = d; } in.close(); in.open((Path+"/battery_1").c_str()); if (in.fail()) { remainingBatteryPercent = (int)(cur_charge*100/max_charge); return; } for (i = 0; i < 6; i++) { in.get(buf, ':'); in >> c >> d; if (i == 0) chargeStatus = (d&2)==0; if (i == 1) cur_charge += d; if (i == 2) max_charge += d; if (i == 5) remainingBatteryLifeSeconds += d; } remainingBatteryPercent = (int)(cur_charge*100/max_charge); } // Acpi Percentage and Remaining time computation based upon // http://www.acpi.info/spec.htm V3.0 // // [...] // 3.9.3 Battery Gas Gauge // // At the most basic level, the OS calculates Remaining Battery // Percentage [%] using the following formula: // // Battery Remaining Capacity [mAh/mWh] // Remaining Battery Percentage [%] = ------------------------------------ * 100 // Last Full Charged Capacity [mAh/mWh] // // Control Method Battery also reports the Present Drain Rate [mA or mW] // for calculating the remaining battery life. At the most basic level, // Remaining Battery life is calculated by following formula: // // Battery Remaining Capacity [mAh/mWh] // Remaining Battery Life [h] = ------------------------------------ // Battery Present Drain Rate [mA/mW] // // Smart Batteries also report the present rate of drain, but since they // can directly report the estimated runtime, this function should be used // instead as it can more accurately account for variations specific to // the battery // [...] // // I don't have a "Smart Battery", so I don't know, how /proc/acpi would // report that. Contributions are greatly appreciated. // // See also http://www.tldp.org/HOWTO/ACPI-HOWTO/usingacpi.html // inline void acpi_status::update(void) { ifstream in; DIR *acpi_battery_dir; struct dirent *battery_entry; int i; acpi_battery_dir=opendir((Path+"/battery").c_str()); if (acpi_battery_dir==NULL) { acLineStatus = 0; chargeStatus = 0; remainingBatteryLifeSeconds = -1; remainingBatteryPercent = -1; return; } long total_capacity=0; long total_remain=0; long total_rate=0; while ((battery_entry=readdir(acpi_battery_dir))) { if(battery_entry->d_name!=string(".") && battery_entry->d_name!=string("..")) { in.open((((Path+"/battery/")+battery_entry->d_name)+"/info").c_str()); stringbuf buf; char c; int capacity=0; for (i=0; i<3; i++) { in.get(buf, ':'); in >> c; if (i==0) { in >> c; if(c!='y') // present: yes i=3; } else if(i==2) { in >> capacity; total_capacity+=capacity; } } in.close(); #ifdef IBAM_DEBUG cout << "Battery "<d_name<<": Capacity " << capacity; #endif if(capacity) { in.open((((Path+"/battery/")+battery_entry->d_name)+"/state").c_str()); for (i=0; i<5; i++) { in.get(buf, ':'); in >> c; if (i==2) { char d,e,f,g,h; in >> c >> d >> e >> f >> g >> h; // OUCH... #-} Somebody, please fix me if(c=='c' && h=='i') // charging state: charging { acLineStatus=1; batteryStatus=3; chargeStatus=1; #ifdef IBAM_DEBUG cout << " charging"; #endif } else if(c=='d') // charging state: discharge { acLineStatus=0; batteryStatus=0; chargeStatus=0; #ifdef IBAM_DEBUG cout << " discharging"; #endif } else if(c=='c' && h=='e') // charging state: charged { acLineStatus=1; batteryStatus=0; chargeStatus=0; #ifdef IBAM_DEBUG cout << " charged"; #endif } } else if(i==3) { int rate=0; in >> rate; total_rate+=rate; #ifdef IBAM_DEBUG cout << " Rate " << rate; #endif } else if(i==4) { int remain=0; in >> remain; total_remain+=remain; #ifdef IBAM_DEBUG cout << " Remain " << remain; #endif } } in.close(); } // has capacity #ifdef IBAM_DEBUG cout << endl; #endif } } closedir(acpi_battery_dir); if(total_capacity) { remainingBatteryPercent=int((100.*total_remain)/total_capacity+.5); remainingBatterySubPercent=100.*total_remain/total_capacity+.5-remainingBatteryPercent; } else { remainingBatteryPercent=100; remainingBatterySubPercent=0; } if(remainingBatteryPercent>100) { remainingBatteryPercent=100; // Don't ask... remainingBatterySubPercent=0; } if(remainingBatteryPercent<100 && acLineStatus==1 && chargeStatus==0) // Deal with strange Acpi-Data? { // either // acLineStatus=1; // batteryStatus=3; // chargeStatus=1; // or // nothing (or is it just occuring because of late last_full_capacity update?) // or // since it seems it starts at 100% for discharge remainingBatteryPercent=100; remainingBatterySubPercent=0; } if(total_rate) { if(chargeStatus) { remainingBatteryLifeSeconds=((total_capacity-total_remain)*60*60)/total_rate; if(remainingBatteryLifeSeconds<0) remainingBatteryLifeSeconds=0; } else remainingBatteryLifeSeconds=(total_remain*60*60)/total_rate; } else remainingBatteryLifeSeconds=(remainingBatteryPercent*IBAM_ASSUME_DEFAULT_BATTERY_MIN*60)/100; #ifdef IBAM_DEBUG cout << "Remaining percent: " << remainingBatteryPercent << endl; cout << "Remaining battery life seconds: " << remainingBatteryLifeSeconds << endl; #endif } inline void sysfs_status::update(void) { ifstream in; DIR *sysfs_battery_dir; struct dirent *battery_entry; sysfs_battery_dir=opendir((Path).c_str()); if (sysfs_battery_dir==NULL) { acLineStatus = 0; chargeStatus = 0; remainingBatteryLifeSeconds = -1; remainingBatteryPercent = -1; return; } long total_capacity=0; long total_remain=0; long total_rate=0; while ((battery_entry=readdir(sysfs_battery_dir))) { if(battery_entry->d_name!=string(".") && battery_entry->d_name!=string("..")) { in.open((((Path)+battery_entry->d_name)+"/present").c_str()); int present=0,capacity=0,remain=0,rate=0;; if(!in.fail()) { char c; in >> c; if(c=='1') // present { present=1; } } in.close(); if(present) { in.open((((Path)+battery_entry->d_name)+"/charge_full").c_str()); if(!in.fail()) { in>>capacity; total_capacity+=capacity; } in.close(); } if(present && capacity) { in.open((((Path)+battery_entry->d_name)+"/charge_now").c_str()); if(!in.fail()) { in>>remain; total_remain+=remain; } in.close(); } if(present && capacity) { in.open((((Path)+battery_entry->d_name)+"/current_now").c_str()); if(!in.fail()) { in>>rate; total_rate+=rate; } in.close(); } if(present && capacity) { in.open((((Path)+battery_entry->d_name)+"/status").c_str()); if(!in.fail()) { char c;//,d,e,f,g,h; in >> c; // >> d >> e >> f >> g >> h; // OUCH... #-} Somebody, please fix me if(c=='C') // charging state: Charging { acLineStatus=1; batteryStatus=3; chargeStatus=1; } else if(c=='D') // charging state: Discharge { acLineStatus=0; batteryStatus=0; chargeStatus=0; } else if(c=='F') // charging state: Full { acLineStatus=1; batteryStatus=0; chargeStatus=0; } } in.close(); } } } closedir(sysfs_battery_dir); if(total_capacity) { remainingBatteryPercent=int((100.*total_remain)/total_capacity+.5); remainingBatterySubPercent=100.*total_remain/total_capacity+.5-remainingBatteryPercent; } else { remainingBatteryPercent=100; remainingBatterySubPercent=0; } if(remainingBatteryPercent>100) { remainingBatteryPercent=100; // Don't ask... remainingBatterySubPercent=0; } if(remainingBatteryPercent<100 && acLineStatus==1 && chargeStatus==0) // Deal with strange Acpi-Data? { // either // acLineStatus=1; // batteryStatus=3; // chargeStatus=1; // or // nothing (or is it just occuring because of late last_full_capacity update?) // or // since it seems it starts at 100% for discharge remainingBatteryPercent=100; remainingBatterySubPercent=0; } if(total_rate) { if(chargeStatus) { remainingBatteryLifeSeconds=int(((total_capacity-total_remain)*60.*60)/total_rate+.5); if(remainingBatteryLifeSeconds<0) remainingBatteryLifeSeconds=0; } else remainingBatteryLifeSeconds=int((total_remain*60.*60)/total_rate+.5); } else remainingBatteryLifeSeconds=(remainingBatteryPercent*IBAM_ASSUME_DEFAULT_BATTERY_MIN*60)/100; #ifdef IBAM_DEBUG cout << "Remaining percent: " << remainingBatteryPercent << endl; cout << "Remaining battery life seconds: " << remainingBatteryLifeSeconds << endl; #endif } inline void percent_data::size_to(int newpercents) { if(newpercents>=maxpercents) { newpercents++; double *time_for=new double[newpercents]; double *time_deriv=new double[newpercents]; int *samples=new int[newpercents]; int i; for(i=0;i=0;i--) if(a.time_samples[i]) { if(a.time_deriv_for_percent[i]<0) a.time_deriv_for_percent[i]=0; o << i << '\t' << a.time_for_percent[i] << '\t' << sqrt(a.time_deriv_for_percent[i]) << '\t' << a.time_samples[i] << endl; } return o; } inline double percent_data::add_data(int percent,double time_for,int samples) { if(percent<0) return 0; size_to(percent); double ratio; if(time_samples[percent]) ratio=time_for/time_for_percent[percent]; else ratio=time_for/(IBAM_ASSUME_DEFAULT_BATTERY_MIN*60./100.); double old_time_for_percent=time_for_percent[percent]; time_for_percent[percent]= (time_for_percent[percent]*time_samples[percent] +time_for*samples )/(samples+time_samples[percent]); time_deriv_for_percent[percent]= ( (time_deriv_for_percent[percent]+old_time_for_percent*old_time_for_percent)*time_samples[percent] +time_for*time_for*samples )/(samples+time_samples[percent])-time_for_percent[percent]*time_for_percent[percent]; time_samples[percent]+=samples; return ratio; } inline double percent_data::average(int a,int b) // average from a to b { if(a>b) { int c=a;a=b;b=c; } if(a<0) { a=0; if(b<0) b=0; } if(b>=maxpercents) { b=maxpercents-1; if(a>=maxpercents) a=b; } int i; double su(0); int co(0); for(i=a;i<=b;i++) { if(time_samples[i]) { su+=time_for_percent[i]*time_samples[i]; co+=time_samples[i]; } } if(co) return (su/co); int gotdata=0; for(a--,b++;(a>0 || b=maxpercents) b=maxpercents-1; su+=time_for_percent[a]*time_samples[a] +time_for_percent[b]*time_samples[b]; co+=time_samples[a]+time_samples[b]; if(time_samples[a] || time_samples[b]) gotdata++; } if(co) return (su/co); return (IBAM_ASSUME_DEFAULT_BATTERY_MIN*60/100); } inline double percent_data::add_data(int percent,double time_for,double time_deriv_for,int samples) { if(percent<0) return 0; size_to(percent); double ratio; if(time_samples[percent]) ratio=time_for/time_for_percent[percent]; else ratio=time_for/average(percent,percent); double old_time_for_percent=time_for_percent[percent]; time_for_percent[percent]= (time_for_percent[percent]*time_samples[percent] +time_for*samples )/(samples+time_samples[percent]); time_deriv_for_percent[percent]= ( (time_deriv_for_percent[percent]+old_time_for_percent*old_time_for_percent)*time_samples[percent] + (time_deriv_for+time_for*time_for)*samples )/(samples+time_samples[percent])-time_for_percent[percent]*time_for_percent[percent]; time_samples[percent]+=samples; return ratio; } inline istream & operator >>(istream & i,percent_data &a) { #ifndef NO_LOCALE_H setlocale(LC_ALL,"en_US"); #endif while(!i.fail() && !i.eof()) { int percent; double time_for(-1); double time_deriv_for(-1); int samples; i >> percent >> time_for >> time_deriv_for>> samples; if(time_for>=0) a.add_data(percent,time_for,time_deriv_for*time_deriv_for,samples); } return i; } inline istream & percent_data::import(istream & i) { #ifndef NO_LOCALE_H setlocale(LC_ALL,"en_US"); #endif percent_data & a(*this); double maxval=0; while(!i.fail() && !i.eof()) { int val; double time_for(-1); int samples; i >> val >> time_for >> samples; if(val>maxval) maxval=val; if(time_for>=0) a.add_data(int(double(val)/maxval*100+.5),time_for*maxval/100,samples/10+1); } return i; } inline double percent_data::remain(int percent) { double r=0; size_to(percent); int i; for(i=percent;i>0 && i>soft_low_limit && i>hard_low_limit;i--) { if(time_samples[i]) r+=time_for_percent[i]; else { int down=i-15; int up=i+15; if(down<0) down=0; if(up>=maxpercents) up=maxpercents-1; r+=average(down,up); } } return r; } inline double percent_data::inverted_remain(int percent) { double r=0; size_to(percent); int i; for(i=percent+1;i=maxpercents) up=maxpercents-1; r+=average(down,up); } } return r; } inline double percent_data::total(void) { double r=0; int i; for(i=maxpercents-1;i>0 && i>soft_low_limit && i>hard_low_limit;i--) { if(time_samples[i]) r+=time_for_percent[i]; else { int down=i-15; int up=i+15; if(down<0) down=0; if(up>=maxpercents) up=maxpercents-1; r+=average(down,up); } } return r; } inline int percent_data::data_low_limit(void) { int i; for(i=1;i> saveversion; double dummy; if(saveversion==string("0.3")) { in >> lasttime >> lastpercent >> lastratio >> laststatus >> dummy >> dummy >> profile_logging >> profile_number >> profile_active; } if(saveversion==string("0.4")) { in >> lasttime >> lastpercent >> lastratio >> lastratiocount >> laststatus >> profile_logging >> profile_number >> profile_active; } if(saveversion==string("0.5") || saveversion==string("0.5.1") || saveversion==string("0.5.2")) { in >> lasttime >> lastpercent >> lastratio >> lastratiocount >> laststatus >> profile_logging >> profile_number >> profile_active >> soft_low_limit >> hard_low_limit; } else data_changed=1; // force update in.close(); currentpercent=apm->percent(); if(currentpercent!=-1) isvalid=1; currentstatus=apm->onBattery()?1:apm->charging()?2:0; if(currentstatus!=laststatus) { lastratio=1; lastratiocount=1; } } inline void ibam::update(void) { save(); apm->update(); currenttime=time(NULL); currentpercent=apm->percent(); if(currentpercent!=-1) isvalid=1; else isvalid=0; currentstatus=apm->onBattery()?1:apm->charging()?2:0; if(currentstatus!=laststatus) { lastratio=1; lastratiocount=1; } } inline int ibam::valid(void) const { return isvalid; } inline void ibam::import(void) { { ifstream in(".ibam.battery.rc"); battery.import(in); battery_changed=1; } { ifstream in(".ibam.charge.rc"); charge.import(in); charge_changed=1; } } inline void ibam::load_battery(void) { if(!battery_loaded) { ifstream in((home+"/battery.rc").c_str()); in >> battery; if(battery.data_low_limit()<=soft_low_limit) { soft_low_limit=battery.data_low_limit()-1; data_changed=1; } battery.set_soft_low_limit(soft_low_limit); battery.set_hard_low_limit(hard_low_limit); battery_loaded=1; } } inline void ibam::load_charge(void) { if(!charge_loaded) { ifstream in((home+"/charge.rc").c_str()); in >> charge; charge_loaded=1; } } inline void ibam::update_statistics(void) { #ifdef EXPERIMENTAL int remember_current=currentstatus; int remember_last=laststatus; // Many batteries switch to charged state immediatly when hitting 100%, // this way, the 99->100% step never gets recorded. The next lines, check // whether the state has just changed, and assume once, that we are still // charging- this way the last step will be measured. The same applies // when unplugging the power cable. // // The problem is, that this data is highly inaccurate as it is unclear // when ibam ran for the last time- this is not stored as this would lead // to continuous harddisc usage. if( (laststatus==2 && (currentstatus!=1 && currentstatus!=2)) // was charging, then full || ((laststatus!=1 && laststatus!=2) && currentstatus==1) // was full, then on battery ) { if(currentpercent!=lastpercent) // There is data at all... { if(laststatus==2) currentstatus=2; // Assume once that we are still charging if(currentstatus==1) laststatus=1; // Assume once that we just switched to battery } } #endif if(currentstatus==laststatus && currenttime-lasttime=IBAM_MINIMAL_SECONDS_PER_PERCENT && sec_per_min<=IBAM_MAXIMAL_SECONDS_PER_PERCENT) { int i; last_sec_per_min=sec_per_min; last_sec_per_min_prediction=last_av; profile_changed=1; if(lastpercent-currentpercent>lastratiocount) lastratiocount=(lastpercent-currentpercent); for(i=currentpercent;i<=lastpercent;i++) { if(lastratiocount>2 && lastpercent!=100) // Don't trust the first lastratio=(lastratio*lastratiocount+battery.add_data(i,sec_per_min))/(lastratiocount+1); lastratiocount++; } battery_changed=1; data_changed=1; } } else if(currentpercent>lastpercent) // strange data { data_changed=1; // discard if(profile_logging && profile_active) profile_number++; profile_active=0; } break; case 2: // charging if(currentpercent>lastpercent) { load_charge(); double sec_per_min; sec_per_min=(currenttime-lasttime)/double(currentpercent-lastpercent); double last_av=charge.average(lastpercent,currentpercent); if(sec_per_min<=IBAM_MAXIMAL_SECONDS_PER_PERCENT && sec_per_min>=IBAM_MINIMAL_SECONDS_PER_PERCENT) { int i; last_sec_per_min=sec_per_min; last_sec_per_min_prediction=last_av; profile_changed=1; if(currentpercent-lastpercent>lastratiocount) lastratiocount=(currentpercent-lastpercent); for(i=lastpercent;i<=currentpercent;i++) { if(lastratiocount>2) // Don't trust the first lastratio=(lastratio*lastratiocount+1./charge.add_data(i,sec_per_min))/(lastratiocount+1); lastratiocount++; } charge_changed=1; data_changed=1; } } else if(currentpercent=IBAM_IGNORE_DATA_AFTER_X_SECONDS) { if(profile_logging && profile_active) profile_number++; profile_active=0; data_changed=1; } } inline void ibam::ignore_statistics(void) { data_changed=1; } inline string ibam::profile_filename(int n,int type) const { char b[20]; char *status_text[4]={"full","battery","charge",""}; sprintf(b,"profile-%03d-%s",n,status_text[(type&3)]); return (home+"/")+b; } inline int ibam::current_profile_number(void) const { return profile_number; } inline int ibam::current_profile_type(void) const { return currentstatus; } inline void ibam::save(void) { if(profile_changed && profile_logging) { profile_number%=IBAM_MAXIMAL_PROFILES; string filename=profile_filename(profile_number,currentstatus); ofstream out(filename.c_str(),ios::app); out << currentpercent << '\t' << last_sec_per_min << '\t' << last_sec_per_min_prediction << endl; if(profile_active==0) data_changed=1; profile_active=1; profile_changed=0; } if(battery_changed) { ofstream out((home+"/battery.rc").c_str()); out << battery; battery_changed=0; } if(charge_changed) { ofstream out((home+"/charge.rc").c_str()); out << charge; charge_changed=0; } if(data_changed) { ofstream out((home+"/ibam.rc").c_str()); if(currentpercent<=soft_low_limit) soft_low_limit=currentpercent-1; out << IBAM_VERSION << '\t' << currenttime << '\t' << currentpercent << '\t' << lastratio << '\t' << lastratiocount << '\t' << currentstatus << '\t' << profile_logging << '\t' << profile_number << '\t' << profile_active << '\t' << soft_low_limit << '\t' << hard_low_limit << endl; lasttime=currenttime; lastpercent=currentpercent; laststatus=currentstatus; data_changed=0; } } inline void ibam::set_profile_logging(int a) { data_changed|=(a!=profile_logging);profile_logging=a; } inline int ibam::profile_logging_setting(void) const { return profile_logging; } inline void ibam::set_soft_low_limit(int a) { data_changed|=(a!=soft_low_limit);soft_low_limit=a; } inline int ibam::get_soft_low_limit(void) const { return soft_low_limit; } inline void ibam::set_hard_low_limit(int a) { data_changed|=(a!=hard_low_limit);hard_low_limit=a; } inline int ibam::get_hard_low_limit(void) const { return hard_low_limit; } inline int ibam::seconds_left_battery_bios(void) { return apm->seconds(); } inline int ibam::seconds_left_battery(void) { load_battery(); return int(battery.remain(currentpercent)+.5); } inline int ibam::seconds_left_battery_adaptive(void) { load_battery(); return int(battery.remain(currentpercent)*lastratio+.5); } inline int ibam::percent_battery_bios(void) { return apm->percent(); } inline int ibam::percent_battery(void) { load_battery(); return int((100.*seconds_left_battery())/battery.total()+.5); } inline int ibam::seconds_left_charge(void) { load_charge(); return int(charge.inverted_remain(currentpercent)+.5); } inline int ibam::seconds_left_charge_adaptive(void) { load_charge(); return int(charge.inverted_remain(currentpercent)/lastratio+.5); } inline int ibam::percent_charge(void) { load_charge(); return 100-int((100.*seconds_left_charge())/charge.total()+.5); } inline int ibam::seconds_battery_total(void) { load_battery(); return int(battery.total()+.5); } inline int ibam::seconds_battery_total_adaptive(void){ load_battery(); return int(battery.total()*lastratio+.5); } inline int ibam::seconds_charge_total(void) { load_charge(); return int(charge.total()+.5); } inline int ibam::seconds_charge_total_adaptive(void) { load_charge(); return int(charge.total()/lastratio+.5); } inline int ibam::seconds_battery_correction_adaptive(void) { return seconds_battery_correction(lastratio); } inline int ibam::seconds_battery_correction(double ratio) { if(currentstatus!=laststatus || currentstatus==0 || lastpercent!=currentpercent) return 0; if(currentstatus==1) { if(apm->subpercent()!=-1) { load_battery(); float v=apm->subpercent(); return -int((1-apm->subpercent())*battery.average(currentpercent,currentpercent)*ratio*(1-v)+(currenttime-lasttime)*v+.5); } return lasttime-currenttime; } load_battery(); load_charge(); return int((currenttime-lasttime)*(battery.average(currentpercent-1,currentpercent+1)/charge.average(currentpercent-1,currentpercent+1))+.5); } inline int ibam::seconds_charge_correction_adaptive(void) { return seconds_charge_correction(lastratio); } inline int ibam::seconds_charge_correction(double ratio) { if(currentstatus!=laststatus || currentstatus==0 || lastpercent!=currentpercent) return 0; if(currentstatus==2) { if(apm->subpercent()!=-1) { load_battery(); float v=1-apm->subpercent(); return -int((apm->subpercent())*charge.average(currentpercent,currentpercent)/ratio*(1-v)+(currenttime-lasttime)*v+.5); } return lasttime-currenttime; } load_battery(); load_charge(); return int((currenttime-lasttime)/(battery.average(currentpercent-1,currentpercent+1)/charge.average(currentpercent-1,currentpercent+1))+.5); } inline int ibam::onBattery(void) { return apm->onBattery(); } inline int ibam::charging(void) { return apm->charging(); } inline double percent_data::average_derivation(int a,int b) // average standard derivation from a to b { if(a>b) { int c=a;a=b;b=c; } if(a<0) { a=0; if(b<0) b=0; } if(b>=maxpercents) { b=maxpercents-1; if(a>=maxpercents) a=b; } int i; double su(0); int co(0); for(i=a;i<=b;i++) { if(time_samples[i]) { if(time_deriv_for_percent[i]>0) su+=sqrt(time_deriv_for_percent[i])*time_samples[i]; co+=time_samples[i]; } } if(co) return (su/co); int gotdata=0; for(a--,b++;(a>0 || b=maxpercents) b=maxpercents-1; if(time_deriv_for_percent[a]>0 && time_samples[a]) su+=sqrt(time_deriv_for_percent[a])*time_samples[a]; if(time_deriv_for_percent[b]>0 && time_samples[b]) su+=sqrt(time_deriv_for_percent[b])*time_samples[b]; co+=time_samples[a]+time_samples[b]; if(time_samples[a] || time_samples[b]) gotdata++; } if(co) return (su/co); return 20; }