~ubuntu-branches/ubuntu/vivid/upower/vivid-proposed

« back to all changes in this revision

Viewing changes to .pc/00git_updates.patch/src/up-history.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2013-10-08 18:26:25 UTC
  • mfrom: (1.5.4)
  • Revision ID: package-import@ubuntu.com-20131008182625-afgb0c8beb0ot1yf
Tags: 0.9.22-1
* New upstream release.
* Drop 00git_updates.patch, included in new release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2
 
 *
3
 
 * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
4
 
 *
5
 
 * Licensed under the GNU General Public License Version 2
6
 
 *
7
 
 * This program is free software; you can redistribute it and/or modify
8
 
 * it under the terms of the GNU General Public License as published by
9
 
 * the Free Software Foundation; either version 2 of the License, or
10
 
 * (at your option) any later version.
11
 
 *
12
 
 * This program is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
 * GNU General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU General Public License
18
 
 * along with this program; if not, write to the Free Software
19
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
 
 */
21
 
 
22
 
#include "config.h"
23
 
 
24
 
#include <stdlib.h>
25
 
#include <stdio.h>
26
 
#include <math.h>
27
 
#include <glib/gi18n.h>
28
 
#include <gio/gio.h>
29
 
 
30
 
#include "up-history.h"
31
 
#include "up-stats-item.h"
32
 
#include "up-history-item.h"
33
 
 
34
 
static void     up_history_finalize     (GObject                *object);
35
 
 
36
 
#define UP_HISTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UP_TYPE_HISTORY, UpHistoryPrivate))
37
 
 
38
 
#define UP_HISTORY_FILE_HEADER          "PackageKit Profile"
39
 
#define UP_HISTORY_SAVE_INTERVAL        (10*60)         /* seconds */
40
 
#define UP_HISTORY_DEFAULT_MAX_DATA_AGE (7*24*60*60)    /* seconds */
41
 
 
42
 
struct UpHistoryPrivate
43
 
{
44
 
        gchar                   *id;
45
 
        gdouble                  rate_last;
46
 
        gint64                   time_full_last;
47
 
        gint64                   time_empty_last;
48
 
        gdouble                  percentage_last;
49
 
        UpDeviceState            state;
50
 
        GPtrArray               *data_rate;
51
 
        GPtrArray               *data_charge;
52
 
        GPtrArray               *data_time_full;
53
 
        GPtrArray               *data_time_empty;
54
 
        guint                    save_id;
55
 
        guint                    max_data_age;
56
 
        gchar                   *dir;
57
 
};
58
 
 
59
 
enum {
60
 
        UP_HISTORY_PROGRESS,
61
 
        UP_HISTORY_LAST_SIGNAL
62
 
};
63
 
 
64
 
G_DEFINE_TYPE (UpHistory, up_history, G_TYPE_OBJECT)
65
 
 
66
 
/**
67
 
 * up_history_set_max_data_age:
68
 
 **/
69
 
void
70
 
up_history_set_max_data_age (UpHistory *history, guint max_data_age)
71
 
{
72
 
        history->priv->max_data_age = max_data_age;
73
 
}
74
 
 
75
 
/**
76
 
 * up_history_array_copy_cb:
77
 
 **/
78
 
static void
79
 
up_history_array_copy_cb (UpHistoryItem *item, GPtrArray *dest)
80
 
{
81
 
        g_ptr_array_add (dest, g_object_ref (item));
82
 
}
83
 
 
84
 
/**
85
 
 * up_history_array_limit_resolution:
86
 
 * @array: The data we have for a specific graph
87
 
 * @max_num: The max desired points
88
 
 *
89
 
 * We need to reduce the number of data points else the graph will take a long
90
 
 * time to plot accuracy we don't need at the larger scales.
91
 
 * This will not reduce the scale or range of the data.
92
 
 *
93
 
 *  100  +     + |  +   |  +   | +     +
94
 
 *       |  A    |      |      |
95
 
 *   80  +     + |  +   |  +   | +     +
96
 
 *       |       | B  C |      |
97
 
 *   60  +     + |  +   |  +   | +     +
98
 
 *       |       |      |      |
99
 
 *   40  +     + |  +   |  +   | + E   +
100
 
 *       |       |      |      | D
101
 
 *   20  +     + |  +   |  +   | +   F +
102
 
 *       |       |      |      |
103
 
 *    0  +-----+-----+-----+-----+-----+
104
 
 *            20    40    60    80   100
105
 
 *
106
 
 * A = 15,90
107
 
 * B = 30,70
108
 
 * C = 52,70
109
 
 * D = 80,30
110
 
 * E = 85,40
111
 
 * F = 90,20
112
 
 *
113
 
 * 1 = 15,90
114
 
 * 2 = 41,70
115
 
 * 3 = 85,30
116
 
 **/
