Merge lp:~pitti/platform-api/test-backend into lp:platform-api

Proposed by Martin Pitt
Status: Merged
Approved by: Ricardo Mendoza
Approved revision: 207
Merged at revision: 182
Proposed branch: lp:~pitti/platform-api/test-backend
Merge into: lp:platform-api
Diff against target: 1137 lines (+988/-11)
13 files modified
CMakeLists.txt (+6/-0)
debian/control (+18/-0)
debian/libubuntu-application-api-test1.docs (+1/-0)
debian/libubuntu-application-api-test1.install (+1/-0)
debian/rules (+6/-0)
src/ubuntu/CMakeLists.txt (+2/-1)
src/ubuntu/hybris/CMakeLists.txt (+1/-0)
src/ubuntu/hybris/bridge.h (+29/-10)
src/ubuntu/testbackend/CMakeLists.txt (+21/-0)
src/ubuntu/testbackend/README.md (+77/-0)
src/ubuntu/testbackend/ubuntu_application_sensors.cpp (+553/-0)
tests/CMakeLists.txt (+30/-0)
tests/test_ubuntu_application_sensors.cpp (+243/-0)
To merge this branch: bzr merge lp:~pitti/platform-api/test-backend
Reviewer Review Type Date Requested Status
Ricardo Mendoza (community) Approve
PS Jenkins bot continuous-integration Approve
Thomas Voß (community) Approve
Review via email: mp+198098@code.launchpad.net

Commit message

Add backend for simulated sensor data.

Description of the change

This provides an initial implementation of simulated sensors, as discussed in
http://pad.ubuntu.com/sensors-testing.

You can now run an app with the simulated sensor backend
(UBUNTU_PLATFORM_API_BACKEND=libubuntu_application_test_api.so) and point it to
a simulation data file (UBUNTU_PLATFORM_API_SENSOR_TEST=/path/to/test.sensor)
and get these events delivered.

This also introduces a test suite and tests for the simulation sensor backend.

Note that this will currently fail, we need to land
https://code.launchpad.net/~thomas-voss/process-cpp/fix_pkgconfig_setup/+merge/198025
and then add a versioned build dep. This also adopts the rather higher-level black magic TEST_FP macro, so that this can go away.

This is an initial MP for reviewing the general structure, my code style (I'm a
C++ novice, so please tell me what to improve), the test structure, etc.

To post a comment you must log in.
Revision history for this message
Martin Pitt (pitti) wrote :

Note that this just provides the initial building blocks. Once that lands, we most probably want to add some more commands to the test data files, such as a command to create a set of standard sensors, or composite events like "turn device by 90 degrees" (either by new commands, or by providing a library of test data files, remains to be discussed).

I'll also create some tests in qtubuntu-sensors which use the QtSensors API, to ensure that the data is correctly passed back and forth through QtSensors/qtubuntu-sensors/platform-api.

Revision history for this message
Martin Pitt (pitti) wrote :

Note to self: Need to package/ship new backend and README.

Revision history for this message
Thomas Voß (thomas-voss) wrote :

Looks great, thanks for getting the testing effort started :)

A few minor niggles:

l. 300ff: You can switch "class" to "struct" and get rid of the explicit "public" specifiers. No need to make it a class if default visibility is public.

l. 341ff: Instead of returning a pointer (and managing its lifetime), you could as well return a mutable reference and initialize it as in:

static SensorController& instance()
{
    static SensorController inst_;
    return inst_;
}

With that, the instance is created exactly once on first access, and released after main automatically.

In line 381, you could then make the type->sensor instance mapping non-static, and switch to a shared_ptr for handling the lifetime of the pointer: map<ubuntu_sensor_type, std::shared_ptr<TestSensor>> sensors.

