Merge lp:~charlesk/indicator-datetime/hw-alarms-api into lp:indicator-datetime/13.10
- hw-alarms-api
- Merge into trunk.14.10
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Ted Gould | ||||
Approved revision: | 353 | ||||
Merged at revision: | 344 | ||||
Proposed branch: | lp:~charlesk/indicator-datetime/hw-alarms-api | ||||
Merge into: | lp:indicator-datetime/13.10 | ||||
Diff against target: |
1364 lines (+882/-141) 20 files modified
CMakeLists.txt (+7/-0) MERGE-REVIEW (+30/-5) debian/control (+2/-0) include/datetime/alarm-queue-simple.h (+63/-0) include/datetime/alarm-queue.h (+12/-28) include/datetime/date-time.h (+3/-0) include/datetime/planner-range.h (+1/-1) include/datetime/wakeup-timer-mainloop.h (+62/-0) include/datetime/wakeup-timer-uha.h (+64/-0) include/datetime/wakeup-timer.h (+55/-0) src/CMakeLists.txt (+31/-24) src/alarm-queue-simple.cpp (+116/-38) src/date-time.cpp (+5/-0) src/engine-eds.cpp (+10/-2) src/main.cpp (+88/-27) src/planner-range.cpp (+1/-1) src/wakeup-timer-mainloop.cpp (+138/-0) src/wakeup-timer-uha.cpp (+175/-0) tests/CMakeLists.txt (+1/-1) tests/test-alarm-queue.cpp (+18/-14) |
||||
To merge this branch: | bzr merge lp:~charlesk/indicator-datetime/hw-alarms-api | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Ted Gould (community) | Approve | ||
Review via email: mp+222716@code.launchpad.net |
This proposal supersedes a proposal from 2014-04-25.
Commit message
Prefer to use ubuntu-
Description of the change
Jenkins isn't going to like this branch as-is.
Prerequisite: lp:~thomas-voss/platform-api/hw-alarms-api
TODO: (1) still some issues in the platform-api branch that I've mailed tvoss about. Once that's cleared I'll be able to give this branch more testing on (2) the phablet hybris impl and (3) the Desktop's fallback mode (ie, use a different implementation when u_hardware_
Ted Gould (ted) wrote : Posted in a previous version of this proposal | # |
Ted Gould (ted) wrote : | # |
Resubmitted for 14.10
- 353. By Charles Kerr
-
in debian/control, remove 'Depends: libubuntu-
platform- hardware- api1' as per ted's suggestion
Ted Gould (ted) : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:352
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:353
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 354. By Charles Kerr
-
Don't build the hw-alarms pieces if ubuntu/
hardware/ alarm.h can't be found. Don't require libplatform- hardware- api-* unless the arch is armhf, i386, or amd64. - 355. By Charles Kerr
-
remove a pair of #warning tracers
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2014-03-23 14:45:38 +0000 |
3 | +++ CMakeLists.txt 2014-06-11 04:07:06 +0000 |
4 | @@ -29,6 +29,7 @@ |
5 | ## |
6 | |
7 | find_package (PkgConfig REQUIRED) |
8 | +include (CheckIncludeFile) |
9 | include (FindPkgConfig) |
10 | |
11 | pkg_check_modules (SERVICE_DEPS REQUIRED |
12 | @@ -43,6 +44,12 @@ |
13 | properties-cpp>=0.0.1) |
14 | include_directories (SYSTEM ${SERVICE_DEPS_INCLUDE_DIRS}) |
15 | |
16 | +CHECK_INCLUDE_FILE(ubuntu/hardware/alarm.h HAVE_UBUNTU_HW_ALARM_H) |
17 | +if (HAVE_UBUNTU_HW_ALARM_H) |
18 | + set (SERVICE_DEPS_LIBRARIES -lubuntu_platform_hardware_api ${SERVICE_DEPS_LIBRARIES}) |
19 | + add_definitions(-DHAVE_UBUNTU_HW_ALARM_H) |
20 | +endif () |
21 | + |
22 | ## |
23 | ## custom targets |
24 | ## |
25 | |
26 | === modified file 'MERGE-REVIEW' |
27 | --- MERGE-REVIEW 2014-01-31 20:17:55 +0000 |
28 | +++ MERGE-REVIEW 2014-06-11 04:07:06 +0000 |
29 | @@ -6,14 +6,39 @@ |
30 | |
31 | * Ensure the project compiles and the test suite executes without error |
32 | * Ensure that non-obvious code has comments explaining it |
33 | - * If the change works on specific profiles, please include those in the merge description. |
34 | + * If the change affects specific features, please reference the appropriate |
35 | + tags in the merge description so reviewers can test appropriately: |
36 | + [phone profile], [desktop profile], [alarms] |
37 | |
38 | == Reviewer Responsibilities == |
39 | |
40 | * Did the Jenkins build compile? Pass? Run unit tests successfully? |
41 | * Are there appropriate tests to cover any new functionality? |
42 | - * If the description says this effects the phone profile: |
43 | - * Run tests indicator-datetime/unity8* |
44 | - * If the description says this effects the desktop profile: |
45 | - * Run tests indicator-datetime/unity7* |
46 | + * Do the tag-specific tests pass? |
47 | + |
48 | +== Phone Profile Tests == |
49 | + |
50 | + * Run tests indicator-datetime/unity8* |
51 | + |
52 | +== Desktop Profile Tests == |
53 | + |
54 | + * Run tests indicator-datetime/unity7* |
55 | + |
56 | +== Alarm Tests == |
57 | + |
58 | + * Hardware wakeups for new alarms: |
59 | + 1. Create and save an upcoming alarm in ubuntu-clock-app. |
60 | + 2. Unplug the phone from any USB connection and put it to sleep. |
61 | + 3. Confirm that the alarm sounds on time even if the phone is asleep. |
62 | + (Note: if in doubt about sleep you can see in the syslog whether the |
63 | + device actually suspended or whether the suspend was aborted) |
64 | + |
65 | + * Hardware wakeups for edited alarms: |
66 | + 1. Edit an alarm that's already passed. (see previous test) |
67 | + 2. Unplug the phone from any USB connection and put it to sleep. |
68 | + 3. Confirm that the alarm sounds on time even if the phone is asleep. |
69 | + (Note: if in doubt about sleep you can see in the syslog whether the |
70 | + device actually suspended or whether the suspend was aborted.) |
71 | + |
72 | + |
73 | |
74 | |
75 | === modified file 'debian/control' |
76 | --- debian/control 2014-03-23 20:11:06 +0000 |
77 | +++ debian/control 2014-06-11 04:07:06 +0000 |
78 | @@ -19,6 +19,8 @@ |
79 | libedataserver1.2-dev (>= 3.5), |
80 | liburl-dispatcher1-dev, |
81 | libproperties-cpp-dev, |
82 | + libplatform-hardware-api-headers [armhf i386 amd64], |
83 | + libplatform-hardware-api1-dev [armhf i386 amd64], |
84 | libdbustest1-dev, |
85 | locales, |
86 | Standards-Version: 3.9.3 |
87 | |
88 | === added file 'include/datetime/alarm-queue-simple.h' |
89 | --- include/datetime/alarm-queue-simple.h 1970-01-01 00:00:00 +0000 |
90 | +++ include/datetime/alarm-queue-simple.h 2014-06-11 04:07:06 +0000 |
91 | @@ -0,0 +1,63 @@ |
92 | +/* |
93 | + * Copyright 2014 Canonical Ltd. |
94 | + * |
95 | + * This program is free software: you can redistribute it and/or modify it |
96 | + * under the terms of the GNU General Public License version 3, as published |
97 | + * by the Free Software Foundation. |
98 | + * |
99 | + * This program is distributed in the hope that it will be useful, but |
100 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
101 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
102 | + * PURPOSE. See the GNU General Public License for more details. |
103 | + * |
104 | + * You should have received a copy of the GNU General Public License along |
105 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
106 | + * |
107 | + * Authors: |
108 | + * Charles Kerr <charles.kerr@canonical.com> |
109 | + */ |
110 | + |
111 | +#ifndef INDICATOR_DATETIME_ALARM_QUEUE_SIMPLE_H |
112 | +#define INDICATOR_DATETIME_ALARM_QUEUE_SIMPLE_H |
113 | + |
114 | +#include <datetime/alarm-queue.h> |
115 | +#include <datetime/clock.h> |
116 | +#include <datetime/planner.h> |
117 | +#include <datetime/wakeup-timer.h> |
118 | + |
119 | +namespace unity { |
120 | +namespace indicator { |
121 | +namespace datetime { |
122 | + |
123 | +/** |
124 | + * \brief A #AlarmQueue implementation |
125 | + */ |
126 | +class SimpleAlarmQueue: public AlarmQueue |
127 | +{ |
128 | +public: |
129 | + SimpleAlarmQueue(const std::shared_ptr<Clock>& clock, |
130 | + const std::shared_ptr<Planner>& upcoming_planner, |
131 | + const std::shared_ptr<WakeupTimer>& timer); |
132 | + ~SimpleAlarmQueue(); |
133 | + core::Signal<const Appointment&>& alarm_reached(); |
134 | + |
135 | +private: |
136 | + void requeue(); |
137 | + bool find_next_alarm(Appointment& setme) const; |
138 | + std::vector<Appointment> find_current_alarms() const; |
139 | + void check_alarms(); |
140 | + |
141 | + std::set<std::pair<std::string,DateTime>> m_triggered; |
142 | + const std::shared_ptr<Clock> m_clock; |
143 | + const std::shared_ptr<Planner> m_planner; |
144 | + const std::shared_ptr<WakeupTimer> m_timer; |
145 | + core::Signal<const Appointment&> m_alarm_reached; |
146 | + DateTime m_datetime; |
147 | +}; |
148 | + |
149 | + |
150 | +} // namespace datetime |
151 | +} // namespace indicator |
152 | +} // namespace unity |
153 | + |
154 | +#endif // INDICATOR_DATETIME_ALARM_QUEUE_H |
155 | |
156 | === renamed file 'include/datetime/clock-watcher.h' => 'include/datetime/alarm-queue.h' |
157 | --- include/datetime/clock-watcher.h 2014-03-10 02:08:47 +0000 |
158 | +++ include/datetime/alarm-queue.h 2014-06-11 04:07:06 +0000 |
159 | @@ -17,12 +17,10 @@ |
160 | * Charles Kerr <charles.kerr@canonical.com> |
161 | */ |
162 | |
163 | -#ifndef INDICATOR_DATETIME_CLOCK_WATCHER_H |
164 | -#define INDICATOR_DATETIME_CLOCK_WATCHER_H |
165 | +#ifndef INDICATOR_DATETIME_ALARM_QUEUE_H |
166 | +#define INDICATOR_DATETIME_ALARM_QUEUE_H |
167 | |
168 | #include <datetime/appointment.h> |
169 | -#include <datetime/clock.h> |
170 | -#include <datetime/planner-upcoming.h> |
171 | |
172 | #include <core/signal.h> |
173 | |
174 | @@ -34,42 +32,28 @@ |
175 | namespace indicator { |
176 | namespace datetime { |
177 | |
178 | +/*** |
179 | +**** |
180 | +***/ |
181 | |
182 | /** |
183 | * \brief Watches the clock and appointments to notify when an |
184 | * appointment's time is reached. |
185 | */ |
186 | -class ClockWatcher |
187 | +class AlarmQueue |
188 | { |
189 | public: |
190 | - ClockWatcher() =default; |
191 | - virtual ~ClockWatcher() =default; |
192 | + AlarmQueue() =default; |
193 | + virtual ~AlarmQueue() =default; |
194 | virtual core::Signal<const Appointment&>& alarm_reached() = 0; |
195 | }; |
196 | |
197 | - |
198 | -/** |
199 | - * \brief A #ClockWatcher implementation |
200 | - */ |
201 | -class ClockWatcherImpl: public ClockWatcher |
202 | -{ |
203 | -public: |
204 | - ClockWatcherImpl(const std::shared_ptr<Clock>& clock, |
205 | - const std::shared_ptr<UpcomingPlanner>& upcoming_planner); |
206 | - ~ClockWatcherImpl() =default; |
207 | - core::Signal<const Appointment&>& alarm_reached(); |
208 | - |
209 | -private: |
210 | - void pulse(); |
211 | - std::set<std::string> m_triggered; |
212 | - const std::shared_ptr<Clock> m_clock; |
213 | - const std::shared_ptr<UpcomingPlanner> m_upcoming_planner; |
214 | - core::Signal<const Appointment&> m_alarm_reached; |
215 | -}; |
216 | - |
217 | +/*** |
218 | +**** |
219 | +***/ |
220 | |
221 | } // namespace datetime |
222 | } // namespace indicator |
223 | } // namespace unity |
224 | |
225 | -#endif // INDICATOR_DATETIME_CLOCK_WATCHER_H |
226 | +#endif // INDICATOR_DATETIME_ALARM_QUEUE_H |
227 | |
228 | === modified file 'include/datetime/date-time.h' |
229 | --- include/datetime/date-time.h 2014-03-10 02:08:47 +0000 |
230 | +++ include/datetime/date-time.h 2014-06-11 04:07:06 +0000 |
231 | @@ -61,10 +61,13 @@ |
232 | bool operator<=(const DateTime& that) const; |
233 | bool operator!=(const DateTime& that) const; |
234 | bool operator==(const DateTime& that) const; |
235 | + int64_t operator- (const DateTime& that) const; |
236 | |
237 | static bool is_same_day(const DateTime& a, const DateTime& b); |
238 | static bool is_same_minute(const DateTime& a, const DateTime& b); |
239 | |
240 | + bool is_set() const { return m_dt != nullptr; } |
241 | + |
242 | private: |
243 | std::shared_ptr<GDateTime> m_dt; |
244 | }; |
245 | |
246 | === modified file 'include/datetime/planner-range.h' |
247 | --- include/datetime/planner-range.h 2014-03-10 03:26:26 +0000 |
248 | +++ include/datetime/planner-range.h 2014-06-11 04:07:06 +0000 |
249 | @@ -53,7 +53,7 @@ |
250 | { |
251 | public: |
252 | SimpleRangePlanner(const std::shared_ptr<Engine>& engine, |
253 | - const std::shared_ptr<Timezone>& timezone); |
254 | + const std::shared_ptr<Timezone>& timezone); |
255 | virtual ~SimpleRangePlanner(); |
256 | |
257 | core::Property<std::vector<Appointment>>& appointments(); |
258 | |
259 | === added file 'include/datetime/wakeup-timer-mainloop.h' |
260 | --- include/datetime/wakeup-timer-mainloop.h 1970-01-01 00:00:00 +0000 |
261 | +++ include/datetime/wakeup-timer-mainloop.h 2014-06-11 04:07:06 +0000 |
262 | @@ -0,0 +1,62 @@ |
263 | +/* |
264 | + * Copyright 2014 Canonical Ltd. |
265 | + * |
266 | + * This program is free software: you can redistribute it and/or modify it |
267 | + * under the terms of the GNU General Public License version 3, as published |
268 | + * by the Free Software Foundation. |
269 | + * |
270 | + * This program is distributed in the hope that it will be useful, but |
271 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
272 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
273 | + * PURPOSE. See the GNU General Public License for more details. |
274 | + * |
275 | + * You should have received a copy of the GNU General Public License along |
276 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
277 | + * |
278 | + * Authors: |
279 | + * Charles Kerr <charles.kerr@canonical.com> |
280 | + */ |
281 | + |
282 | +#ifndef INDICATOR_DATETIME_WAKEUP_TIMER_MAINLOOP_H |
283 | +#define INDICATOR_DATETIME_WAKEUP_TIMER_MAINLOOP_H |
284 | + |
285 | +#include <datetime/clock.h> |
286 | +#include <datetime/wakeup-timer.h> |
287 | + |
288 | +#include <memory> // std::unique_ptr, std::shared_ptr |
289 | + |
290 | +namespace unity { |
291 | +namespace indicator { |
292 | +namespace datetime { |
293 | + |
294 | +/*** |
295 | +**** |
296 | +***/ |
297 | + |
298 | +/** |
299 | + * \brief a WakeupTimer implemented with g_timeout_add() |
300 | + */ |
301 | +class MainloopWakeupTimer: public WakeupTimer |
302 | +{ |
303 | +public: |
304 | + MainloopWakeupTimer(const std::shared_ptr<Clock>&); |
305 | + ~MainloopWakeupTimer(); |
306 | + void set_wakeup_time (const DateTime&); |
307 | + core::Signal<>& timeout(); |
308 | + |
309 | +private: |
310 | + MainloopWakeupTimer(const MainloopWakeupTimer&) =delete; |
311 | + MainloopWakeupTimer& operator= (const MainloopWakeupTimer&) =delete; |
312 | + class Impl; |
313 | + std::unique_ptr<Impl> p; |
314 | +}; |
315 | + |
316 | +/*** |
317 | +**** |
318 | +***/ |
319 | + |
320 | +} // namespace datetime |
321 | +} // namespace indicator |
322 | +} // namespace unity |
323 | + |
324 | +#endif // INDICATOR_DATETIME_WAKEUP_TIMER_MAINLOOP_H |
325 | |
326 | === added file 'include/datetime/wakeup-timer-uha.h' |
327 | --- include/datetime/wakeup-timer-uha.h 1970-01-01 00:00:00 +0000 |
328 | +++ include/datetime/wakeup-timer-uha.h 2014-06-11 04:07:06 +0000 |
329 | @@ -0,0 +1,64 @@ |
330 | +/* |
331 | + * Copyright 2014 Canonical Ltd. |
332 | + * |
333 | + * This program is free software: you can redistribute it and/or modify it |
334 | + * under the terms of the GNU General Public License version 3, as published |
335 | + * by the Free Software Foundation. |
336 | + * |
337 | + * This program is distributed in the hope that it will be useful, but |
338 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
339 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
340 | + * PURPOSE. See the GNU General Public License for more details. |
341 | + * |
342 | + * You should have received a copy of the GNU General Public License along |
343 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
344 | + * |
345 | + * Authors: |
346 | + * Charles Kerr <charles.kerr@canonical.com> |
347 | + */ |
348 | + |
349 | +#ifndef INDICATOR_DATETIME_WAKEUP_TIMER_UHA_H |
350 | +#define INDICATOR_DATETIME_WAKEUP_TIMER_UHA_H |
351 | + |
352 | +#include <datetime/clock.h> |
353 | +#include <datetime/wakeup-timer.h> |
354 | + |
355 | +#include <memory> // std::unique_ptr, std::shared_ptr |
356 | + |
357 | +namespace unity { |
358 | +namespace indicator { |
359 | +namespace datetime { |
360 | + |
361 | +/*** |
362 | +**** |
363 | +***/ |
364 | + |
365 | +/** |
366 | + * \brief a WakeupTimer implemented the UbuntuHardwareAlarm API |
367 | + */ |
368 | +class UhaWakeupTimer: public WakeupTimer |
369 | +{ |
370 | +public: |
371 | + UhaWakeupTimer(const std::shared_ptr<Clock>&); |
372 | + ~UhaWakeupTimer(); |
373 | + void set_wakeup_time (const DateTime&); |
374 | + core::Signal<>& timeout(); |
375 | + |
376 | + static bool is_supported(); |
377 | + |
378 | +private: |
379 | + UhaWakeupTimer(const UhaWakeupTimer&) =delete; |
380 | + UhaWakeupTimer& operator= (const UhaWakeupTimer&) =delete; |
381 | + class Impl; |
382 | + std::unique_ptr<Impl> p; |
383 | +}; |
384 | + |
385 | +/*** |
386 | +**** |
387 | +***/ |
388 | + |
389 | +} // namespace datetime |
390 | +} // namespace indicator |
391 | +} // namespace unity |
392 | + |
393 | +#endif // INDICATOR_DATETIME_WAKEUP_TIMER_UHA_H |
394 | |
395 | === added file 'include/datetime/wakeup-timer.h' |
396 | --- include/datetime/wakeup-timer.h 1970-01-01 00:00:00 +0000 |
397 | +++ include/datetime/wakeup-timer.h 2014-06-11 04:07:06 +0000 |
398 | @@ -0,0 +1,55 @@ |
399 | +/* |
400 | + * Copyright 2014 Canonical Ltd. |
401 | + * |
402 | + * This program is free software: you can redistribute it and/or modify it |
403 | + * under the terms of the GNU General Public License version 3, as published |
404 | + * by the Free Software Foundation. |
405 | + * |
406 | + * This program is distributed in the hope that it will be useful, but |
407 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
408 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
409 | + * PURPOSE. See the GNU General Public License for more details. |
410 | + * |
411 | + * You should have received a copy of the GNU General Public License along |
412 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
413 | + * |
414 | + * Authors: |
415 | + * Charles Kerr <charles.kerr@canonical.com> |
416 | + */ |
417 | + |
418 | +#ifndef INDICATOR_DATETIME_WAKEUP_TIMER_H |
419 | +#define INDICATOR_DATETIME_WAKEUP_TIMER_H |
420 | + |
421 | +#include <datetime/date-time.h> |
422 | + |
423 | +#include <core/signal.h> |
424 | + |
425 | +namespace unity { |
426 | +namespace indicator { |
427 | +namespace datetime { |
428 | + |
429 | +/*** |
430 | +**** |
431 | +***/ |
432 | + |
433 | +/** |
434 | + * \brief A one-shot timer that emits a signal when its timeout is reached. |
435 | + */ |
436 | +class WakeupTimer |
437 | +{ |
438 | +public: |
439 | + WakeupTimer() =default; |
440 | + virtual ~WakeupTimer() =default; |
441 | + virtual void set_wakeup_time (const DateTime&) =0; |
442 | + virtual core::Signal<>& timeout() = 0; |
443 | +}; |
444 | + |
445 | +/*** |
446 | +**** |
447 | +***/ |
448 | + |
449 | +} // namespace datetime |
450 | +} // namespace indicator |
451 | +} // namespace unity |
452 | + |
453 | +#endif // INDICATOR_DATETIME_WAKEUP_TIMER_H |
454 | |
455 | === modified file 'src/CMakeLists.txt' |
456 | --- src/CMakeLists.txt 2014-03-10 03:26:26 +0000 |
457 | +++ src/CMakeLists.txt 2014-06-11 04:07:06 +0000 |
458 | @@ -7,30 +7,37 @@ |
459 | add_definitions (-DTIMEZONE_FILE="/etc/timezone" |
460 | -DG_LOG_DOMAIN="Indicator-Datetime") |
461 | |
462 | -add_library (${SERVICE_LIB} STATIC |
463 | - actions.cpp |
464 | - actions-live.cpp |
465 | - appointment.cpp |
466 | - clock.cpp |
467 | - clock-live.cpp |
468 | - clock-watcher.cpp |
469 | - date-time.cpp |
470 | - engine-eds.cpp |
471 | - exporter.cpp |
472 | - formatter.cpp |
473 | - formatter-desktop.cpp |
474 | - locations.cpp |
475 | - locations-settings.cpp |
476 | - menu.cpp |
477 | - planner-month.cpp |
478 | - planner-range.cpp |
479 | - planner-upcoming.cpp |
480 | - settings-live.cpp |
481 | - snap.cpp |
482 | - timezone-file.cpp |
483 | - timezone-geoclue.cpp |
484 | - timezones-live.cpp |
485 | - utils.c) |
486 | +set (SERVICE_SOURCES |
487 | + actions.cpp |
488 | + actions-live.cpp |
489 | + alarm-queue-simple.cpp |
490 | + appointment.cpp |
491 | + clock.cpp |
492 | + clock-live.cpp |
493 | + date-time.cpp |
494 | + engine-eds.cpp |
495 | + exporter.cpp |
496 | + formatter.cpp |
497 | + formatter-desktop.cpp |
498 | + locations.cpp |
499 | + locations-settings.cpp |
500 | + menu.cpp |
501 | + planner-month.cpp |
502 | + planner-range.cpp |
503 | + planner-upcoming.cpp |
504 | + settings-live.cpp |
505 | + snap.cpp |
506 | + timezone-file.cpp |
507 | + timezone-geoclue.cpp |
508 | + timezones-live.cpp |
509 | + utils.c |
510 | + wakeup-timer-mainloop.cpp) |
511 | + |
512 | +if (HAVE_UBUNTU_HW_ALARM_H) |
513 | + set (SERVICE_SOURCES ${SERVICE_SOURCES} wakeup-timer-uha.cpp) |
514 | +endif () |
515 | + |
516 | +add_library (${SERVICE_LIB} STATIC ${SERVICE_SOURCES}) |
517 | include_directories (${CMAKE_SOURCE_DIR}) |
518 | link_directories (${SERVICE_DEPS_LIBRARY_DIRS}) |
519 | |
520 | |
521 | === renamed file 'src/clock-watcher.cpp' => 'src/alarm-queue-simple.cpp' |
522 | --- src/clock-watcher.cpp 2014-03-10 02:08:47 +0000 |
523 | +++ src/alarm-queue-simple.cpp 2014-06-11 04:07:06 +0000 |
524 | @@ -17,59 +17,137 @@ |
525 | * Charles Kerr <charles.kerr@canonical.com> |
526 | */ |
527 | |
528 | -#include <datetime/clock-watcher.h> |
529 | +#include <datetime/alarm-queue-simple.h> |
530 | + |
531 | +#include <cmath> |
532 | |
533 | namespace unity { |
534 | namespace indicator { |
535 | namespace datetime { |
536 | |
537 | /*** |
538 | -**** |
539 | +**** Public API |
540 | ***/ |
541 | |
542 | -ClockWatcherImpl::ClockWatcherImpl(const std::shared_ptr<Clock>& clock, |
543 | - const std::shared_ptr<UpcomingPlanner>& upcoming_planner): |
544 | +SimpleAlarmQueue::SimpleAlarmQueue(const std::shared_ptr<Clock>& clock, |
545 | + const std::shared_ptr<Planner>& planner, |
546 | + const std::shared_ptr<WakeupTimer>& timer): |
547 | m_clock(clock), |
548 | - m_upcoming_planner(upcoming_planner) |
549 | + m_planner(planner), |
550 | + m_timer(timer), |
551 | + m_datetime(clock->localtime()) |
552 | { |
553 | - m_clock->date_changed.connect([this](){ |
554 | + m_planner->appointments().changed().connect([this](const std::vector<Appointment>&){ |
555 | + g_debug("AlarmQueue %p calling requeue() due to appointments changed", this); |
556 | + requeue(); |
557 | + }); |
558 | + |
559 | + m_clock->minute_changed.connect([=]{ |
560 | const auto now = m_clock->localtime(); |
561 | - g_debug("ClockWatcher %p refretching appointments due to date change: %s", this, now.format("%F %T").c_str()); |
562 | - m_upcoming_planner->date().set(now); |
563 | - }); |
564 | - |
565 | - m_clock->minute_changed.connect([this](){ |
566 | - g_debug("ClockWatcher %p calling pulse() due to clock minute_changed", this); |
567 | - pulse(); |
568 | - }); |
569 | - |
570 | - m_upcoming_planner->appointments().changed().connect([this](const std::vector<Appointment>&){ |
571 | - g_debug("ClockWatcher %p calling pulse() due to appointments changed", this); |
572 | - pulse(); |
573 | - }); |
574 | - |
575 | - pulse(); |
576 | -} |
577 | - |
578 | -core::Signal<const Appointment&>& ClockWatcherImpl::alarm_reached() |
579 | + constexpr auto skew_threshold_usec = int64_t{90} * G_USEC_PER_SEC; |
580 | + const bool clock_jumped = std::abs(now - m_datetime) > skew_threshold_usec; |
581 | + m_datetime = now; |
582 | + if (clock_jumped) { |
583 | + g_debug("AlarmQueue %p calling requeue() due to clock skew", this); |
584 | + requeue(); |
585 | + } |
586 | + }); |
587 | + |
588 | + m_timer->timeout().connect([this](){ |
589 | + g_debug("AlarmQueue %p calling requeue() due to timeout", this); |
590 | + requeue(); |
591 | + }); |
592 | + |
593 | + requeue(); |
594 | +} |
595 | + |
596 | +SimpleAlarmQueue::~SimpleAlarmQueue() |
597 | +{ |
598 | +} |
599 | + |
600 | +core::Signal<const Appointment&>& SimpleAlarmQueue::alarm_reached() |
601 | { |
602 | return m_alarm_reached; |
603 | } |
604 | |
605 | -void ClockWatcherImpl::pulse() |
606 | -{ |
607 | - const auto now = m_clock->localtime(); |
608 | - |
609 | - for(const auto& appointment : m_upcoming_planner->appointments().get()) |
610 | - { |
611 | - if (m_triggered.count(appointment.uid)) |
612 | - continue; |
613 | - if (!DateTime::is_same_minute(now, appointment.begin)) |
614 | - continue; |
615 | - |
616 | - m_triggered.insert(appointment.uid); |
617 | - m_alarm_reached(appointment); |
618 | - } |
619 | +/*** |
620 | +**** |
621 | +***/ |
622 | + |
623 | +void SimpleAlarmQueue::requeue() |
624 | +{ |
625 | + // kick any current alarms |
626 | + for (auto current : find_current_alarms()) |
627 | + { |
628 | + const std::pair<std::string,DateTime> trig {current.uid, current.begin}; |
629 | + m_triggered.insert(trig); |
630 | + m_alarm_reached(current); |
631 | + } |
632 | + |
633 | + // idle until the next alarm |
634 | + Appointment next; |
635 | + if (find_next_alarm(next)) |
636 | + { |
637 | + g_debug ("setting timer to wake up for next appointment '%s' at %s", |
638 | + next.summary.c_str(), |
639 | + next.begin.format("%F %T").c_str()); |
640 | + |
641 | + m_timer->set_wakeup_time(next.begin); |
642 | + } |
643 | +} |
644 | + |
645 | +// find the next alarm that will kick now or in the future |
646 | +bool SimpleAlarmQueue::find_next_alarm(Appointment& setme) const |
647 | +{ |
648 | + bool found = false; |
649 | + Appointment tmp; |
650 | + const auto now = m_clock->localtime(); |
651 | + const auto beginning_of_minute = now.add_full (0, 0, 0, 0, 0, -now.seconds()); |
652 | + |
653 | + const auto appointments = m_planner->appointments().get(); |
654 | + g_debug ("planner has %zu appointments in it", (size_t)appointments.size()); |
655 | + |
656 | + for(const auto& walk : appointments) |
657 | + { |
658 | + const std::pair<std::string,DateTime> trig {walk.uid, walk.begin}; |
659 | + if (m_triggered.count(trig)) |
660 | + continue; |
661 | + |
662 | + if (walk.begin < beginning_of_minute) // has this one already passed? |
663 | + continue; |
664 | + |
665 | + if (found && (tmp.begin < walk.begin)) // do we already have a better match? |
666 | + continue; |
667 | + |
668 | + tmp = walk; |
669 | + found = true; |
670 | + } |
671 | + |
672 | + if (found) |
673 | + setme = tmp; |
674 | + |
675 | + return found; |
676 | +} |
677 | + |
678 | +// find the alarm(s) that should kick right now |
679 | +std::vector<Appointment> SimpleAlarmQueue::find_current_alarms() const |
680 | +{ |
681 | + std::vector<Appointment> appointments; |
682 | + |
683 | + const auto now = m_clock->localtime(); |
684 | + |
685 | + for(const auto& walk : m_planner->appointments().get()) |
686 | + { |
687 | + const std::pair<std::string,DateTime> trig {walk.uid, walk.begin}; |
688 | + if (m_triggered.count(trig)) // did we already use this one? |
689 | + continue; |
690 | + if (!DateTime::is_same_minute(now, walk.begin)) |
691 | + continue; |
692 | + |
693 | + appointments.push_back(walk); |
694 | + } |
695 | + |
696 | + return appointments; |
697 | } |
698 | |
699 | /*** |
700 | |
701 | === modified file 'src/date-time.cpp' |
702 | --- src/date-time.cpp 2014-03-10 02:08:47 +0000 |
703 | +++ src/date-time.cpp 2014-06-11 04:07:06 +0000 |
704 | @@ -174,6 +174,11 @@ |
705 | return g_date_time_compare(get(), that.get()) == 0; |
706 | } |
707 | |
708 | +int64_t DateTime::operator- (const DateTime& that) const |
709 | +{ |
710 | + return g_date_time_difference(get(), that.get()); |
711 | +} |
712 | + |
713 | bool DateTime::is_same_day(const DateTime& a, const DateTime& b) |
714 | { |
715 | // it's meaningless to compare uninitialized dates |
716 | |
717 | === modified file 'src/engine-eds.cpp' |
718 | --- src/engine-eds.cpp 2014-04-15 16:11:34 +0000 |
719 | +++ src/engine-eds.cpp 2014-06-11 04:07:06 +0000 |
720 | @@ -418,6 +418,14 @@ |
721 | auto status = ICAL_STATUS_NONE; |
722 | e_cal_component_get_status(component, &status); |
723 | |
724 | + const auto begin_dt = DateTime(begin); |
725 | + const auto end_dt = DateTime(end); |
726 | + g_debug ("got appointment from %s to %s, uid %s status %d", |
727 | + begin_dt.format("%F %T").c_str(), |
728 | + end_dt.format("%F %T").c_str(), |
729 | + uid, |
730 | + (int)status); |
731 | + |
732 | if ((uid != nullptr) && |
733 | (status != ICAL_STATUS_COMPLETED) && |
734 | (status != ICAL_STATUS_CANCELLED)) |
735 | @@ -430,8 +438,8 @@ |
736 | if (text.value) |
737 | appointment.summary = text.value; |
738 | |
739 | - appointment.begin = DateTime(begin); |
740 | - appointment.end = DateTime(end); |
741 | + appointment.begin = begin_dt; |
742 | + appointment.end = end_dt; |
743 | appointment.color = subtask->color; |
744 | appointment.uid = uid; |
745 | |
746 | |
747 | === modified file 'src/main.cpp' |
748 | --- src/main.cpp 2014-03-10 03:26:26 +0000 |
749 | +++ src/main.cpp 2014-06-11 04:07:06 +0000 |
750 | @@ -18,8 +18,8 @@ |
751 | */ |
752 | |
753 | #include <datetime/actions-live.h> |
754 | +#include <datetime/alarm-queue-simple.h> |
755 | #include <datetime/clock.h> |
756 | -#include <datetime/clock-watcher.h> |
757 | #include <datetime/engine-mock.h> |
758 | #include <datetime/engine-eds.h> |
759 | #include <datetime/exporter.h> |
760 | @@ -31,6 +31,11 @@ |
761 | #include <datetime/state.h> |
762 | #include <datetime/timezone-file.h> |
763 | #include <datetime/timezones-live.h> |
764 | +#include <datetime/wakeup-timer-mainloop.h> |
765 | + |
766 | +#ifdef HAVE_UBUNTU_HW_ALARM_H |
767 | + #include <datetime/wakeup-timer-uha.h> |
768 | +#endif |
769 | |
770 | #include <glib/gi18n.h> // bindtextdomain() |
771 | #include <gio/gio.h> |
772 | @@ -42,6 +47,81 @@ |
773 | |
774 | using namespace unity::indicator::datetime; |
775 | |
776 | +namespace |
777 | +{ |
778 | + std::shared_ptr<Engine> create_engine() |
779 | + { |
780 | + std::shared_ptr<Engine> engine; |
781 | + |
782 | + // we don't show appointments in the greeter, |
783 | + // so no need to connect to EDS there... |
784 | + if (!g_strcmp0("lightdm", g_get_user_name())) |
785 | + engine.reset(new MockEngine); |
786 | + else |
787 | + engine.reset(new EdsEngine); |
788 | + |
789 | + return engine; |
790 | + } |
791 | + |
792 | + std::shared_ptr<WakeupTimer> create_wakeup_timer(const std::shared_ptr<Clock>& clock) |
793 | + { |
794 | + std::shared_ptr<WakeupTimer> wakeup_timer; |
795 | + |
796 | +#ifdef HAVE_UBUNTU_HW_ALARM_H |
797 | + if (UhaWakeupTimer::is_supported()) // prefer to use the platform API |
798 | + wakeup_timer = std::make_shared<UhaWakeupTimer>(clock); |
799 | + else |
800 | +#endif |
801 | + wakeup_timer = std::make_shared<MainloopWakeupTimer>(clock); |
802 | + |
803 | + return wakeup_timer; |
804 | + } |
805 | + |
806 | + std::shared_ptr<State> create_state(const std::shared_ptr<Engine>& engine, |
807 | + const std::shared_ptr<Timezone>& tz) |
808 | + { |
809 | + // create the live objects |
810 | + auto live_settings = std::make_shared<LiveSettings>(); |
811 | + auto live_timezones = std::make_shared<LiveTimezones>(live_settings, TIMEZONE_FILE); |
812 | + auto live_clock = std::make_shared<LiveClock>(live_timezones); |
813 | + |
814 | + // create a full-month planner currently pointing to the current month |
815 | + const auto now = live_clock->localtime(); |
816 | + auto range_planner = std::make_shared<SimpleRangePlanner>(engine, tz); |
817 | + auto calendar_month = std::make_shared<MonthPlanner>(range_planner, now); |
818 | + |
819 | + // create an upcoming-events planner currently pointing to the current date |
820 | + range_planner = std::make_shared<SimpleRangePlanner>(engine, tz); |
821 | + auto calendar_upcoming = std::make_shared<UpcomingPlanner>(range_planner, now); |
822 | + |
823 | + // create the state |
824 | + auto state = std::make_shared<State>(); |
825 | + state->settings = live_settings; |
826 | + state->clock = live_clock; |
827 | + state->locations = std::make_shared<SettingsLocations>(live_settings, live_timezones); |
828 | + state->calendar_month = calendar_month; |
829 | + state->calendar_upcoming = calendar_upcoming; |
830 | + return state; |
831 | + } |
832 | + |
833 | + std::shared_ptr<AlarmQueue> create_simple_alarm_queue(const std::shared_ptr<Clock>& clock, |
834 | + const std::shared_ptr<Engine>& engine, |
835 | + const std::shared_ptr<Timezone>& tz) |
836 | + { |
837 | + // create an upcoming-events planner that =always= tracks the clock's date |
838 | + auto range_planner = std::make_shared<SimpleRangePlanner>(engine, tz); |
839 | + auto upcoming_planner = std::make_shared<UpcomingPlanner>(range_planner, clock->localtime()); |
840 | + clock->date_changed.connect([clock,upcoming_planner](){ |
841 | + const auto now = clock->localtime(); |
842 | + g_debug("refretching appointments due to date change: %s", now.format("%F %T").c_str()); |
843 | + upcoming_planner->date().set(now); |
844 | + }); |
845 | + |
846 | + auto wakeup_timer = create_wakeup_timer(clock); |
847 | + return std::make_shared<SimpleAlarmQueue>(clock, upcoming_planner, wakeup_timer); |
848 | + } |
849 | +} |
850 | + |
851 | int |
852 | main(int /*argc*/, char** /*argv*/) |
853 | { |
854 | @@ -54,35 +134,16 @@ |
855 | bindtextdomain(GETTEXT_PACKAGE, GNOMELOCALEDIR); |
856 | textdomain(GETTEXT_PACKAGE); |
857 | |
858 | - // we don't show appointments in the greeter, |
859 | - // so no need to connect to EDS there... |
860 | - std::shared_ptr<Engine> engine; |
861 | - if (!g_strcmp0("lightdm", g_get_user_name())) |
862 | - engine.reset(new MockEngine); |
863 | - else |
864 | - engine.reset(new EdsEngine); |
865 | - |
866 | - // build the state, actions, and menufactory |
867 | - std::shared_ptr<State> state(new State); |
868 | - std::shared_ptr<Settings> live_settings(new LiveSettings); |
869 | - std::shared_ptr<Timezones> live_timezones(new LiveTimezones(live_settings, TIMEZONE_FILE)); |
870 | - std::shared_ptr<Clock> live_clock(new LiveClock(live_timezones)); |
871 | - std::shared_ptr<Timezone> file_timezone(new FileTimezone(TIMEZONE_FILE)); |
872 | - const auto now = live_clock->localtime(); |
873 | - state->settings = live_settings; |
874 | - state->clock = live_clock; |
875 | - state->locations.reset(new SettingsLocations(live_settings, live_timezones)); |
876 | - auto calendar_month = new MonthPlanner(std::shared_ptr<RangePlanner>(new SimpleRangePlanner(engine, file_timezone)), now); |
877 | - state->calendar_month.reset(calendar_month); |
878 | - state->calendar_upcoming.reset(new UpcomingPlanner(std::shared_ptr<RangePlanner>(new SimpleRangePlanner(engine, file_timezone)), now)); |
879 | - std::shared_ptr<Actions> actions(new LiveActions(state)); |
880 | + auto engine = create_engine(); |
881 | + auto timezone = std::make_shared<FileTimezone>(TIMEZONE_FILE); |
882 | + auto state = create_state(engine, timezone); |
883 | + auto actions = std::make_shared<LiveActions>(state); |
884 | MenuFactory factory(actions, state); |
885 | |
886 | - // snap decisions |
887 | - std::shared_ptr<UpcomingPlanner> upcoming_planner(new UpcomingPlanner(std::shared_ptr<RangePlanner>(new SimpleRangePlanner(engine, file_timezone)), now)); |
888 | - ClockWatcherImpl clock_watcher(live_clock, upcoming_planner); |
889 | + // set up the snap decisions |
890 | Snap snap; |
891 | - clock_watcher.alarm_reached().connect([&snap](const Appointment& appt){ |
892 | + auto alarm_queue = create_simple_alarm_queue(state->clock, engine, timezone); |
893 | + alarm_queue->alarm_reached().connect([&snap](const Appointment& appt){ |
894 | auto snap_show = [](const Appointment& a){ |
895 | const char* url; |
896 | if(!a.url.empty()) |
897 | |
898 | === modified file 'src/planner-range.cpp' |
899 | --- src/planner-range.cpp 2014-03-10 03:26:26 +0000 |
900 | +++ src/planner-range.cpp 2014-06-11 04:07:06 +0000 |
901 | @@ -34,7 +34,7 @@ |
902 | m_range(std::pair<DateTime,DateTime>(DateTime::NowLocal(), DateTime::NowLocal())) |
903 | { |
904 | engine->changed().connect([this](){ |
905 | - g_debug("RangePlanner %p rebuilding soon because Engine %p emitted 'changed' signal%p", this, m_engine.get()); |
906 | + g_debug("RangePlanner %p rebuilding soon because Engine %p emitted 'changed' signal", this, m_engine.get()); |
907 | rebuild_soon(); |
908 | }); |
909 | |
910 | |
911 | === added file 'src/wakeup-timer-mainloop.cpp' |
912 | --- src/wakeup-timer-mainloop.cpp 1970-01-01 00:00:00 +0000 |
913 | +++ src/wakeup-timer-mainloop.cpp 2014-06-11 04:07:06 +0000 |
914 | @@ -0,0 +1,138 @@ |
915 | +/* |
916 | + * Copyright 2014 Canonical Ltd. |
917 | + * |
918 | + * This program is free software: you can redistribute it and/or modify it |
919 | + * under the terms of the GNU General Public License version 3, as published |
920 | + * by the Free Software Foundation. |
921 | + * |
922 | + * This program is distributed in the hope that it will be useful, but |
923 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
924 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
925 | + * PURPOSE. See the GNU General Public License for more details. |
926 | + * |
927 | + * You should have received a copy of the GNU General Public License along |
928 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
929 | + * |
930 | + * Authors: |
931 | + * Charles Kerr <charles.kerr@canonical.com> |
932 | + */ |
933 | + |
934 | +#include <datetime/wakeup-timer-mainloop.h> |
935 | + |
936 | +#include <glib.h> |
937 | + |
938 | +#include <cstdlib> // abs() |
939 | + |
940 | +namespace unity { |
941 | +namespace indicator { |
942 | +namespace datetime { |
943 | + |
944 | +/*** |
945 | +**** |
946 | +***/ |
947 | + |
948 | +class MainloopWakeupTimer::Impl |
949 | +{ |
950 | + |
951 | +public: |
952 | + |
953 | + Impl(const std::shared_ptr<Clock>& clock): |
954 | + m_clock(clock) |
955 | + { |
956 | + } |
957 | + |
958 | + ~Impl() |
959 | + { |
960 | + cancel_timer(); |
961 | + } |
962 | + |
963 | + void set_wakeup_time(const DateTime& d) |
964 | + { |
965 | + m_wakeup_time = d; |
966 | + |
967 | + rebuild_timer(); |
968 | + } |
969 | + |
970 | + core::Signal<>& timeout() { return m_timeout; } |
971 | + |
972 | +private: |
973 | + |
974 | + void rebuild_timer() |
975 | + { |
976 | + cancel_timer(); |
977 | + |
978 | + g_return_if_fail(m_wakeup_time.is_set()); |
979 | + |
980 | + const auto now = m_clock->localtime(); |
981 | + const auto difference_usec = g_date_time_difference(m_wakeup_time.get(), now.get()); |
982 | + const guint interval_msec = std::abs(difference_usec) / 1000u; |
983 | + g_debug("%s setting wakeup timer to kick at %s, which is in %zu seconds", |
984 | + G_STRFUNC, |
985 | + m_wakeup_time.format("%F %T").c_str(), |
986 | + size_t{interval_msec/1000}); |
987 | + |
988 | + m_timeout_tag = g_timeout_add_full(G_PRIORITY_HIGH, |
989 | + interval_msec, |
990 | + on_timeout, |
991 | + this, |
992 | + nullptr); |
993 | + } |
994 | + |
995 | + static gboolean on_timeout(gpointer gself) |
996 | + { |
997 | + g_debug("%s %s", G_STRLOC, G_STRFUNC); |
998 | + static_cast<Impl*>(gself)->on_timeout(); |
999 | + return G_SOURCE_REMOVE; |
1000 | + } |
1001 | + |
1002 | + void on_timeout() |
1003 | + { |
1004 | + cancel_timer(); |
1005 | + m_timeout(); |
1006 | + } |
1007 | + |
1008 | + void cancel_timer() |
1009 | + { |
1010 | + if (m_timeout_tag != 0) |
1011 | + { |
1012 | + g_source_remove(m_timeout_tag); |
1013 | + m_timeout_tag = 0; |
1014 | + } |
1015 | + } |
1016 | + |
1017 | + core::Signal<> m_timeout; |
1018 | + const std::shared_ptr<Clock>& m_clock; |
1019 | + guint m_timeout_tag = 0; |
1020 | + DateTime m_wakeup_time; |
1021 | +}; |
1022 | + |
1023 | +/*** |
1024 | +**** |
1025 | +***/ |
1026 | + |
1027 | +MainloopWakeupTimer::MainloopWakeupTimer(const std::shared_ptr<Clock>& clock): |
1028 | + p(new Impl(clock)) |
1029 | +{ |
1030 | +} |
1031 | + |
1032 | +MainloopWakeupTimer::~MainloopWakeupTimer() |
1033 | +{ |
1034 | +} |
1035 | + |
1036 | +void MainloopWakeupTimer::set_wakeup_time(const DateTime& d) |
1037 | +{ |
1038 | + p->set_wakeup_time(d); |
1039 | +} |
1040 | + |
1041 | +core::Signal<>& MainloopWakeupTimer::timeout() |
1042 | +{ |
1043 | + return p->timeout(); |
1044 | +} |
1045 | + |
1046 | +/*** |
1047 | +**** |
1048 | +***/ |
1049 | + |
1050 | +} // namespace datetime |
1051 | +} // namespace indicator |
1052 | +} // namespace unity |
1053 | |
1054 | === added file 'src/wakeup-timer-uha.cpp' |
1055 | --- src/wakeup-timer-uha.cpp 1970-01-01 00:00:00 +0000 |
1056 | +++ src/wakeup-timer-uha.cpp 2014-06-11 04:07:06 +0000 |
1057 | @@ -0,0 +1,175 @@ |
1058 | +/* |
1059 | + * Copyright 2014 Canonical Ltd. |
1060 | + * |
1061 | + * This program is free software: you can redistribute it and/or modify it |
1062 | + * under the terms of the GNU General Public License version 3, as published |
1063 | + * by the Free Software Foundation. |
1064 | + * |
1065 | + * This program is distributed in the hope that it will be useful, but |
1066 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
1067 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1068 | + * PURPOSE. See the GNU General Public License for more details. |
1069 | + * |
1070 | + * You should have received a copy of the GNU General Public License along |
1071 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1072 | + * |
1073 | + * Authors: |
1074 | + * Charles Kerr <charles.kerr@canonical.com> |
1075 | + */ |
1076 | + |
1077 | +#include <datetime/wakeup-timer-uha.h> |
1078 | + |
1079 | +#include <ubuntu/hardware/alarm.h> |
1080 | + |
1081 | +#include <glib.h> |
1082 | + |
1083 | +#include <unistd.h> |
1084 | + |
1085 | +#include <ctime> // struct timespec |
1086 | +#include <mutex> |
1087 | +#include <thread> |
1088 | + |
1089 | +namespace unity { |
1090 | +namespace indicator { |
1091 | +namespace datetime { |
1092 | + |
1093 | +/*** |
1094 | +**** |
1095 | +***/ |
1096 | + |
1097 | +class UhaWakeupTimer::Impl |
1098 | +{ |
1099 | + |
1100 | +public: |
1101 | + |
1102 | + Impl(const std::shared_ptr<Clock>& clock): |
1103 | + m_clock(clock), |
1104 | + m_hardware_alarm(u_hardware_alarm_create()) |
1105 | + { |
1106 | + // fire up a worker thread that initially just sleeps |
1107 | + set_wakeup_time_to_the_distant_future(); |
1108 | + m_thread = std::move(std::thread([&](){threadfunc();})); |
1109 | + } |
1110 | + |
1111 | + ~Impl() |
1112 | + { |
1113 | + // tell the worker thread to wake up and exit |
1114 | + m_yielding = true; |
1115 | + set_wakeup_time(m_clock->localtime().add_full(0,0,0,0,0,0.1)); |
1116 | + |
1117 | + // wait for it to happen |
1118 | + if (m_thread.joinable()) |
1119 | + m_thread.join(); |
1120 | + |
1121 | + g_idle_remove_by_data(this); |
1122 | + |
1123 | + u_hardware_alarm_unref(m_hardware_alarm); |
1124 | + } |
1125 | + |
1126 | + void set_wakeup_time(const DateTime& d) |
1127 | + { |
1128 | + g_debug("%s %s", G_STRLOC, G_STRFUNC); |
1129 | + std::lock_guard<std::recursive_mutex> lg(m_mutex); |
1130 | + |
1131 | + const auto wakeup_time = d.to_unix(); |
1132 | + |
1133 | + // simple sanity check: don't try to wait for something that's already passed |
1134 | + const auto now = m_clock->localtime().to_unix(); |
1135 | + g_return_if_fail (wakeup_time >= now); |
1136 | + |
1137 | + struct timespec sleep_interval; |
1138 | + sleep_interval.tv_sec = wakeup_time; |
1139 | + sleep_interval.tv_nsec = 0; |
1140 | + g_debug("%s %s setting hardware wakeup time to %s (%zu seconds from now)", |
1141 | + G_STRLOC, G_STRFUNC, |
1142 | + d.format("%F %T").c_str(), |
1143 | + (size_t)(wakeup_time - now)); |
1144 | + u_hardware_alarm_set_relative_to_with_behavior(m_hardware_alarm, |
1145 | + U_HARDWARE_ALARM_TIME_REFERENCE_RTC, |
1146 | + U_HARDWARE_ALARM_SLEEP_BEHAVIOR_WAKEUP_DEVICE, |
1147 | + &sleep_interval); |
1148 | + } |
1149 | + |
1150 | + core::Signal<>& timeout() { return m_timeout; } |
1151 | + |
1152 | +private: |
1153 | + |
1154 | + void set_wakeup_time_to_the_distant_future() |
1155 | + { |
1156 | + const auto tomorrow = m_clock->localtime().add_full(0,0,1,0,0,0); |
1157 | + set_wakeup_time(tomorrow); |
1158 | + } |
1159 | + |
1160 | + static gboolean kick_idle (gpointer gself) |
1161 | + { |
1162 | + static_cast<Impl*>(gself)->m_timeout(); |
1163 | + |
1164 | + return G_SOURCE_REMOVE; |
1165 | + } |
1166 | + |
1167 | + void threadfunc() |
1168 | + { |
1169 | + while (!m_yielding) |
1170 | + { |
1171 | + // wait for the next hw alarm |
1172 | + UHardwareAlarmWaitResult wait_result; |
1173 | + g_debug ("calling wait_for_next_alarm"); |
1174 | + auto rc = u_hardware_alarm_wait_for_next_alarm(m_hardware_alarm, &wait_result); |
1175 | + g_return_if_fail (rc == U_STATUS_SUCCESS); |
1176 | + |
1177 | + // set a long wakeup interval for the next iteration of the loop. |
1178 | + // if there's another Appointment queued up by the Planner, |
1179 | + // our timeout() listener will call set_wakeup_time() to set the |
1180 | + // real wakeup interval. |
1181 | + set_wakeup_time_to_the_distant_future(); |
1182 | + |
1183 | + // delegate the kick back to the main thread |
1184 | + g_idle_add (kick_idle, this); |
1185 | + } |
1186 | + } |
1187 | + |
1188 | + core::Signal<> m_timeout; |
1189 | + std::recursive_mutex m_mutex; |
1190 | + bool m_yielding = false; |
1191 | + const std::shared_ptr<Clock>& m_clock; |
1192 | + UHardwareAlarm m_hardware_alarm = nullptr; |
1193 | + std::thread m_thread; |
1194 | +}; |
1195 | + |
1196 | +/*** |
1197 | +**** |
1198 | +***/ |
1199 | + |
1200 | +UhaWakeupTimer::UhaWakeupTimer(const std::shared_ptr<Clock>& clock): |
1201 | + p(new Impl(clock)) |
1202 | +{ |
1203 | +} |
1204 | + |
1205 | +UhaWakeupTimer::~UhaWakeupTimer() |
1206 | +{ |
1207 | +} |
1208 | + |
1209 | +bool UhaWakeupTimer::is_supported() |
1210 | +{ |
1211 | + auto hw_alarm = u_hardware_alarm_create(); |
1212 | + g_debug ("%s hardware alarm %p", G_STRFUNC, hw_alarm); |
1213 | + return hw_alarm != nullptr; |
1214 | +} |
1215 | + |
1216 | +void UhaWakeupTimer::set_wakeup_time(const DateTime& d) |
1217 | +{ |
1218 | + p->set_wakeup_time(d); |
1219 | +} |
1220 | + |
1221 | +core::Signal<>& UhaWakeupTimer::timeout() |
1222 | +{ |
1223 | + return p->timeout(); |
1224 | +} |
1225 | + |
1226 | +/*** |
1227 | +**** |
1228 | +***/ |
1229 | + |
1230 | +} // namespace datetime |
1231 | +} // namespace indicator |
1232 | +} // namespace unity |
1233 | |
1234 | === modified file 'tests/CMakeLists.txt' |
1235 | --- tests/CMakeLists.txt 2014-02-04 19:00:22 +0000 |
1236 | +++ tests/CMakeLists.txt 2014-06-11 04:07:06 +0000 |
1237 | @@ -41,8 +41,8 @@ |
1238 | target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS}) |
1239 | endfunction() |
1240 | add_test_by_name(test-actions) |
1241 | +add_test_by_name(test-alarm-queue) |
1242 | add_test_by_name(test-clock) |
1243 | -add_test_by_name(test-clock-watcher) |
1244 | add_test_by_name(test-exporter) |
1245 | add_test_by_name(test-formatter) |
1246 | add_test_by_name(test-live-actions) |
1247 | |
1248 | === renamed file 'tests/test-clock-watcher.cpp' => 'tests/test-alarm-queue.cpp' |
1249 | --- tests/test-clock-watcher.cpp 2014-03-10 02:08:47 +0000 |
1250 | +++ tests/test-alarm-queue.cpp 2014-06-11 04:07:06 +0000 |
1251 | @@ -17,7 +17,8 @@ |
1252 | * Charles Kerr <charles.kerr@canonical.com> |
1253 | */ |
1254 | |
1255 | -#include <datetime/clock-watcher.h> |
1256 | +#include <datetime/alarm-queue-simple.h> |
1257 | +#include <datetime/wakeup-timer-mainloop.h> |
1258 | |
1259 | #include <gtest/gtest.h> |
1260 | |
1261 | @@ -25,7 +26,7 @@ |
1262 | |
1263 | using namespace unity::indicator::datetime; |
1264 | |
1265 | -class ClockWatcherFixture: public StateFixture |
1266 | +class AlarmQueueFixture: public StateFixture |
1267 | { |
1268 | private: |
1269 | |
1270 | @@ -34,7 +35,8 @@ |
1271 | protected: |
1272 | |
1273 | std::vector<std::string> m_triggered; |
1274 | - std::unique_ptr<ClockWatcher> m_watcher; |
1275 | + std::shared_ptr<WakeupTimer> m_wakeup_timer; |
1276 | + std::unique_ptr<AlarmQueue> m_watcher; |
1277 | std::shared_ptr<RangePlanner> m_range_planner; |
1278 | std::shared_ptr<UpcomingPlanner> m_upcoming; |
1279 | |
1280 | @@ -42,9 +44,10 @@ |
1281 | { |
1282 | super::SetUp(); |
1283 | |
1284 | + m_wakeup_timer.reset(new MainloopWakeupTimer(m_state->clock)); |
1285 | m_range_planner.reset(new MockRangePlanner); |
1286 | m_upcoming.reset(new UpcomingPlanner(m_range_planner, m_state->clock->localtime())); |
1287 | - m_watcher.reset(new ClockWatcherImpl(m_state->clock, m_upcoming)); |
1288 | + m_watcher.reset(new SimpleAlarmQueue(m_state->clock, m_upcoming, m_wakeup_timer)); |
1289 | m_watcher->alarm_reached().connect([this](const Appointment& appt){ |
1290 | m_triggered.push_back(appt.uid); |
1291 | }); |
1292 | @@ -108,7 +111,7 @@ |
1293 | **** |
1294 | ***/ |
1295 | |
1296 | -TEST_F(ClockWatcherFixture, AppointmentsChanged) |
1297 | +TEST_F(AlarmQueueFixture, AppointmentsChanged) |
1298 | { |
1299 | // Add some appointments to the planner. |
1300 | // One of these matches our state's localtime, so that should get triggered. |
1301 | @@ -117,12 +120,12 @@ |
1302 | m_range_planner->appointments().set(a); |
1303 | |
1304 | // Confirm that it got fired |
1305 | - EXPECT_EQ(1, m_triggered.size()); |
1306 | + ASSERT_EQ(1, m_triggered.size()); |
1307 | EXPECT_EQ(a[0].uid, m_triggered[0]); |
1308 | } |
1309 | |
1310 | |
1311 | -TEST_F(ClockWatcherFixture, TimeChanged) |
1312 | +TEST_F(AlarmQueueFixture, TimeChanged) |
1313 | { |
1314 | // Add some appointments to the planner. |
1315 | // Neither of these match the state's localtime, so nothing should be triggered. |
1316 | @@ -132,26 +135,27 @@ |
1317 | |
1318 | // Set the state's clock to a time that matches one of the appointments(). |
1319 | // That appointment should get triggered. |
1320 | +g_message ("%s setting clock to %s", G_STRLOC, a[1].begin.format("%F %T").c_str()); |
1321 | m_mock_state->mock_clock->set_localtime(a[1].begin); |
1322 | - EXPECT_EQ(1, m_triggered.size()); |
1323 | + ASSERT_EQ(1, m_triggered.size()); |
1324 | EXPECT_EQ(a[1].uid, m_triggered[0]); |
1325 | } |
1326 | |
1327 | |
1328 | -TEST_F(ClockWatcherFixture, MoreThanOne) |
1329 | +TEST_F(AlarmQueueFixture, MoreThanOne) |
1330 | { |
1331 | const auto now = m_state->clock->localtime(); |
1332 | std::vector<Appointment> a = build_some_appointments(); |
1333 | a[0].begin = a[1].begin = now; |
1334 | m_range_planner->appointments().set(a); |
1335 | |
1336 | - EXPECT_EQ(2, m_triggered.size()); |
1337 | + ASSERT_EQ(2, m_triggered.size()); |
1338 | EXPECT_EQ(a[0].uid, m_triggered[0]); |
1339 | EXPECT_EQ(a[1].uid, m_triggered[1]); |
1340 | } |
1341 | |
1342 | |
1343 | -TEST_F(ClockWatcherFixture, NoDuplicates) |
1344 | +TEST_F(AlarmQueueFixture, NoDuplicates) |
1345 | { |
1346 | // Setup: add an appointment that gets triggered. |
1347 | const auto now = m_state->clock->localtime(); |
1348 | @@ -160,13 +164,13 @@ |
1349 | a.push_back(appointments[0]); |
1350 | a[0].begin = now; |
1351 | m_range_planner->appointments().set(a); |
1352 | - EXPECT_EQ(1, m_triggered.size()); |
1353 | + ASSERT_EQ(1, m_triggered.size()); |
1354 | EXPECT_EQ(a[0].uid, m_triggered[0]); |
1355 | |
1356 | // Now change the appointment vector by adding one to it. |
1357 | - // Confirm that the ClockWatcher doesn't re-trigger a[0] |
1358 | + // Confirm that the AlarmQueue doesn't re-trigger a[0] |
1359 | a.push_back(appointments[1]); |
1360 | m_range_planner->appointments().set(a); |
1361 | - EXPECT_EQ(1, m_triggered.size()); |
1362 | + ASSERT_EQ(1, m_triggered.size()); |
1363 | EXPECT_EQ(a[0].uid, m_triggered[0]); |
1364 | } |
+ std::vector< Appointment> find_current_ alarms( ) const;
Doesn't that mean that the Appointment object will get copied when put in the vector?
+ bool is_set() const { return m_dt.get() != nullptr; }
I think that you don't need the "get()" here, the "!=" is overridden so you can just do "!= nullptr"
In SimpleAlarmQueue it'd be nice to not have m_time and m_timer, easy to get them confused (I did)
824 + const auto difference_usec = g_date_ time_difference (m_wakeup_ time.get( ), now.get()); difference_ usec / 1000u;
825 + const guint interval_msec = (guint)
Seems like we shouldn't just cast this to make it unsigned. abs? Or check the negative case?
Not sure how I feel about UhaWakeupTimer, it seems like you're basically creating a new GSource. But out of band. I'm not sure that it wouldn't be better to actually create a new GSource, thoughts?