117
 
static GPtrArray *
118
 
up_history_array_limit_resolution (GPtrArray *array, guint max_num)
119
 
{
120
 
        UpHistoryItem *item;
121
 
        UpHistoryItem *item_new;
122
 
        gfloat division;
123
 
        guint length;
124
 
        gint i;
125
 
        guint last;
126
 
        guint first;
127
 
        GPtrArray *new;
128
 
        UpDeviceState state = UP_DEVICE_STATE_UNKNOWN;
129
 
        guint64 time_s = 0;
130
 
        gdouble value = 0;
131
 
        guint64 count = 0;
132
 
        guint step = 1;
133
 
        gfloat preset;
134
 
 
135
 
        new = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
136
 
        g_debug ("length of array (before) %i", array->len);
137
 
 
138
 
        /* check length */
139
 
        length = array->len;
140
 
        if (length == 0)
141
 
                goto out;
142
 
        if (length < max_num) {
143
 
                /* need to copy array */
144
 
                g_ptr_array_foreach (array, (GFunc) up_history_array_copy_cb, new);
145
 
                goto out;
146
 
        }
147
 
 
148
 
        /* last element */
149
 
        item = (UpHistoryItem *) g_ptr_array_index (array, length-1);
150
 
        last = up_history_item_get_time (item);
151
 
        item = (UpHistoryItem *) g_ptr_array_index (array, 0);
152
 
        first = up_history_item_get_time (item);
153
 
 
154
 
        division = (first - last) / (gfloat) max_num;
155
 
        g_debug ("Using a x division of %f (first=%i,last=%i)", division, first, last);
156
 
 
157
 
        /* Reduces the number of points to a pre-set level using a time
158
 
         * division algorithm so we don't keep diluting the previous
159
 
         * data with a conventional 1-in-x type algorithm. */
160
 
        for (i=length-1; i>=0; i--) {
161
 
                item = (UpHistoryItem *) g_ptr_array_index (array, i);
162
 
                preset = last + (division * (gfloat) step);
163
 
 
164
 
                /* if state changed or we went over the preset do a new point */
165
 
                if (count > 0 &&
166
 
                    (up_history_item_get_time (item) > preset ||
167
 
                     up_history_item_get_state (item) != state)) {
168
 
                        item_new = up_history_item_new ();
169
 
                        up_history_item_set_time (item_new, time_s / count);
170
 
                        up_history_item_set_value (item_new, value / count);
171
 
                        up_history_item_set_state (item_new, state);
172
 
                        g_ptr_array_add (new, item_new);
173
 
 
174
 
                        step++;
175
 
                        time_s = up_history_item_get_time (item);
176
 
                        value = up_history_item_get_value (item);
177
 
                        state = up_history_item_get_state (item);
178
 
                        count = 1;
179
 
                } else {
180
 
                        count++;
181
 
                        time_s += up_history_item_get_time (item);
182
 
                        value += up_history_item_get_value (item);
183
 
                }
184
 
        }
185
 
 
186
 
        /* only add if nonzero */
187
 
        if (count > 0) {
188
 
                item_new = up_history_item_new ();
189
 
                up_history_item_set_time (item_new, time_s / count);
190
 
                up_history_item_set_value (item_new, value / count);
191
 
                up_history_item_set_state (item_new, state);
192
 
                g_ptr_array_add (new, item_new);
193
 
        }
194
 
 
195
 
        /* check length */
196
 
        g_debug ("length of array (after) %i", new->len);
197
 
out:
198
 
        return new;
199
 
}
200
 
 
201
 
/**
202
 
 * up_history_copy_array_timespan:
203
 
 **/
204
 
static GPtrArray *
205
 
up_history_copy_array_timespan (const GPtrArray *array, guint timespan)
206
 
{
207
 
        guint i;
208
 
        UpHistoryItem *item;
209
 
        GPtrArray *array_new;
210
 
        GTimeVal timeval;
211
 
 
212
 
        /* no data */
213
 
        if (array->len == 0)
214
 
                return NULL;
215
 
 
216
 
        /* no limit on data */
217
 
        if (timespan == 0) {
218
 
                array_new = g_ptr_array_ref ((GPtrArray *) array);
219
 
                goto out;
220
 
        }
221
 
 
222
 
        /* new data */
223
 
        array_new = g_ptr_array_new ();
224
 
        g_get_current_time (&timeval);
225
 
        g_debug ("limiting data to last %i seconds", timespan);
226
 
 
227
 
        /* treat the timespan like a range, and search backwards */
228
 
        timespan *= 0.95f;
229
 
        for (i=array->len-1; i>0; i--) {
230
 
                item = (UpHistoryItem *) g_ptr_array_index (array, i);
231
 
                if (timeval.tv_sec - up_history_item_get_time (item) < timespan)
232
 
                        g_ptr_array_add (array_new, g_object_ref (item));
233
 
        }
234
 
out:
235
 
        return array_new;
236
 
}
237
 
 
238
 
