tests: update sav/nitserial_args1.res because change in RTA
[nit.git] / lib / android / sensors.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2014 Romain Chanoir <romain.chanoir@viacesi.fr>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # This module is used to manipulate android sensors
18 # The sensor support is implemented in android_app module, so the user can enable the type of sensor he wants to use.
19 # There is an example of how you can use the android sensors in nit/examples/mnit_ballz :
20 #
21 # ~~~~nitish
22 # #FIXME rewrite the example
23 # var app = new MyApp
24 # app.sensors_support_enabled = true
25 # app.accelerometer.enabled = true
26 # app.accelerometer.eventrate = 10000
27 # app.magnetic_field.enabled = true
28 # app.gyroscope.enabled = true
29 # app.light.enabled = true
30 # app.proximity.enabled = true
31 # app.main_loop
32 # ~~~~
33 #
34 # In this example, we enable the sensor support, then enable all types of sensors supported, before running the app.
35 # The result is you get all type of SensorEvent (ASensorAccelerometer, ASensorMagneticField ...) in the input method of your app
36 module sensors
37
38 import android
39 import mnit
40
41 in "C header" `{
42 #include <jni.h>
43 #include <android/sensor.h>
44 `}
45
46 extern class ASensorType `{int`}
47 new accelerometer: ASensorType `{return ASENSOR_TYPE_ACCELEROMETER;`}
48 fun is_accelerometer: Bool `{return recv == ASENSOR_TYPE_ACCELEROMETER;`}
49 new magnetic_field: ASensorType `{return ASENSOR_TYPE_MAGNETIC_FIELD;`}
50 fun is_magnetic_field: Bool `{return recv == ASENSOR_TYPE_MAGNETIC_FIELD;`}
51 new gyroscope:ASensorType `{return ASENSOR_TYPE_GYROSCOPE;`}
52 fun is_gyroscope: Bool `{ return recv == ASENSOR_TYPE_GYROSCOPE;`}
53 new light: ASensorType `{return ASENSOR_TYPE_LIGHT;`}
54 fun is_light: Bool `{return recv == ASENSOR_TYPE_LIGHT;`}
55 new proximity: ASensorType `{return ASENSOR_TYPE_PROXIMITY;`}
56 fun is_proximity:Bool `{return recv == ASENSOR_TYPE_PROXIMITY;`}
57 end
58
59 # Manages the sensors
60 extern class ASensorManager `{ASensorManager*`}
61
62 new get_instance: ASensorManager `{return ASensorManager_getInstance();`}
63
64 # Returns the list of available sensors
65 fun get_sensor_list: Pointer `{
66 ASensorList *list;
67 ASensorManager_getSensorList(recv, list);
68 return list;
69 `}
70
71 # Create a new sensor event queue and associate it with a looper
72 fun create_event_queue(app: NativeAppGlue): ASensorEventQueue `{
73 return ASensorManager_createEventQueue(recv, app->looper, LOOPER_ID_USER, NULL, NULL);
74 `}
75
76 # Returns the default sensor of the given type
77 fun get_default_sensor(sensortype: ASensorType): ASensor `{
78 return ASensorManager_getDefaultSensor(recv, sensortype);
79 `}
80
81 # Destroys the event queue and free all resources associated to it
82 fun destroy_event_queue(queue: ASensorEventQueue) `{
83 ASensorManager_destroyEventQueue(recv, queue);
84 `}
85 end
86
87 # Manages the sensors events
88 extern class ASensorEventQueue `{ASensorEventQueue*`}
89
90 # Enable the selected sensor, returns a negative value on error
91 fun enable_sensor(sensor: ASensor): Int `{
92 return ASensorEventQueue_enableSensor(recv, sensor);
93 `}
94
95 # Disable the selected sensor, returns a negative value on error
96 fun disable_sensor(sensor: ASensor): Int `{
97 return ASensorEventQueue_disableSensor(recv, sensor);
98 `}
99
100 # Set the delivery rate of events in microseconds for the given sensor
101 fun set_event_rate(sensor: ASensor, usec: Int): Int `{
102 return ASensorEventQueue_setEventRate(recv, sensor, usec);
103 `}
104 # Returns 1 if the queue has events, 0 if it does not have events,
105 # and a negative value if there is an error
106 fun has_events: Int `{
107 return ASensorEventQueue_hasEvents(recv);
108 `}
109
110 # Returns the next available events from the queue.
111 # Returns a negative value if no events are available or an error has occured
112 # otherwise the number of events returned
113 fun get_events(events: ASensorEvents, count: Int): Int `{
114 return ASensorEventQueue_getEvents(recv, events, (size_t)count);
115 `}
116 end
117
118 # Extern class referencing a ASensor
119 extern class ASensor `{ASensorRef`}
120
121 new `{return malloc(sizeof(ASensorRef));`}
122 fun name: NativeString `{return (char*)ASensor_getName(recv);`}
123 fun vendor: NativeString `{return (char*)ASensor_getVendor(recv);`}
124 fun sensor_type: ASensorType `{return ASensor_getType(recv);`}
125 fun resolution: Float `{return ASensor_getResolution(recv);`}
126 fun min_delay: Int `{return ASensor_getMinDelay(recv);`}
127 end
128
129 # NIT representation of an Android Sensor used in android_app to initialize sensors
130 class AndroidSensor
131
132 var asensor = new ASensor is writable
133 var enabled = false is writable
134 var event_rate = 100000 is writable
135
136 fun name: String do return asensor.name.to_s
137 fun vendor: String do return asensor.vendor.to_s
138 fun sensor_type: ASensorType do return asensor.sensor_type
139 fun resolution: Float do return asensor.resolution
140 fun min_delay: Int do return asensor.min_delay
141 end
142
143 # Extern class referencing a ASensorEvent
144 extern class ASensorEvent `{ASensorEvent*`}
145 super SensorEvent
146
147 fun version: Int `{return recv->version;`}
148 fun sensor: ASensor `{return (ASensorRef)recv->sensor;`}
149 fun sensor_type: ASensorType `{return recv->type;`}
150 fun timestamp: Int `{return recv->timestamp;`}
151 end
152
153 extern class FullSensor `{ASensorEvent*`}
154 super ASensorLight
155 super ASensorProximity
156
157 fun temperature: Float `{return recv->temperature;`}
158 fun pressure: Float `{return recv->pressure;`}
159 fun data: Pointer `{return recv->data;`}
160 fun vector: ASensorVector `{return &(recv->vector);`}
161 fun acceleration: ASensorVector `{return &(recv->acceleration);`}
162 fun magnetic: ASensorVector `{return &(recv->magnetic);`}
163 end
164
165 # Extern class referencing a ASensorVector, attribute of ASensorRef
166 extern class ASensorVector `{ASensorVector*`}
167
168 fun v: Pointer `{return recv->v;`}
169 fun x: Float `{ return recv->x;`}
170 fun y: Float `{return recv->y;`}
171 fun z: Float `{return recv->z;`}
172 fun azimuth: Float `{return recv->azimuth;`}
173 fun pitch: Float `{return recv->pitch;`}
174 fun roll: Float `{return recv->roll;`}
175 fun status: Int `{return recv->status;`}
176 fun reserved: Pointer `{return recv->reserved;`}
177 end
178
179 # Sensor event returned by the Accelerometer sensor
180 extern class ASensorAccelerometer `{ASensorEvent*`}
181 super ASensorEvent
182
183 fun x: Float `{return recv->acceleration.x;`}
184 fun y: Float `{return recv->acceleration.y;`}
185 fun z: Float `{return recv->acceleration.z;`}
186 end
187
188 # Sensor event returned by the Magnetic Field sensor
189 extern class ASensorMagneticField `{ASensorEvent*`}
190 super ASensorEvent
191
192 fun x: Float `{return recv->magnetic.x;`}
193 fun y: Float `{return recv->magnetic.y;`}
194 fun z: Float `{ return recv->magnetic.z;`}
195 end
196
197 # Sensor event returned by the gyroscope sensor
198 extern class ASensorGyroscope `{ASensorEvent*`}
199 super ASensorEvent
200
201 fun x: Float `{return recv->vector.x;`}
202 fun y: Float `{return recv->vector.y;`}
203 fun z: Float `{return recv->vector.y;`}
204 end
205
206 # Sensor event returned by the Light sensor
207 extern class ASensorLight `{ASensorEvent*`}
208 super ASensorEvent
209
210 fun light: Float `{return recv->light;`}
211 end
212
213 # sensor event returned by the Proximity Sensor
214 extern class ASensorProximity `{ASensorEvent*`}
215 super ASensorEvent
216
217 fun distance: Float `{return recv->distance;`}
218 end
219
220 # Array of SensorEvents
221 extern class ASensorEvents `{ASensorEvent*`}
222
223 new (length: Int) `{return malloc(sizeof(ASensorEvent)*length);`}
224
225 fun [](index: Int): ASensorEvent `{
226 return recv+index;
227 `}
228 end
229
230 redef class App
231 var accelerometer = new AndroidSensor
232 var magnetic_field = new AndroidSensor
233 var gyroscope = new AndroidSensor
234 var light = new AndroidSensor
235 var proximity = new AndroidSensor
236 var sensormanager: ASensorManager
237 var eventqueue: ASensorEventQueue
238 var sensors_support_enabled = false is writable
239
240 private fun extern_input_sensor_accelerometer(event: ASensorAccelerometer) do input(event)
241 private fun extern_input_sensor_magnetic_field(event: ASensorMagneticField) do input(event)
242 private fun extern_input_sensor_gyroscope(event: ASensorGyroscope) do input(event)
243 private fun extern_input_sensor_light(event: ASensorLight) do input(event)
244 private fun extern_input_sensor_proximity(event: ASensorProximity) do input(event)
245
246 # Sensors support
247 # The user decides which sensors he wants to use by setting them enabled
248 private fun enable_sensors
249 do
250 if sensors_support_enabled then enable_sensors_management else return
251 if accelerometer.enabled then enable_accelerometer
252 if magnetic_field.enabled then enable_magnetic_field
253 if gyroscope.enabled then enable_gyroscope
254 if light.enabled then enable_light
255 if proximity.enabled then enable_proximity
256 end
257
258 private fun enable_sensors_management
259 do
260 sensormanager = new ASensorManager.get_instance
261 #eventqueue = sensormanager.create_event_queue(new NdkAndroidApp)
262 eventqueue = initialize_event_queue(sensormanager, native_app_glue.looper)
263 end
264
265 # HACK: need a nit method to get mnit_java_app, then we can use the appropriate sensormanager.create_event_queue method to initialize the event queue
266 private fun initialize_event_queue(sensormanager: ASensorManager, looper: ALooper): ASensorEventQueue `{
267 return ASensorManager_createEventQueue(sensormanager, looper, LOOPER_ID_USER, NULL, NULL);
268 `}
269
270 private fun enable_accelerometer
271 do
272 accelerometer.asensor = sensormanager.get_default_sensor(new ASensorType.accelerometer)
273 if accelerometer.asensor.address_is_null then
274 print "Accelerometer sensor unavailable"
275 else
276 if eventqueue.enable_sensor(accelerometer.asensor) < 0 then print "Accelerometer enabling failed"
277 eventqueue.set_event_rate(accelerometer.asensor, accelerometer.event_rate)
278 end
279 end
280
281 private fun enable_magnetic_field
282 do
283 magnetic_field.asensor = sensormanager.get_default_sensor(new ASensorType.magnetic_field)
284 if magnetic_field.asensor.address_is_null then
285 print "Magnetic Field unavailable"
286 else
287 if eventqueue.enable_sensor(magnetic_field.asensor) < 0 then print "Magnetic Field enabling failed"
288 eventqueue.set_event_rate(magnetic_field.asensor, magnetic_field.event_rate)
289 end
290 end
291
292 private fun enable_gyroscope
293 do
294 gyroscope.asensor = sensormanager.get_default_sensor(new ASensorType.gyroscope)
295 if gyroscope.asensor.address_is_null then
296 print "Gyroscope sensor unavailable"
297 else
298 if eventqueue.enable_sensor(gyroscope.asensor) < 0 then print "Gyroscope enabling failed"
299 eventqueue.set_event_rate(gyroscope.asensor, gyroscope.event_rate)
300 end
301 end
302
303 private fun enable_light
304 do
305 light.asensor = sensormanager.get_default_sensor(new ASensorType.light)
306 if light.asensor.address_is_null then
307 print "Light sensor unavailable"
308 else
309 if eventqueue.enable_sensor(light.asensor) < 0 then print "Light enabling failed"
310 eventqueue.set_event_rate(light.asensor, light.event_rate)
311 end
312 end
313
314 private fun enable_proximity
315 do
316 proximity.asensor = sensormanager.get_default_sensor(new ASensorType.proximity)
317 if proximity.asensor.address_is_null then
318 print "Proximity sensor unavailable"
319 else
320 if eventqueue.enable_sensor(proximity.asensor) < 0 then print "Proximity enabling failed"
321 eventqueue.set_event_rate(light.asensor, light.event_rate)
322 end
323 end
324
325 redef fun run
326 do
327 enable_sensors
328
329 super
330 end
331
332 redef fun handle_looper_event(ident, event, data)
333 do
334 super
335 handle_sensor_events(ident)
336 end
337
338 private fun handle_sensor_events(ident: Int) import extern_input_sensor_accelerometer, extern_input_sensor_magnetic_field, extern_input_sensor_gyroscope, extern_input_sensor_light, extern_input_sensor_proximity, eventqueue `{
339 //If a sensor has data, process it
340 if(ident == LOOPER_ID_USER) {
341 //maybe add a boolean to the app to know if we want to use Sensor API or ASensorEvent directly ...
342 ASensorEvent* events = malloc(sizeof(ASensorEvent)*10);
343 int nbevents;
344 ASensorEventQueue* queue = App_eventqueue(recv);
345 while((nbevents = ASensorEventQueue_getEvents(queue, events, 10)) > 0) {
346 int i;
347 for(i = 0; i < nbevents; i++){
348 ASensorEvent event = events[i];
349 switch (event.type) {
350 case ASENSOR_TYPE_ACCELEROMETER:
351 App_extern_input_sensor_accelerometer(recv, &event);
352 break;
353 case ASENSOR_TYPE_MAGNETIC_FIELD:
354 App_extern_input_sensor_magnetic_field(recv, &event);
355 break;
356 case ASENSOR_TYPE_GYROSCOPE:
357 App_extern_input_sensor_gyroscope(recv, &event);
358 break;
359 case ASENSOR_TYPE_LIGHT:
360 App_extern_input_sensor_light(recv, &event);
361 break;
362 case ASENSOR_TYPE_PROXIMITY:
363 App_extern_input_sensor_proximity(recv, &event);
364 break;
365 }
366 }
367 }
368 }
369 `}
370 end