For stylistic karma: The functions handling time could be switched over to use std::chrono (see http://en.cppreference.com/w/cpp/chrono/duration). With that, you don't need comments in the source code specifying the timebase but just return std::chrono::microseconds or std::chrono::nanoseconds. Casting between time bases happens automatically then. With std::chrono, the current time can be sampled with std::chrono::high_resolution_clock::now() or std::chrono::steady_clock::now().

review: Needs Fixing
Revision history for this message
Martin Pitt (pitti) wrote :

Did the changes Thomas suggested in his review, thanks!

Revision history for this message
Martin Pitt (pitti) wrote :

More code review appreciated, but so far I'm happy with this as a first version. Plan:

- Wait for process-cpp to land, then bump build-dep on it in this MP
- Get this MP landed
- Add some high-level integration tests to qtubuntu-sensors which use the QtSensors API, to make sure that qtsensors-opensource-src → qtubuntusensors → platform-api communication all works (not blocked by the above, can be developed in parallel)
- land these tests

After that we should meet with some app developers to discuss what kind of more abstract events they would like to get, and add them to our sensor test API (the file parser).

Revision history for this message
Martin Pitt (pitti) wrote :

process-cpp landed at last, so I made the necessary build-dep changes and dropped TEST_FP which now moved into process-cpp. Ready now from my POV.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~pitti/platform-api/test-backend updated
203. By Martin Pitt

Declare functions which return float as "aapcs" calling convention on ARM, like the hybris library

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~pitti/platform-api/test-backend updated
204. By Martin Pitt

avoid integer overflow in itimerspec calculation, and fix precision warnings

Revision history for this message
Thomas Voß (thomas-voss) wrote :

LGTM, again: Thanks for getting this started.

review: Approve
Revision history for this message
Martin Pitt (pitti) wrote :

Ricardo, can you please do another review, and top-approve if you are happy with it? Thanks!

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Martin Pitt (pitti) wrote :

Notes from IRC from Rick: It should stop building a *.so symlink for the test backend, and libubuntu-application-test-api1 should be libubuntu-application-api-test1 to follow naming for mirserver/mirclient/hybris backends.

Another thing to look at: the test .so only provides the sensor functions, not the whole thing; the bridge could be more clever about that and load the other symbols from the real backend; but that's supposedly not blocking the MP.

lp:~pitti/platform-api/test-backend updated
205. By Martin Pitt

merge with trunk

206. By Martin Pitt

Don't install a *.so symlink for libubuntu_application_test_api

This is not a development library to link against, and users (i. e. test
suites) should always specify the ABI version.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ricardo Mendoza (ricmm) wrote :

As said by pitti the missing providers for non-sensor related helpers is not a blocker for this MR, as this lays the groundwork for the general testing and implements only the sensor backend.

A followup MR will split backends and make more smart use of the bridge to dynamically load each component area.

Currently just missing the package/SO rename and it should be good to go.

review: Needs Fixing
lp:~pitti/platform-api/test-backend updated
207. By Martin Pitt

rename libubuntu-application-test-api1 to libubuntu-application-api-test1

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ricardo Mendoza (ricmm) wrote :

Looks good, tested across devices. All comments addressed.

Landing.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2013-08-22 06:32:14 +0000
3+++ CMakeLists.txt 2014-01-08 15:17:50 +0000
4@@ -93,3 +93,9 @@
5 add_subdirectory(doc/)
6 add_subdirectory(include/)
7 add_subdirectory(src/)
8+
9+#### Enable tests
10+include(CTest)
11+set(GTEST_ROOT /usr/src/gtest)
12+add_subdirectory(tests/)
13+add_subdirectory(${GTEST_ROOT} ${CMAKE_CURRENT_BINARY_DIR}/gtest)
14
15=== modified file 'debian/control'
16--- debian/control 2014-01-02 21:25:57 +0000
17+++ debian/control 2014-01-08 15:17:50 +0000
18@@ -17,6 +17,8 @@
19 libdbus-1-dev,
20 dbus-cpp-dev,
21 libubuntu-location-service-dev,
22+ libgtest-dev,
23+ libprocess-cpp-dev (>= 0.0.1+14.04.20131212),
24 Standards-Version: 3.9.4
25 Homepage: https://launchpad.net/platform-api
26 Vcs-Bzr: lp:platform-api
27@@ -142,6 +144,22 @@
28 The produced library should be used via libhybris, to communicate with the
29 Android userspace, which is where the Ubuntu Application Manager lives.
30
31+Package: libubuntu-application-api-test1
32+Section: libs
33+Architecture: any
34+Pre-Depends: ${misc:Pre-Depends},
35+Multi-Arch: same
36+Depends: ${misc:Depends},
37+ ${shlibs:Depends},
38+Description: test implementation of the Platform API
39+ This package provides an implementation of the Platform API for testing. It
40+ does not communicate with actual hardware, but reads input from a text file.
41+ .
42+ You need to explicitly enable this at runtime. Please see the README for
43+ details.
44+ .
45+ For now this provides simulated sensors.
46+
47 Package: libplatform-api1-hybris-tests
48 Architecture: any
49 Depends: ${misc:Depends},
50
51=== added file 'debian/libubuntu-application-api-test1.docs'
52--- debian/libubuntu-application-api-test1.docs 1970-01-01 00:00:00 +0000
53+++ debian/libubuntu-application-api-test1.docs 2014-01-08 15:17:50 +0000
54@@ -0,0 +1,1 @@
55+src/ubuntu/testbackend/README.md
56
57=== added file 'debian/libubuntu-application-api-test1.install'
58--- debian/libubuntu-application-api-test1.install 1970-01-01 00:00:00 +0000
59+++ debian/libubuntu-application-api-test1.install 2014-01-08 15:17:50 +0000
60@@ -0,0 +1,1 @@
61+usr/lib/*/libubuntu_application_api_test.so.*
62
63=== modified file 'debian/rules'
64--- debian/rules 2013-08-14 12:16:09 +0000
65+++ debian/rules 2014-01-08 15:17:50 +0000
66@@ -13,3 +13,9 @@
67
68 overrid_dh_install:
69 dh_install --fail-missing
70+
71+override_dh_auto_test:
72+ifeq (, $(findstring nocheck, $(DEB_BUILD_OPTIONS)))
73+ cd obj-* && ctest --verbose
74+endif
75+
76
77=== modified file 'src/ubuntu/CMakeLists.txt'
78--- src/ubuntu/CMakeLists.txt 2013-08-23 13:48:59 +0000
79+++ src/ubuntu/CMakeLists.txt 2014-01-08 15:17:50 +0000
80@@ -3,6 +3,7 @@
81 )
82
83 add_subdirectory(application)
84+add_subdirectory(testbackend)
85
86 set(
87 UBUNTU_APPLICATION_API_LINK_LIBRARIES
88@@ -25,4 +26,4 @@
89
90 if(ENABLE_MIRCLIENT_IMPLEMENTATION)
91 add_subdirectory(mirclient/)
92-endif()
93\ No newline at end of file
94+endif()
95
96=== modified file 'src/ubuntu/hybris/CMakeLists.txt'
97--- src/ubuntu/hybris/CMakeLists.txt 2013-08-17 05:22:31 +0000
98+++ src/ubuntu/hybris/CMakeLists.txt 2014-01-08 15:17:50 +0000
99@@ -27,6 +27,7 @@
100
101 target_link_libraries(
102 ubuntu_platform_hardware_api
103+ dl
104 hybris-common
105 )
106
107
108=== modified file 'src/ubuntu/hybris/bridge.h'
109--- src/ubuntu/hybris/bridge.h 2013-12-03 07:27:23 +0000
110+++ src/ubuntu/hybris/bridge.h 2014-01-08 15:17:50 +0000
111@@ -22,6 +22,8 @@
112 #include <assert.h>
113 #include <dlfcn.h>
114 #include <stddef.h>
115+#include <stdlib.h>
116+#include <string.h>
117
118 #define HIDDEN_SYMBOL __attribute__ ((visibility ("hidden")))
119
120@@ -39,19 +41,24 @@
121 namespace internal
122 {
123
124+/* By default we load the backend from /system/lib/libubuntu_application_api.so
125+ * Programs can select a different backend with $UBUNTU_PLATFORM_API_BACKEND,
126+ * which either needs to be a full path or just the file name (then it will be
127+ * looked up in the usual library search path, see dlopen(3)).
128+ */
129 struct HIDDEN_SYMBOL ToApplication
130 {
131 static const char* path()
132 {
133- return "/system/lib/libubuntu_application_api.so";
134- }
135-};
136-
137-struct HIDDEN_SYMBOL ToHardware
138-{
139- static const char* path()
140- {
141- return "/system/lib/libubuntu_platform_hardware_api.so";
142+ static const char* cache = NULL;
143+
144+ if (cache == NULL) {
145+ cache = secure_getenv("UBUNTU_PLATFORM_API_BACKEND");
146+ if (cache == NULL)
147+ cache = "/system/lib/libubuntu_application_api.so";
148+ }
149+
150+ return cache;
151 }
152 };
153
154@@ -67,12 +74,23 @@
155
156 void* resolve_symbol(const char* symbol) const
157 {
158- return android_dlsym(lib_handle, symbol);
159+ return dlsym_fn(lib_handle, symbol);
160 }
161
162 protected:
163 Bridge() : lib_handle(android_dlopen(Scope::path(), RTLD_LAZY))
164 {
165+ const char* path = Scope::path();
166+ /* use Android dl functions for Android libs in /system/, glibc dl
167+ * functions for others */
168+ if (strncmp(path, "/system/", 8) == 0) {
169+ lib_handle = android_dlopen(path, RTLD_LAZY);
170+ dlsym_fn = android_dlsym;
171+ } else {
172+ lib_handle = dlopen(path, RTLD_LAZY);
173+ dlsym_fn = dlsym;
174+ }
175+
176 assert(lib_handle && "Error loading ubuntu_application_api");
177 }
178
179@@ -82,6 +100,7 @@
180 }
181
182 void* lib_handle;
183+ void* (*dlsym_fn) (void*, const char*);
184 };
185
186 }
187
188=== added directory 'src/ubuntu/testbackend'
189=== added file 'src/ubuntu/testbackend/CMakeLists.txt'
190--- src/ubuntu/testbackend/CMakeLists.txt 1970-01-01 00:00:00 +0000
191+++ src/ubuntu/testbackend/CMakeLists.txt 2014-01-08 15:17:50 +0000
192@@ -0,0 +1,21 @@
193+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11")
194+
195+add_library(
196+ ubuntu_application_api_test SHARED
197+ ubuntu_application_sensors.cpp
198+)
199+
200+set_target_properties(
201+ ubuntu_application_api_test
202+ PROPERTIES
203+ VERSION ${UBUNTU_PLATFORM_API_VERSION_MAJOR}.${UBUNTU_PLATFORM_API_VERSION_MINOR}.${UBUNTU_PLATFORM_API_VERSION_PATCH}
204+ SOVERSION ${UBUNTU_PLATFORM_API_VERSION_MAJOR}
205+)
206+
207+install(
208+ TARGETS ubuntu_application_api_test
209+ # this is not a development library to compile against, users should always
210+ # specify the SONAME; so don't build a *.so
211+ LIBRARY DESTINATION "${LIB_INSTALL_DIR}" NAMELINK_SKIP
212+)
213+
214
215=== added file 'src/ubuntu/testbackend/README.md'
216--- src/ubuntu/testbackend/README.md 1970-01-01 00:00:00 +0000
217+++ src/ubuntu/testbackend/README.md 2014-01-08 15:17:50 +0000
218@@ -0,0 +1,77 @@
219+Testing applications with simulated sensor data
220+===============================================
221+
222+Purpose
223+-------
224+platform-api's interface to sensor data is in the shared library
225+`libubuntu_platform_hardware_api.so`. That is only a stub which dynamically
226+(dlopen) loads a backend library which provides the actual implementation. By
227+default this is `/system/lib/libubuntu_application_api.so` which reads sensor
228+data from the Android side. For testing purposes this can be replaced with this
229+`libubuntu_application_api_test.so.1` which simulates sensors and their data based
230+on a simple text input file.
231+
232+Using the test sensors
233+----------------------
234+Run your application under test with the environment variable
235+
236+ UBUNTU_PLATFORM_API_BACKEND=libubuntu_application_api_test.so.1
237+
238+and make sure that ld.so(8) can find it. If you don't have the library
239+installed in a standard system library path, it is recommended to set
240+`LD_LIBRARY_PATH` to the directory that contains the library (usually when using
241+the library right out of the build tree). Alternatively you can specify the
242+full path in `$UBUNTU_PLATFORM_API_BACKEND`.
243+
244+The env variable `$UBUNTU_PLATFORM_API_SENSOR_TEST` needs to point to a file that
245+describes the desired sensor behaviour.
246+
247+Data format
248+-----------
249+The test sensors use a simple line based file format. The first part
250+instantiates desired sensors with their parameters:
251+
252+ create [accel|light] <min> <max> <resolution>
253+ # but no arguments for proximity sensor:
254+ create proximity
255+
256+After that, it defines events; <delay> specifies time after previous event
257+in ms:
258+
259+ <delay> proximity [unknown|near|far]
260+ <delay> light <value>
261+ <delay> accel <x> <y> <z>
262+
263+Empty lines and comment lines (starting with #) are allowed.
264+
265+Example file:
266+
267+ create light 0 10 1
268+ create accel 0 1000 0.1
269+ create proximity
270+
271+ 200 proximity near
272+ 500 light 5
273+ # simulate crash on the ground
274+ 500 accel 0.2 0.1 10
275+ 100 accel 0.2 0.2 1000
276+ 20 accel 0 0 0
277+ 10 proximity far
278+ 0 light 10
279+
280+
281+Complete example
282+----------------
283+ * Build platform-api:
284+
285+ mkdir obj; (cd obj; cmake .. && make)
286+
287+ * Put above example file into /tmp/test.sensors
288+
289+ * Run the sensor test with it:
290+
291+ LD_LIBRARY_PATH=obj/src/ubuntu/testbackend \
292+ UBUNTU_PLATFORM_API_BACKEND=libubuntu_application_api_test.so.1 \
293+ UBUNTU_PLATFORM_API_SENSOR_TEST=/tmp/test.sensors \
294+ obj/src/ubuntu/hybris/tests/test_android_sensors_api
295+
296
297=== added file 'src/ubuntu/testbackend/ubuntu_application_sensors.cpp'
298--- src/ubuntu/testbackend/ubuntu_application_sensors.cpp 1970-01-01 00:00:00 +0000
299+++ src/ubuntu/testbackend/ubuntu_application_sensors.cpp 2014-01-08 15:17:50 +0000
300@@ -0,0 +1,553 @@
301+/*
302+ * Copyright (C) 2013 Canonical Ltd
303+ *
304+ * This program is free software: you can redistribute it and/or modify
305+ * it under the terms of the GNU Lesser General Public License version 3 as
306+ * published by the Free Software Foundation.
307+ *
308+ * This program is distributed in the hope that it will be useful,
309+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
310+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
311+ * GNU Lesser General Public License for more details.
312+ *
313+ * You should have received a copy of the GNU Lesser General Public License
314+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
315+ *
316+ * Authored by: Martin Pitt <martin.pitti@ubuntu.com>
317+ */
318+
319+#include <ubuntu/application/sensors/ubuntu_application_sensors.h>
320+#include <ubuntu/application/sensors/accelerometer.h>
321+#include <ubuntu/application/sensors/proximity.h>
322+#include <ubuntu/application/sensors/light.h>
323+
324+#include <cstddef>
325+#include <cstdlib>
326+#include <cstring>
327+#include <cerrno>
328+#include <csignal>
329+#include <iostream>
330+#include <sstream>
331+#include <fstream>
332+#include <stdexcept>
333+#include <chrono>
334+#include <map>
335+#include <memory>
336+
337+using namespace std;
338+
339+// necessary for functions that return float
340+// pcs attribute (calling convention) is only defined on ARM, avoid warning on
341+// other platforms
342+#ifdef __arm__
343+#define __SF_FN_ATTR __attribute__((pcs("aapcs")))
344+#else
345+#define __SF_FN_ATTR
346+#endif
347+
348+
349+/***************************************
350+ *
351+ * test sensor implementation
352+ *
353+ ***************************************/
354+
355+// this is only internal API, so we make everything public
356+struct TestSensor
357+{
358+ TestSensor(ubuntu_sensor_type _type, float _min_value, float _max_value, float _resolution) :
359+ type(_type),
360+ enabled(false),
361+ resolution(_resolution),
362+ min_delay(0),
363+ min_value(_min_value),
364+ max_value(_max_value),
365+ on_event_cb(NULL),
366+ event_cb_context(NULL),
367+ x(_min_value),
368+ y(_min_value),
369+ z(_min_value),
370+ distance((UASProximityDistance) 0), // LP#1256969
371+ timestamp(0)
372+ {}
373+
374+ ubuntu_sensor_type type;
375+ bool enabled;
376+ float resolution;
377+ uint32_t min_delay;
378+ float min_value, max_value;
379+ void (*on_event_cb)(void*, void*);
380+ void* event_cb_context;
381+
382+ /* current value; note that we do not track separate Event objects/pointers
383+ * at all, and just always deliver the current value */
384+ float x, y, z;
385+ UASProximityDistance distance;
386+ uint64_t timestamp;
387+};
388+
389+/* Singleton which reads the sensor data file and maintains the TestSensor
390+ * instances */
391+class SensorController
392+{
393+ public:
394+ // Ensure that controller is initialized, and return singleton
395+ static SensorController& instance()
396+ {
397+ static SensorController _inst;
398+ return _inst;
399+ }
400+
401+ // Return TestSensor of given type, or NULL if it doesn't exist
402+ TestSensor* get(ubuntu_sensor_type type)
403+ {
404+ try {
405+ return sensors.at(type).get();
406+ } catch (const out_of_range&) {
407+ return NULL;
408+ }
409+ }
410+
411+ private:
412+ SensorController();
413+ bool next_command();
414+ bool process_create_command();
415+ void process_event_command();
416+ void setup_timer(unsigned delay_ms);
417+ static void on_timer(union sigval sval);
418+
419+ static ubuntu_sensor_type type_from_name(const string& type)
420+ {
421+ if (type == "light")
422+ return ubuntu_sensor_type_light;
423+ if (type == "proximity")
424+ return ubuntu_sensor_type_proximity;
425+ if (type == "accel")
426+ return ubuntu_sensor_type_accelerometer;
427+
428+ cerr << "TestSensor ERROR: unknown sensor type " << type << endl;
429+ abort();
430+ }
431+
432+ map<ubuntu_sensor_type, shared_ptr<TestSensor>> sensors;
433+ ifstream data;
434+
435+ // current command/event
436+ string current_command;
437+ TestSensor* event_sensor;
438+ float event_x, event_y, event_z;
439+ UASProximityDistance event_distance;
440+};
441+
442+SensorController::SensorController()
443+{
444+ const char* path = getenv("UBUNTU_PLATFORM_API_SENSOR_TEST");
445+
446+ if (path == NULL) {
447+ cerr << "TestSensor ERROR: Need $UBUNTU_PLATFORM_API_SENSOR_TEST to point to a data file\n";
448+ abort();
449+ }
450+
451+ //cout << "SensorController ctor: opening " << path << endl;
452+
453+ data.open(path);
454+ if (!data.is_open()) {
455+ cerr << "TestSensor ERROR: Failed to open data file " << path << ": " << strerror(errno) << endl;
456+ abort();
457+ }
458+
459+ // process all "create" commands
460+ while (next_command()) {
461+ if (!process_create_command())
462+ break;
463+ }
464+
465+ // start event processing
466+ if (!data.eof())
467+ process_event_command();
468+}
469+
470+bool
471+SensorController::next_command()
472+{
473+ while (getline(data, current_command)) {
474+ // trim leading and trailing space
475+ current_command.erase(0, current_command.find_first_not_of(" \t"));
476+ current_command.erase(current_command.find_last_not_of(" \t") + 1);
477+ // ignore empty or comment lines
478+ if (current_command.size() == 0 || current_command[0] == '#')
479+ continue;
480+ return true;
481+ }
482+ return false;
483+}
484+
485+bool
486+SensorController::process_create_command()
487+{
488+ stringstream ss(current_command, ios_base::in);
489+ string token;
490+
491+ // we only process "create" commands here; if we have something else, stop
492+ ss >> token;
493+ if (token != "create")
494+ return false;
495+
496+ ss >> token;
497+ ubuntu_sensor_type type = type_from_name(token);
498+
499+ if (get(type) != NULL) {
500+ cerr << "TestSensor ERROR: duplicate creation of sensor type " << token << endl;
501+ abort();
502+ }
503+
504+ float min = 0, max = 0, resolution = 0;
505+
506+ if (type != ubuntu_sensor_type_proximity) {
507+ // read min, max, resolution
508+ ss >> min >> max >> resolution;
509+
510+ if (max <= min) {
511+ cerr << "TestSensor ERROR: max_value must be >= min_value in " << current_command << endl;
512+ abort();
513+ }
514+ if (resolution <= 0) {
515+ cerr << "TestSensor ERROR: resolution must be > 0 in " << current_command << endl;
516+ abort();
517+ }
518+ }
519+
520+ //cout << "SensorController::process_create_command: type " << type << " min " << min << " max " << max << " res " << resolution << endl;
521+
522+ sensors[type] = make_shared<TestSensor>(type, min, max, resolution);
523+ return true;
524+}
525+
526+void
527+SensorController::process_event_command()
528+{
529+ stringstream ss(current_command, ios_base::in);
530+ int delay;
531+
532+ //cout << "TestSensor: processing event " << current_command << endl;
533+
534+ // parse delay
535+ ss >> delay;
536+ if (delay <= 0) {
537+ cerr << "TestSensor ERROR: delay must be positive in command " << current_command << endl;
538+ abort();
539+ }
540+
541+ // parse sensor type
542+ string token;
543+ ss >> token;
544+ ubuntu_sensor_type type = type_from_name(token);
545+ event_sensor = get(type);
546+ if (event_sensor == NULL) {
547+ cerr << "TestSensor ERROR: sensor does not exist, you need to create it: " << token << endl;
548+ abort();
549+ }
550+
551+ switch (type) {
552+ case ubuntu_sensor_type_light:
553+ ss >> event_x;
554+ //cout << "got event: sensor type " << type << " (light), delay "
555+ // << delay << " ms, value " << event_x << endl;
556+ break;
557+
558+ case ubuntu_sensor_type_accelerometer:
559+ ss >> event_x >> event_y >> event_z;
560+ //cout << "got event: sensor type " << type << " (accel), delay "
561+ // << delay << " ms, value " << event_x << "/" << event_y << "/" << event_z << endl;
562+ break;
563+
564+ case ubuntu_sensor_type_proximity:
565+ ss >> token;
566+ if (token == "unknown")
567+ event_distance = (UASProximityDistance) 0; // LP#1256969
568+ else if (token == "near")
569+ event_distance = U_PROXIMITY_NEAR;
570+ else if (token == "far")
571+ event_distance = U_PROXIMITY_FAR;
572+ else {
573+ cerr << "TestSensor ERROR: unknown proximity value " << token << endl;
574+ abort();
575+ }
576+ //cout << "got event: sensor type " << type << " (proximity), delay "
577+ // << delay << " ms, value " << int(event_distance) << endl;
578+ break;
579+
580+ default:
581+ cerr << "TestSensor ERROR: unhandled sensor type " << token << endl;
582+ abort();
583+ }
584+
585+ // wake up after given delay for committing the change and processing the
586+ // next event
587+ setup_timer(unsigned(delay));
588+}
589+
590+void
591+SensorController::setup_timer(unsigned delay_ms)
592+{
593+ static timer_t timerid; // we keep a pointer to that until on_timer
594+ struct sigevent sev;
595+ struct itimerspec its { {0, 0}, // interval
596+ {time_t(delay_ms / 1000),
597+ long((delay_ms % 1000) * 1000000L) % 1000000000L } };
598+
599+ sev.sigev_notify = SIGEV_THREAD;
600+ sev.sigev_notify_function = SensorController::on_timer;
601+ sev.sigev_notify_attributes = NULL;
602+ sev.sigev_value.sival_ptr = &timerid;
603+
604+ if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) < 0) {
605+ perror("TestSensor ERROR: Failed to create timer");
606+ abort();
607+ }
608+ if (timer_settime(timerid, 0, &its, NULL) < 0) {
609+ perror("TestSensor ERROR: Failed to set up timer");
610+ abort();
611+ };
612+}
613+
614+void
615+SensorController::on_timer(union sigval sval)
616+{
617+ timer_t* timerid = static_cast<timer_t*>(sval.sival_ptr);
618+ //cout << "on_timer called\n";
619+ timer_delete(*timerid);
620+
621+ SensorController& sc = SensorController::instance();
622+
623+ // update sensor values, call callback
624+ if (sc.event_sensor && sc.event_sensor->enabled) {
625+ sc.event_sensor->x = sc.event_x;
626+ sc.event_sensor->y = sc.event_y;
627+ sc.event_sensor->z = sc.event_z;
628+ sc.event_sensor->distance = sc.event_distance;
629+ sc.event_sensor->timestamp = chrono::duration_cast<chrono::nanoseconds>(
630+ chrono::system_clock::now().time_since_epoch()).count();
631+ if (sc.event_sensor->on_event_cb != NULL) {
632+ //cout << "TestSensor: calling sensor callback for type " << sc.event_sensor->type << endl;
633+ sc.event_sensor->on_event_cb(sc.event_sensor, sc.event_sensor->event_cb_context);
634+ } else {
635+ //cout << "TestSensor: sensor type " << sc.event_sensor->type << "has no callback\n";
636+ }
637+ } else {
638+ //cout << "TestSensor: sensor type " << sc.event_sensor->type << "disabled, not processing event\n";
639+ }
640+
641+ // read/process next event
642+ if (sc.next_command())
643+ sc.process_event_command();
644+ else {
645+ //cout << "TestSensor: script ended, no further commands\n";
646+ }
647+}
648+
649+
650+/***************************************
651+ *
652+ * Acceleration API
653+ *
654+ ***************************************/
655+
656+UASensorsAccelerometer* ua_sensors_accelerometer_new()
657+{
658+ return SensorController::instance().get(ubuntu_sensor_type_accelerometer);
659+}
660+
661+UStatus ua_sensors_accelerometer_enable(UASensorsAccelerometer* s)
662+{
663+ static_cast<TestSensor*>(s)->enabled = true;
664+ return (UStatus) 0;
665+}
666+
667+UStatus ua_sensors_accelerometer_disable(UASensorsAccelerometer* s)
668+{
669+ static_cast<TestSensor*>(s)->enabled = false;
670+ return (UStatus) 0;
671+}
672+
673+uint32_t ua_sensors_accelerometer_get_min_delay(UASensorsAccelerometer* s)
674+{
675+ return static_cast<TestSensor*>(s)->min_delay;
676+}
677+
678+float ua_sensors_accelerometer_get_min_value(UASensorsAccelerometer* s) __SF_FN_ATTR;
679+float ua_sensors_accelerometer_get_min_value(UASensorsAccelerometer* s)
680+{
681+ return static_cast<TestSensor*>(s)->min_value;
682+}
683+
684+float ua_sensors_accelerometer_get_max_value(UASensorsAccelerometer* s) __SF_FN_ATTR;
685+float ua_sensors_accelerometer_get_max_value(UASensorsAccelerometer* s)
686+{
687+ return static_cast<TestSensor*>(s)->max_value;
688+}
689+
690+float ua_sensors_accelerometer_get_resolution(UASensorsAccelerometer* s) __SF_FN_ATTR;
691+float ua_sensors_accelerometer_get_resolution(UASensorsAccelerometer* s)
692+{
693+ return static_cast<TestSensor*>(s)->resolution;
694+}
695+
696+void ua_sensors_accelerometer_set_reading_cb(UASensorsAccelerometer* s, on_accelerometer_event_cb cb, void* ctx)
697+{
698+ TestSensor* sensor = static_cast<TestSensor*>(s);
699+ sensor->on_event_cb = cb;
700+ sensor->event_cb_context = ctx;
701+}
702+
703+uint64_t uas_accelerometer_event_get_timestamp(UASAccelerometerEvent* e)
704+{
705+ return static_cast<TestSensor*>(e)->timestamp;
706+}
707+
708+float uas_accelerometer_event_get_acceleration_x(UASAccelerometerEvent* e) __SF_FN_ATTR;
709+float uas_accelerometer_event_get_acceleration_x(UASAccelerometerEvent* e)
710+{
711+ return static_cast<TestSensor*>(e)->x;
712+}
713+
714+float uas_accelerometer_event_get_acceleration_y(UASAccelerometerEvent* e) __SF_FN_ATTR;
715+float uas_accelerometer_event_get_acceleration_y(UASAccelerometerEvent* e)
716+{
717+ return static_cast<TestSensor*>(e)->y;
718+}
719+
720+float uas_accelerometer_event_get_acceleration_z(UASAccelerometerEvent* e) __SF_FN_ATTR;
721+float uas_accelerometer_event_get_acceleration_z(UASAccelerometerEvent* e)
722+{
723+ return static_cast<TestSensor*>(e)->z;
724+}
725+
726+/***************************************
727+ *
728+ * Proximity API
729+ *
730+ ***************************************/
731+
732+UASensorsProximity* ua_sensors_proximity_new()
733+{
734+ return SensorController::instance().get(ubuntu_sensor_type_proximity);
735+}
736+
737+UStatus ua_sensors_proximity_enable(UASensorsProximity* s)
738+{
739+ static_cast<TestSensor*>(s)->enabled = true;
740+ return (UStatus) 0;
741+}
742+
743+UStatus ua_sensors_proximity_disable(UASensorsProximity* s)
744+{
745+ static_cast<TestSensor*>(s)->enabled = false;
746+ return (UStatus) 0;
747+}
748+
749+uint32_t ua_sensors_proximity_get_min_delay(UASensorsProximity* s)
750+{
751+ return static_cast<TestSensor*>(s)->min_delay;
752+}
753+
754+// the next three function make no sense in the API, just return zero
755+float ua_sensors_proximity_get_min_value(UASensorsProximity*) __SF_FN_ATTR;
756+float ua_sensors_proximity_get_min_value(UASensorsProximity*)
757+{
758+ return 0.0;
759+}
760+
761+float ua_sensors_proximity_get_max_value(UASensorsProximity*) __SF_FN_ATTR;
762+float ua_sensors_proximity_get_max_value(UASensorsProximity*)
763+{
764+ return 0.0;
765+}
766+
767+float ua_sensors_proximity_get_resolution(UASensorsProximity*) __SF_FN_ATTR;
768+float ua_sensors_proximity_get_resolution(UASensorsProximity*)
769+{
770+ return 0.0;
771+}
772+
773+void ua_sensors_proximity_set_reading_cb(UASensorsProximity* s, on_proximity_event_cb cb, void* ctx)
774+{
775+ TestSensor* sensor = static_cast<TestSensor*>(s);
776+ sensor->on_event_cb = cb;
777+ sensor->event_cb_context = ctx;
778+}
779+
780+uint64_t uas_proximity_event_get_timestamp(UASProximityEvent* e)
781+{
782+ return static_cast<TestSensor*>(e)->timestamp;
783+}
784+
785+UASProximityDistance uas_proximity_event_get_distance(UASProximityEvent* e)
786+{
787+ return static_cast<TestSensor*>(e)->distance;
788+}
789+
790+
791+/***************************************
792+ *
793+ * Light API
794+ *
795+ ***************************************/
796+
797+UASensorsLight* ua_sensors_light_new()
798+{
799+ return SensorController::instance().get(ubuntu_sensor_type_light);
800+}
801+
802+UStatus ua_sensors_light_enable(UASensorsLight* s)
803+{
804+ static_cast<TestSensor*>(s)->enabled = true;
805+ return (UStatus) 0;
806+}
807+
808+UStatus ua_sensors_light_disable(UASensorsLight* s)
809+{
810+ static_cast<TestSensor*>(s)->enabled = false;
811+ return (UStatus) 0;
812+}
813+
814+uint32_t ua_sensors_light_get_min_delay(UASensorsLight* s)
815+{
816+ return static_cast<TestSensor*>(s)->min_delay;
817+}
818+
819+float ua_sensors_light_get_min_value(UASensorsLight* s) __SF_FN_ATTR;
820+float ua_sensors_light_get_min_value(UASensorsLight* s)
821+{
822+ return static_cast<TestSensor*>(s)->min_value;
823+}
824+
825+float ua_sensors_light_get_max_value(UASensorsLight* s) __SF_FN_ATTR;
826+float ua_sensors_light_get_max_value(UASensorsLight* s)
827+{
828+ return static_cast<TestSensor*>(s)->max_value;
829+}
830+
831+float ua_sensors_light_get_resolution(UASensorsLight* s) __SF_FN_ATTR;
832+float ua_sensors_light_get_resolution(UASensorsLight* s)
833+{
834+ return static_cast<TestSensor*>(s)->resolution;
835+}
836+
837+void ua_sensors_light_set_reading_cb(UASensorsLight* s, on_light_event_cb cb, void* ctx)
838+{
839+ TestSensor* sensor = static_cast<TestSensor*>(s);
840+ sensor->on_event_cb = cb;
841+ sensor->event_cb_context = ctx;
842+}
843+
844+uint64_t uas_light_event_get_timestamp(UASLightEvent* e)
845+{
846+ return static_cast<TestSensor*>(e)->timestamp;
847+}
848+
849+float uas_light_event_get_light(UASLightEvent* e) __SF_FN_ATTR;
850+float uas_light_event_get_light(UASLightEvent* e)
851+{
852+ return static_cast<TestSensor*>(e)->x;
853+}
854
855=== added directory 'tests'
856=== added file 'tests/CMakeLists.txt'
857--- tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
858+++ tests/CMakeLists.txt 2014-01-08 15:17:50 +0000
859@@ -0,0 +1,30 @@
860+find_package(PkgConfig REQUIRED)
861+pkg_check_modules(PROCESS_CPP process-cpp REQUIRED)
862+
863+include_directories(${GTEST_ROOT}/src)
864+include_directories(${PROCESS_CPP_INCLUDE_DIRS})
865+
866+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11")
867+
868+add_executable(
869+ test_ubuntu_application_sensors
870+ test_ubuntu_application_sensors.cpp
871+)
872+
873+target_link_libraries(
874+ test_ubuntu_application_sensors
875+
876+ ubuntu_application_api
877+ gtest
878+ gtest_main
879+ ${PROCESS_CPP_LIBRARIES}
880+)
881+
882+# we need to call the tests with pointing to the locally built test platform
883+# library
884+add_test(
885+ test_ubuntu_application_sensors
886+
887+ env LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/src/ubuntu/testbackend ${CMAKE_CURRENT_BINARY_DIR}/test_ubuntu_application_sensors
888+)
889+
890
891=== added file 'tests/test_ubuntu_application_sensors.cpp'
892--- tests/test_ubuntu_application_sensors.cpp 1970-01-01 00:00:00 +0000
893+++ tests/test_ubuntu_application_sensors.cpp 2014-01-08 15:17:50 +0000
894@@ -0,0 +1,243 @@
895+/*
896+ * Copyright (C) 2013 Canonical Ltd
897+ *
898+ * This program is free software: you can redistribute it and/or modify
899+ * it under the terms of the GNU Lesser General Public License version 3 as
900+ * published by the Free Software Foundation.
901+ *
902+ * This program is distributed in the hope that it will be useful,
903+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
904+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
905+ * GNU Lesser General Public License for more details.
906+ *
907+ * You should have received a copy of the GNU Lesser General Public License
908+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
909+ *
910+ * Authored by: Martin Pitt <martin.pitti@ubuntu.com>
911+ */
912+
913+#include <cstdlib>
914+#include <cstdio>
915+#include <queue>
916+#include <chrono>
917+
918+#include <core/testing/fork_and_run.h>
919+
920+#include "gtest/gtest.h"
921+
922+#include <ubuntu/application/sensors/accelerometer.h>
923+#include <ubuntu/application/sensors/event/accelerometer.h>
924+#include <ubuntu/application/sensors/proximity.h>
925+#include <ubuntu/application/sensors/event/proximity.h>
926+#include <ubuntu/application/sensors/light.h>
927+#include <ubuntu/application/sensors/event/light.h>
928+
929+using namespace std;
930+
931+typedef chrono::time_point<chrono::system_clock,chrono::nanoseconds> time_point_system_ns;
932+
933+struct event {
934+ uint64_t timestamp;
935+ float x, y, z;
936+ UASProximityDistance distance;
937+ void* context;
938+};
939+queue<struct event> events;
940+
941+class APITest : public testing::Test
942+{
943+ protected:
944+ virtual void SetUp()
945+ {
946+ snprintf(data_file, sizeof(data_file), "%s", "/tmp/sensor_test.XXXXXX");
947+ data_fd = mkstemp(data_file);
948+ if (data_fd < 0) {
949+ perror("mkstemp");
950+ abort();
951+ }
952+ setenv("UBUNTU_PLATFORM_API_SENSOR_TEST", data_file, 1);
953+ setenv("UBUNTU_PLATFORM_API_BACKEND", "libubuntu_application_api_test.so.1", 1);
954+
955+ // ensure the queue is clear
956+ while (events.size() > 0)
957+ events.pop();
958+ }
959+
960+ virtual void TearDown()
961+ {
962+ unlink(data_file);
963+ }
964+
965+ void set_data(const char* data)
966+ {
967+ write(data_fd, data, strlen(data));
968+ fsync(data_fd);
969+ }
970+
971+ char data_file[100];
972+ int data_fd;
973+};
974+
975+// without any data, there are no sensors defined
976+TESTP_F(APITest, NoData, {
977+ EXPECT_EQ(NULL, ua_sensors_accelerometer_new());
978+ EXPECT_EQ(NULL, ua_sensors_proximity_new());
979+ EXPECT_EQ(NULL, ua_sensors_light_new());
980+})
981+
982+TESTP_F(APITest, CreateProximity, {
983+ set_data("create proximity");
984+ EXPECT_EQ(NULL, ua_sensors_accelerometer_new());
985+ EXPECT_EQ(NULL, ua_sensors_light_new());
986+
987+ UASensorsProximity *s = ua_sensors_proximity_new();
988+ EXPECT_TRUE(s != NULL);
989+})
990+
991+TESTP_F(APITest, CreateAccelerator, {
992+ set_data("create accel 0.5 1000 0.1");
993+ EXPECT_EQ(NULL, ua_sensors_proximity_new());
994+ EXPECT_EQ(NULL, ua_sensors_light_new());
995+
996+ UASensorsAccelerometer *s = ua_sensors_accelerometer_new();
997+ EXPECT_TRUE(s != NULL);
998+ EXPECT_FLOAT_EQ(0.5, ua_sensors_accelerometer_get_min_value(s));
999+ EXPECT_FLOAT_EQ(1000.0, ua_sensors_accelerometer_get_max_value(s));
1000+ EXPECT_FLOAT_EQ(0.1, ua_sensors_accelerometer_get_resolution(s));
1001+})
1002+
1003+TESTP_F(APITest, CreateLight, {
1004+ set_data("create light 0 10 0.5");
1005+ EXPECT_EQ(NULL, ua_sensors_proximity_new());
1006+ EXPECT_EQ(NULL, ua_sensors_accelerometer_new());
1007+
1008+ UASensorsLight *s = ua_sensors_light_new();
1009+ EXPECT_TRUE(s != NULL);
1010+ EXPECT_FLOAT_EQ(0.0, ua_sensors_light_get_min_value(s));
1011+ EXPECT_FLOAT_EQ(10.0, ua_sensors_light_get_max_value(s));
1012+ EXPECT_FLOAT_EQ(0.5, ua_sensors_light_get_resolution(s));
1013+})
1014+
1015+TESTP_F(APITest, ProximityEvents, {
1016+ set_data("create proximity\n"
1017+ " # some comment\n"
1018+ " \n"
1019+ "50 proximity near\n"
1020+ "100 proximity far\n"
1021+ "80 proximity unknown\n"
1022+ );
1023+
1024+ UASensorsProximity *s = ua_sensors_proximity_new();
1025+ EXPECT_TRUE(s != NULL);
1026+ ua_sensors_proximity_enable(s);
1027+ auto start_time = chrono::system_clock::now();
1028+
1029+ ua_sensors_proximity_set_reading_cb(s,
1030+ [](UASProximityEvent* ev, void* ctx) {
1031+ events.push({uas_proximity_event_get_timestamp(ev),
1032+ .0, .0, .0,
1033+ uas_proximity_event_get_distance(ev),
1034+ ctx});
1035+ }, NULL);
1036+
1037+ usleep(350000);
1038+ EXPECT_EQ(3, events.size());
1039+
1040+ auto e = events.front();
1041+ events.pop();
1042+ EXPECT_EQ(e.distance, U_PROXIMITY_NEAR);
1043+ EXPECT_EQ(NULL, e.context);
1044+ auto event_time = time_point_system_ns(std::chrono::nanoseconds(e.timestamp));
1045+ auto delay = chrono::duration_cast<chrono::milliseconds>(event_time - start_time).count();
1046+ EXPECT_GE(delay, 30);
1047+ EXPECT_LE(delay, 70);
1048+
1049+ e = events.front();
1050+ events.pop();
1051+ EXPECT_EQ(e.distance, U_PROXIMITY_FAR);
1052+ event_time = time_point_system_ns(std::chrono::nanoseconds(e.timestamp));
1053+ delay = chrono::duration_cast<chrono::milliseconds>(event_time - start_time).count();
1054+ EXPECT_GE(delay, 130);
1055+ EXPECT_LE(delay, 170);
1056+
1057+ e = events.front();
1058+ events.pop();
1059+ EXPECT_EQ(e.distance, (UASProximityDistance) 0);
1060+ event_time = time_point_system_ns(std::chrono::nanoseconds(e.timestamp));
1061+ delay = chrono::duration_cast<chrono::milliseconds>(event_time - start_time).count();
1062+ EXPECT_GE(delay, 210);
1063+ EXPECT_LE(delay, 250);
1064+})
1065+
1066+TESTP_F(APITest, LightEvents, {
1067+ set_data(" create light 0 10 1\n"
1068+ "1 light 5\n"
1069+ "100 light 8\n"
1070+ );
1071+
1072+ UASensorsLight *s = ua_sensors_light_new();
1073+ EXPECT_TRUE(s != NULL);
1074+ ua_sensors_light_enable(s);
1075+ auto start_time = chrono::system_clock::now();
1076+
1077+ ua_sensors_light_set_reading_cb(s,
1078+ [](UASLightEvent* ev, void* ctx) {
1079+ events.push({uas_light_event_get_timestamp(ev),
1080+ uas_light_event_get_light(ev), .0, .0,
1081+ (UASProximityDistance) 0, ctx});
1082+ }, NULL);
1083+
1084+ usleep(130000);
1085+ EXPECT_EQ(2, events.size());
1086+
1087+ auto e = events.front();
1088+ events.pop();
1089+ EXPECT_FLOAT_EQ(e.x, 5);
1090+ EXPECT_EQ(NULL, e.context);
1091+ auto event_time = time_point_system_ns(std::chrono::nanoseconds(e.timestamp));
1092+ auto delay = chrono::duration_cast<chrono::milliseconds>(event_time - start_time).count();
1093+ EXPECT_LE(delay, 10);
1094+
1095+ e = events.front();
1096+ events.pop();
1097+ EXPECT_FLOAT_EQ(e.x, 8);
1098+ event_time = time_point_system_ns(std::chrono::nanoseconds(e.timestamp));
1099+ delay = chrono::duration_cast<chrono::milliseconds>(event_time - start_time).count();
1100+ EXPECT_GE(delay, 91);
1101+ EXPECT_LE(delay, 111);
1102+})
1103+
1104+TESTP_F(APITest, AccelEvents, {
1105+ // cover the case of > 1 s, to ensure that we correctly do mod arithmetic
1106+ set_data("create accel -1000 1000 0.1\n"
1107+ "1100 accel 5.5 -8.5 9.9\n"
1108+ );
1109+
1110+ UASensorsAccelerometer *s = ua_sensors_accelerometer_new();
1111+ EXPECT_TRUE(s != NULL);
1112+ ua_sensors_accelerometer_enable(s);
1113+ auto start_time = chrono::system_clock::now();
1114+
1115+ ua_sensors_accelerometer_set_reading_cb(s,
1116+ [](UASAccelerometerEvent* ev, void* ctx) {
1117+ events.push({uas_accelerometer_event_get_timestamp(ev),
1118+ uas_accelerometer_event_get_acceleration_x(ev),
1119+ uas_accelerometer_event_get_acceleration_y(ev),
1120+ uas_accelerometer_event_get_acceleration_z(ev),
1121+ (UASProximityDistance) 0, ctx});
1122+ }, NULL);
1123+
1124+ usleep(1200000);
1125+ EXPECT_EQ(1, events.size());
1126+
1127+ auto e = events.front();
1128+ events.pop();
1129+ EXPECT_FLOAT_EQ(e.x, 5.5);
1130+ EXPECT_FLOAT_EQ(e.y, -8.5);
1131+ EXPECT_FLOAT_EQ(e.z, 9.9);
1132+ EXPECT_EQ(NULL, e.context);
1133+ auto event_time = time_point_system_ns(std::chrono::nanoseconds(e.timestamp));
1134+ auto delay = chrono::duration_cast<chrono::milliseconds>(event_time - start_time).count();
1135+ EXPECT_GE(delay, 1050);
1136+ EXPECT_LE(delay, 1150);
1137+})

Subscribers

People subscribed via source and target branches