/**
239
 
 * up_history_get_data:
240
 
 **/
241
 
GPtrArray *
242
 
up_history_get_data (UpHistory *history, UpHistoryType type, guint timespan, guint resolution)
243
 
{
244
 
        GPtrArray *array;
245
 
        GPtrArray *array_resolution;
246
 
        const GPtrArray *array_data = NULL;
247
 
 
248
 
        g_return_val_if_fail (UP_IS_HISTORY (history), NULL);
249
 
 
250
 
        if (history->priv->id == NULL)
251
 
                return NULL;
252
 
 
253
 
        if (type == UP_HISTORY_TYPE_CHARGE)
254
 
                array_data = history->priv->data_charge;
255
 
        else if (type == UP_HISTORY_TYPE_RATE)
256
 
                array_data = history->priv->data_rate;
257
 
        else if (type == UP_HISTORY_TYPE_TIME_FULL)
258
 
                array_data = history->priv->data_time_full;
259
 
        else if (type == UP_HISTORY_TYPE_TIME_EMPTY)
260
 
                array_data = history->priv->data_time_empty;
261
 
 
262
 
        /* not recognised */
263
 
        if (array_data == NULL)
264
 
                return NULL;
265
 
 
266
 
        /* only return a certain time */
267
 
        array = up_history_copy_array_timespan (array_data, timespan);
268
 
        if (array == NULL)
269
 
                return NULL;
270
 
 
271
 
        /* only add a certain number of points */
272
 
        array_resolution = up_history_array_limit_resolution (array, resolution);
273
 
        g_ptr_array_unref (array);
274
 
 
275
 
        return array_resolution;
276
 
}
277
 
 
278
 
/**
279
 
 * up_history_get_profile_data:
280
 
 **/
281
 
GPtrArray *
282
 
up_history_get_profile_data (UpHistory *history, gboolean charging)
283
 
