Merge lp:~pitti/platform-api/test-backend into lp:platform-api
- test-backend
- Merge into trunk
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 |
Related bugs: |
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://
You can now run an app with the simulated sensor backend
(UBUNTU_
a simulation data file (UBUNTU_
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:/
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.
Martin Pitt (pitti) wrote : | # |
Martin Pitt (pitti) wrote : | # |
Note to self: Need to package/ship new backend and README.
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_
For stylistic karma: The functions handling time could be switched over to use std::chrono (see http://
Martin Pitt (pitti) wrote : | # |
Did the changes Thomas suggested in his review, thanks!
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-
- 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).
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:202
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 203. By Martin Pitt
-
Declare functions which return float as "aapcs" calling convention on ARM, like the hybris library
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:203
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 204. By Martin Pitt
-
avoid integer overflow in itimerspec calculation, and fix precision warnings
Thomas Voß (thomas-voss) wrote : | # |
LGTM, again: Thanks for getting this started.
Martin Pitt (pitti) wrote : | # |
Ricardo, can you please do another review, and top-approve if you are happy with it? Thanks!
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:204
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Martin Pitt (pitti) wrote : | # |
Notes from IRC from Rick: It should stop building a *.so symlink for the test backend, and libubuntu-
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.
- 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.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:206
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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.
- 207. By Martin Pitt
-
rename libubuntu-
application- test-api1 to libubuntu- application- api-test1
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:207
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ricardo Mendoza (ricmm) wrote : | # |
Looks good, tested across devices. All comments addressed.
Landing.
Preview Diff
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 | +}) |
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.