{
284
 
        guint i;
285
 
        guint non_zero_accuracy = 0;
286
 
        gfloat average = 0.0f;
287
 
        guint bin;
288
 
        guint oldbin = 999;
289
 
        UpHistoryItem *item_last = NULL;
290
 
        UpHistoryItem *item;
291
 
        UpHistoryItem *item_old = NULL;
292
 
        UpStatsItem *stats;
293
 
        GPtrArray *array;
294
 
        GPtrArray *data;
295
 
        guint time_s;
296
 
        gdouble value;
297
 
        gdouble total_value = 0.0f;
298
 
 
299
 
        g_return_val_if_fail (UP_IS_HISTORY (history), NULL);
300
 
 
301
 
        /* create 100 item list and set to zero */
302
 
        data = g_ptr_array_new ();
303
 
        for (i=0; i<101; i++) {
304
 
                stats = up_stats_item_new ();
305
 
                g_ptr_array_add (data, stats);
306
 
        }
307
 
 
308
 
        array = history->priv->data_charge;
309
 
        for (i=0; i<array->len; i++) {
310
 
                item = (UpHistoryItem *) g_ptr_array_index (array, i);
311
 
                if (item_last == NULL ||
312
 
                    up_history_item_get_state (item) != up_history_item_get_state (item_last)) {
313
 
                        item_old = NULL;
314
 
                        goto cont;
315
 
                }
316
 
 
317
 
                /* round to the nearest int */
318
 
                bin = rint (up_history_item_get_value (item));
319
 
 
320
 
                /* ensure bin is in range */
321
 
                if (bin >= data->len)
322
 
                        bin = data->len - 1;
323
 
 
324
 
                /* different */
325
 
                if (oldbin != bin) {
326
 
                        oldbin = bin;
327
 
                        if (item_old != NULL) {
328
 
                                /* not enough or too much difference */
329
 
                                value = fabs (up_history_item_get_value (item) - up_history_item_get_value (item_old));
330
 
                                if (value < 0.01f) {
331
 
                                        item_old = NULL;
332
 
                                        goto cont;
333
 
                                }
334
 
                                if (value > 3.0f) {
335
 
                                        item_old = NULL;
336
 
                                        goto cont;
337
 
                                }
338
 
 
339
 
                                time_s = up_history_item_get_time (item) - up_history_item_get_time (item_old);
340
 
                                /* use the accuracy field as a counter for now */
341
 
                                if ((charging && up_history_item_get_state (item) == UP_DEVICE_STATE_CHARGING) ||
342
 
                                    (!charging && up_history_item_get_state (item) == UP_DEVICE_STATE_DISCHARGING)) {
343
 
                                        stats = (UpStatsItem *) g_ptr_array_index (data, bin);
344
 
                                        up_stats_item_set_value (stats, up_stats_item_get_value (stats) + time_s);
345
 
                                        up_stats_item_set_accuracy (stats, up_stats_item_get_accuracy (stats) + 1);
346
 
                                }
347
 
                        }
348
 
                        item_old = item;
349
 
                }
350
 
cont:
351
 
                item_last = item;
352
 
        }
353
 
 
354
 
        /* divide the value by the number of samples to make the average */
355
 
        for (i=0; i<101; i++) {
356
 
                stats = (UpStatsItem *) g_ptr_array_index (data, i);
357
 
                if (up_stats_item_get_accuracy (stats) != 0)
358
 
                        up_stats_item_set_value (stats, up_stats_item_get_value (stats) / up_stats_item_get_accuracy (stats));
359
 
        }
360
 
 
361
 
        /* find non-zero accuracy values for the average */
362
 
        for (i=0; i<101; i++) {
363
 
                stats = (UpStatsItem *) g_ptr_array_index (data, i);
364
 
                if (up_stats_item_get_accuracy (stats) > 0) {
365
 
                        total_value += up_stats_item_get_value (stats);
366
 
                        non_zero_accuracy++;
367
 
                }
368
 
        }
369
 
 
370
 
        /* average */
371
 
        if (non_zero_accuracy != 0)
372
 
                average = total_value / non_zero_accuracy;
373
 
        g_debug ("average is %f", average);
374
 
 
375
 
        /* make the values a factor of 0, so that 1.0 is twice the
376
 
         * average, and -1.0 is half the average */
377
 
        for (i=0; i<101; i++) {
378
 
                stats = (UpStatsItem *) g_ptr_array_index (data, i);
379
 
                if (up_stats_item_get_accuracy (stats) > 0)
380
 
                        up_stats_item_set_value (stats, (up_stats_item_get_value (stats) - average) / average);
381
 
                else
382
 
                        up_stats_item_set_value (stats, 0.0f);
383
 
        }
384
 
 
385
 
        /* accuracy is a percentage scale, where each cycle = 20% */
386
 
        for (i=0; i<101; i++) {
387
 
                stats = (UpStatsItem *) g_ptr_array_index (data, i);
388
 
                up_stats_item_set_accuracy (stats, up_stats_item_get_accuracy (stats) * 20.0f);
389
 
        }
390
 
 
391
 
        return data;
392
 
}
393
 
 
394
 
/**
395
 
 * up_history_get_filename:
396
 
 **/
397
 
static gchar *
398
 
up_history_get_filename (UpHistory *history, const gchar *type)
399
 
{
400
 
        gchar *path;
401
 
        gchar *filename;
402
 
 
403
 
        filename = g_strdup_printf ("history-%s-%s.dat", type, history->priv->id);
404
 
        path = g_build_filename (history->priv->dir, filename, NULL);
405
 
        g_free (filename);
406
 
        return path;
407
 
}
408
 
 
409
 
/**
410
 
 * up_history_set_directory:
411
 
 **/
412
 
void
413
 
up_history_set_directory (UpHistory *history, const gchar *dir)
414
 
{
415
 
        g_free (history->priv->dir);
416
 
        history->priv->dir = g_strdup (dir);
417
 
}
418
 
 
419
 
/**
420
 
 * up_history_array_to_file:
421
 
 * @list: a valid #GPtrArray instance
422
 
 * @filename: a filename
423
 
 *
424
 
 * Saves a copy of the list to a file
425
 
 **/
426
 
static gboolean
427
 
up_history_array_to_file (UpHistory *history, GPtrArray *list, const gchar *filename)
428
 
{
429
 
        guint i;
430
 
        UpHistoryItem *item;
431
 
        gchar *part;
432
 
        GString *string;
433
 
        gboolean ret = TRUE;
434
 
        GError *error = NULL;
435
 
        GTimeVal time_now;
436
 
        guint time_item;
437
 
        guint cull_count = 0;
438
 
 
439
 
        /* get current time */
440
 
        g_get_current_time (&time_now);
441
 
 
442
 
        /* generate data */
443
 
        string = g_string_new ("");
444
 
        for (i=0; i<list->len; i++) {
445
 
                item = g_ptr_array_index (list, i);
446
 
 
447
 
                /* only save entries for the last 24 hours */
448
 
                time_item = up_history_item_get_time (item);
449
 
                if (time_now.tv_sec - time_item > history->priv->max_data_age) {
450
 
                        cull_count++;
451
 
                        continue;
452
 
                }
453
 
                part = up_history_item_to_string (item);
454
 
                if (part == NULL) {
455
 
                        ret = FALSE;
456
 
                        break;
457
 
                }
458
 
                g_string_append_printf (string, "%s\n", part);
459
 
                g_free (part);
460
 
        }
461
 
        part = g_string_free (string, FALSE);
462
 
 
463
 
        /* how many did we kill? */
464
 
        g_debug ("culled %i of %i", cull_count, list->len);
465
 
 
466
 
        /* we failed to convert to string */
467
 
        if (!ret) {
468
 
                g_warning ("failed to convert");
469
 
                goto out;
470
 
        }
471
 
 
472
 
        /* save to disk */
473
 
        ret = g_file_set_contents (filename, part, -1, &error);
474
 
        if (!ret) {
475
 
                g_warning ("failed to set data: %s", error->message);
476
 
                g_error_free (error);
477
 
                goto out;
478
 
        }
479
 
        g_debug ("saved %s", filename);
480
 
 
481
 
out:
482
 
        g_free (part);
483
 
        return ret;
484
 
}
485
 
 
486
 
/**
487
 
 * up_history_array_from_file:
488
 
 * @list: a valid #GPtrArray instance
489
 
 * @filename: a filename
490
 
 *
491
 
 * Appends the list from a file
492
 
 **/
493
 
static gboolean
494
 
up_history_array_from_file (GPtrArray *list, const gchar *filename)
495
 
{
496
 
        gboolean ret;
497
 
        GError *error = NULL;
498
 
        gchar *data = NULL;
499
 
        gchar **parts = NULL;
500
 
        guint i;
501
 
        guint length;
502
 
        UpHistoryItem *item;
503
 
 
504
 
        /* do we exist */
505
 
        ret = g_file_test (filename, G_FILE_TEST_EXISTS);
506
 
        if (!ret) {
507
 
                g_debug ("failed to get data from %s as file does not exist", filename);
508
 
                goto out;
509
 
        }
510
 
 
511
 
        /* get contents */
512
 
        ret = g_file_get_contents (filename, &data, NULL, &error);
513
 
        if (!ret) {
514
 
                g_warning ("failed to get data: %s", error->message);
515
 
                g_error_free (error);
516
 
                goto out;
517
 
        }
518
 
 
519
 
        /* split by line ending */
520
 
        parts = g_strsplit (data, "\n", 0);
521
 
        length = g_strv_length (parts);
522
 
        if (length == 0) {
523
 
                g_debug ("no data in %s", filename);
524
 
                goto out;
525
 
        }
526
 
 
527
 
        /* add valid entries */
528
 
        g_debug ("loading %i items of data from %s", length, filename);
529
 
        for (i=0; i<length-1; i++) {
530
 
                item = up_history_item_new ();
531
 
                ret = up_history_item_set_from_string (item, parts[i]);
532
 
                if (ret)
533
 
                        g_ptr_array_add (list, item);
534
 
        }
535
 
 
536
 
out:
537
 
        g_strfreev (parts);
538
 
        g_free (data);
539
 
        return ret;
540
 
}
541
 
 
542
 
/**
543
 
 * up_history_save_data:
544
 
 **/
545
 
gboolean
546
 
up_history_save_data (UpHistory *history)
547
 
{
548
 
        gboolean ret = FALSE;
549
 
        gchar *filename_rate = NULL;
550
 
        gchar *filename_charge = NULL;
551
 
        gchar *filename_time_full = NULL;
552
 
        gchar *filename_time_empty = NULL;
553
 
 
554
 
        /* we have an ID? */
555
 
        if (history->priv->id == NULL) {
556
 
                g_warning ("no ID, cannot save");
557
 
                goto out;
558
 
        }
559
 
 
560
 
        /* get filenames */
561
 
        filename_rate = up_history_get_filename (history, "rate");
562
 
        filename_charge = up_history_get_filename (history, "charge");
563
 
        filename_time_full = up_history_get_filename (history, "time-full");
564
 
        filename_time_empty = up_history_get_filename (history, "time-empty");
565
 
 
566
 
        /* save to disk */
567
 
        ret = up_history_array_to_file (history, history->priv->data_rate, filename_rate);
568
 
        if (!ret)
569
 
                goto out;
570
 
        ret = up_history_array_to_file (history, history->priv->data_charge, filename_charge);
571
 
        if (!ret)
572
 
                goto out;
573
 
        ret = up_history_array_to_file (history, history->priv->data_time_full, filename_time_full);
574
 
        if (!ret)
575
 
                goto out;
576
 
        ret = up_history_array_to_file (history, history->priv->data_time_empty, filename_time_empty);
577
 
        if (!ret)
578
 
                goto out;
579
 
out:
580
 
        g_free (filename_rate);
581
 
        g_free (filename_charge);
582
 
        g_free (filename_time_full);
583
 
        g_free (filename_time_empty);
584
 
        return ret;
585
 
}
586
 
 
587
 
/**
588
 
 * up_history_schedule_save_cb:
589
 
 **/
590
 
static gboolean
591
 
up_history_schedule_save_cb (UpHistory *history)
592
 
{
593
 
        up_history_save_data (history);
594
 
        history->priv->save_id = 0;
595
 
        return FALSE;
596
 
}
597
 
 
598
 
/**
599
 
 * up_history_is_low_power:
600
 
 **/
601
 
static gboolean
602
 
up_history_is_low_power (UpHistory *history)
603
 
{
604
 
        guint length;
605
 
        UpHistoryItem *item;
606
 
 
607
 
        /* current status is always up to date */
608
 
        if (history->priv->state != UP_DEVICE_STATE_DISCHARGING)
609
 
                return FALSE;
610
 
 
611
 
        /* have we got any data? */
612
 
        length = history->priv->data_charge->len;
613
 
        if (length == 0)
614
 
                return FALSE;
615
 
 
616
 
        /* get the last saved charge object */
617
 
        item = (UpHistoryItem *) g_ptr_array_index (history->priv->data_charge, length-1);
618
 
        if (up_history_item_get_state (item) != UP_DEVICE_STATE_DISCHARGING)
619
 
                return FALSE;
620
 
 
621
 
        /* high enough */
622
 
        if (up_history_item_get_value (item) > 10)
623
 
                return FALSE;
624
 
 
625
 
        /* we are low power */
626
 
        return TRUE;
627
 
}
628
 
 
629
 
/**
630
 
 * up_history_schedule_save:
631
 
 **/
632
 
static gboolean
633
 
up_history_schedule_save (UpHistory *history)
634
 
{
635
 
        gboolean ret;
636
 
 
637
 
        /* if low power, then don't batch up save requests */
638
 
        ret = up_history_is_low_power (history);
639
 
        if (ret) {
640
 
                g_debug ("saving directly to disk as low power");
641
 
                up_history_save_data (history);
642
 
                return TRUE;
643
 
        }
644
 
 
645
 
        /* we already have one saved */
646
 
        if (history->priv->save_id != 0) {
647
 
                g_debug ("deferring as others queued");
648
 
                return TRUE;
649
 
        }
650
 
 
651
 
        /* nothing scheduled, do new */
652
 
        g_debug ("saving in %i seconds", UP_HISTORY_SAVE_INTERVAL);
653
 
        history->priv->save_id = g_timeout_add_seconds (UP_HISTORY_SAVE_INTERVAL,
654
 
                                                        (GSourceFunc) up_history_schedule_save_cb, history);
655
 
#if GLIB_CHECK_VERSION(2,25,8)
656
 
        g_source_set_name_by_id (history->priv->save_id, "[UpHistory] save");
657
 
#endif
658
 
        return TRUE;
659
 
}
660
 
 
661
 
/**
662
 
 * up_history_load_data:
663
 
 **/
664
 
static gboolean
665
 
up_history_load_data (UpHistory *history)
666
 
{
667
 
        gchar *filename;
668
 
        UpHistoryItem *item;
669
 
 
670
 
        /* load rate history from disk */
671
 
        filename = up_history_get_filename (history, "rate");
672
 
        up_history_array_from_file (history->priv->data_rate, filename);
673
 
        g_free (filename);
674
 
 
675
 
        /* load charge history from disk */
676
 
        filename = up_history_get_filename (history, "charge");
677
 
        up_history_array_from_file (history->priv->data_charge, filename);
678
 
        g_free (filename);
679
 
 
680
 
        /* load charge history from disk */
681
 
        filename = up_history_get_filename (history, "time-full");
682
 
        up_history_array_from_file (history->priv->data_time_full, filename);
683
 
        g_free (filename);
684
 
 
685
 
        /* load charge history from disk */
686
 
        filename = up_history_get_filename (history, "time-empty");
687
 
        up_history_array_from_file (history->priv->data_time_empty, filename);
688
 
        g_free (filename);
689
 
 
690
 
        /* save a marker so we don't use incomplete percentages */
691
 
        item = up_history_item_new ();
692
 
        up_history_item_set_time_to_present (item);
693
 
        g_ptr_array_add (history->priv->data_rate, g_object_ref (item));
694
 
        g_ptr_array_add (history->priv->data_charge, g_object_ref (item));
695
 
        g_ptr_array_add (history->priv->data_time_full, g_object_ref (item));
696
 
        g_ptr_array_add (history->priv->data_time_empty, g_object_ref (item));
697
 
        g_object_unref (item);
698
 
        up_history_schedule_save (history);
699
 
 
700
 
        return TRUE;
701
 
}
702
 
 
703
 
/**
704
 
 * up_history_set_id:
705
 
 **/
706
 
gboolean
707
 
up_history_set_id (UpHistory *history, const gchar *id)
708
 
{
709
 
        gboolean ret;
710
 
 
711
 
        g_return_val_if_fail (UP_IS_HISTORY (history), FALSE);
712
 
 
713
 
        if (history->priv->id != NULL)
714
 
                return FALSE;
715
 
        if (id == NULL)
716
 
                return FALSE;
717
 
 
718
 
        g_debug ("using id: %s", id);
719
 
        history->priv->id = g_strdup (id);
720
 
        /* load all previous data */
721
 
        ret = up_history_load_data (history);
722
 
        return ret;
723
 
}
724
 
 
725
 
/**
726
 
 * up_history_set_state:
727
 
 **/
728
 
gboolean
729
 
up_history_set_state (UpHistory *history, UpDeviceState state)
730
 
{
731
 
        g_return_val_if_fail (UP_IS_HISTORY (history), FALSE);
732
 
 
733
 
        if (history->priv->id == NULL)
734
 
                return FALSE;
735
 
        history->priv->state = state;
736
 
        return TRUE;
737
 
}
738
 
 
739
 
/**
740
 
 * up_history_set_charge_data:
741
 
 **/
742
 
gboolean
743
 
up_history_set_charge_data (UpHistory *history, gdouble percentage)
744
 
{
745
 
        UpHistoryItem *item;
746
 
 
747
 
        g_return_val_if_fail (UP_IS_HISTORY (history), FALSE);
748
 
 
749
 
        if (history->priv->id == NULL)
750
 
                return FALSE;
751
 
        if (history->priv->state == UP_DEVICE_STATE_UNKNOWN)
752
 
                return FALSE;
753
 
        if (history->priv->percentage_last == percentage)
754
 
                return FALSE;
755
 
 
756
 
        /* add to array and schedule save file */
757
 
        item = up_history_item_new ();
758
 
        up_history_item_set_time_to_present (item);
759
 
        up_history_item_set_value (item, percentage);
760
 
        up_history_item_set_state (item, history->priv->state);
761
 
        g_ptr_array_add (history->priv->data_charge, item);
762
 
        up_history_schedule_save (history);
763
 
 
764
 
        /* save last value */
765
 
        history->priv->percentage_last = percentage;
766
 
 
767
 
        return TRUE;
768
 
}
769
 
 
770
 
/**
771
 
 * up_history_set_rate_data:
772
 
 **/
773
 
gboolean
774
 
up_history_set_rate_data (UpHistory *history, gdouble rate)
775
 
{
776
 
        UpHistoryItem *item;
777
 
 
778
 
        g_return_val_if_fail (UP_IS_HISTORY (history), FALSE);
779
 
 
780
 
        if (history->priv->id == NULL)
781
 
                return FALSE;
782
 
        if (history->priv->state == UP_DEVICE_STATE_UNKNOWN)
783
 
                return FALSE;
784
 
        if (history->priv->rate_last == rate)
785
 
                return FALSE;
786
 
 
787
 
        /* add to array and schedule save file */
788
 
        item = up_history_item_new ();
789
 
        up_history_item_set_time_to_present (item);
790
 
        up_history_item_set_value (item, rate);
791
 
        up_history_item_set_state (item, history->priv->state);
792
 
        g_ptr_array_add (history->priv->data_rate, item);
793
 
        up_history_schedule_save (history);
794
 
 
795
 
        /* save last value */
796
 
        history->priv->rate_last = rate;
797
 
 
798
 
        return TRUE;
799
 
}
800
 
 
801
 
/**
802
 
 * up_history_set_time_full_data:
803
 
 **/
804
 
gboolean
805
 
up_history_set_time_full_data (UpHistory *history, gint64 time_s)
806
 
{
807
 
        UpHistoryItem *item;
808
 
 
809
 
        g_return_val_if_fail (UP_IS_HISTORY (history), FALSE);
810
 
 
811
 
        if (history->priv->id == NULL)
812
 
                return FALSE;
813
 
        if (history->priv->state == UP_DEVICE_STATE_UNKNOWN)
814
 
                return FALSE;
815
 
        if (time_s < 0)
816
 
                return FALSE;
817
 
        if (history->priv->time_full_last == time_s)
818
 
                return FALSE;
819
 
 
820
 
        /* add to array and schedule save file */
821
 
        item = up_history_item_new ();
822
 
        up_history_item_set_time_to_present (item);
823
 
        up_history_item_set_value (item, (gdouble) time_s);
824
 
        up_history_item_set_state (item, history->priv->state);
825
 
        g_ptr_array_add (history->priv->data_time_full, item);
826
 
        up_history_schedule_save (history);
827
 
 
828
 
        /* save last value */
829
 
        history->priv->time_full_last = time_s;
830
 
 
831
 
        return TRUE;
832
 
}
833
 
 
834
 
/**
835
 
 * up_history_set_time_empty_data:
836
 
 **/
837
 
gboolean
838
 
up_history_set_time_empty_data (UpHistory *history, gint64 time_s)
839
 
{
840
 
        UpHistoryItem *item;
841
 
 
842
 
        g_return_val_if_fail (UP_IS_HISTORY (history), FALSE);
843
 
 
844
 
        if (history->priv->id == NULL)
845
 
                return FALSE;
846
 
        if (history->priv->state == UP_DEVICE_STATE_UNKNOWN)
847
 
                return FALSE;
848
 
        if (time_s < 0)
849
 
                return FALSE;
850
 
        if (history->priv->time_empty_last == time_s)
851
 
                return FALSE;
852
 
 
853
 
        /* add to array and schedule save file */
854
 
        item = up_history_item_new ();
855
 
        up_history_item_set_time_to_present (item);
856
 
        up_history_item_set_value (item, (gdouble) time_s);
857
 
        up_history_item_set_state (item, history->priv->state);
858
 
        g_ptr_array_add (history->priv->data_time_empty, item);
859
 
        up_history_schedule_save (history);
860
 
 
861
 
        /* save last value */
862
 
        history->priv->time_empty_last = time_s;
863
 
 
864
 
        return TRUE;
865
 
}
866
 
 
867
 
/**
868
 
 * up_history_class_init:
869
 
 * @klass: The UpHistoryClass
870
 
 **/
871
 
static void
872
 
up_history_class_init (UpHistoryClass *klass)
873
 
{
874
 
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
875
 
        object_class->finalize = up_history_finalize;
876
 
        g_type_class_add_private (klass, sizeof (UpHistoryPrivate));
877
 
}
878
 
 
879
 
/**
880
 
 * up_history_init:
881
 
 * @history: This class instance
882
 
 **/
883
 
static void
884
 
up_history_init (UpHistory *history)
885
 
{
886
 
        history->priv = UP_HISTORY_GET_PRIVATE (history);
887
 
        history->priv->id = NULL;
888
 
        history->priv->rate_last = 0;
889
 
        history->priv->percentage_last = 0;
890
 
        history->priv->state = UP_DEVICE_STATE_UNKNOWN;
891
 
        history->priv->data_rate = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
892
 
        history->priv->data_charge = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
893
 
        history->priv->data_time_full = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
894
 
        history->priv->data_time_empty = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
895
 
        history->priv->save_id = 0;
896
 
        history->priv->max_data_age = UP_HISTORY_DEFAULT_MAX_DATA_AGE;
897
 
        history->priv->dir = g_build_filename (HISTORY_DIR, NULL);
898
 
}
899
 
 
900
 
/**
901
 
 * up_history_finalize:
902
 
 * @object: The object to finalize
903
 
 **/
904
 
static void
905
 
up_history_finalize (GObject *object)
906
 
{
907
 
        UpHistory *history;
908
 
 
909
 
        g_return_if_fail (UP_IS_HISTORY (object));
910
 
 
911
 
        history = UP_HISTORY (object);
912
 
 
913
 
        /* save */
914
 
        if (history->priv->save_id > 0)
915
 
                g_source_remove (history->priv->save_id);
916
 
        if (history->priv->id != NULL)
917
 
                up_history_save_data (history);
918
 
 
919
 
        g_ptr_array_unref (history->priv->data_rate);
920
 
        g_ptr_array_unref (history->priv->data_charge);
921
 
        g_ptr_array_unref (history->priv->data_time_full);
922
 
        g_ptr_array_unref (history->priv->data_time_empty);
923
 
 
924
 
        g_free (history->priv->id);
925
 
        g_free (history->priv->dir);
926
 
 
927
 
        g_return_if_fail (history->priv != NULL);
928
 
 
929
 
        G_OBJECT_CLASS (up_history_parent_class)->finalize (object);
930
 
}
931
 
 
932
 
/**
933
 
 * up_history_new:
934
 
 *
935
 
 * Return value: a new UpHistory object.
936
 
 **/
937
 
UpHistory *
938
 
up_history_new (void)
939
 
{
940
 
        UpHistory *history;
941
 
        history = g_object_new (UP_TYPE_HISTORY, NULL);
942
 
        return UP_HISTORY (history);
943
 
}
944