Merge: nitiwiki: external highlighter
[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 # redef class App
24 # sensors_support_enabled = true
25 # accelerometer.enabled = true
26 # accelerometer.eventrate = 10000
27 # magnetic_field.enabled = true
28 # gyroscope.enabled = true
29 # light.enabled = true
30 # proximity.enabled = true
31 # end
32 # ~~~~
33 #
34 # In this example, we enable the sensor support, then enable all types of sensors supported by the API, directly with `App` attributes
35 # As a result, you get all type of SensorEvent (ASensorAccelerometer, ASensorMagneticField ...) in the `input` callback of `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 self == ASENSOR_TYPE_ACCELEROMETER;`}
49 new magnetic_field: ASensorType `{return ASENSOR_TYPE_MAGNETIC_FIELD;`}
50 fun is_magnetic_field: Bool `{return self == ASENSOR_TYPE_MAGNETIC_FIELD;`}
51 new gyroscope:ASensorType `{return ASENSOR_TYPE_GYROSCOPE;`}
52 fun is_gyroscope: Bool `{ return self == ASENSOR_TYPE_GYROSCOPE;`}
53 new light: ASensorType `{return ASENSOR_TYPE_LIGHT;`}
54 fun is_light: Bool `{return self == ASENSOR_TYPE_LIGHT;`}
55 new proximity: ASensorType `{return ASENSOR_TYPE_PROXIMITY;`}
56 fun is_proximity:Bool `{return self == 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(self, 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(self, 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(self, 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(self, 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(self, 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(self, 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(self, 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(self);
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(self, 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(self);`}
123 fun vendor: NativeString `{return (char*)ASensor_getVendor(self);`}
124 fun sensor_type: ASensorType `{return ASensor_getType(self);`}
125 fun resolution: Float `{return ASensor_getResolution(self);`}
126 fun min_delay: Int `{return ASensor_getMinDelay(self);`}
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 self->version;`}
148 fun sensor: ASensor `{return (ASensorRef)self->sensor;`}
149 fun sensor_type: ASensorType `{return self->type;`}
150 fun timestamp: Int `{return self->timestamp;`}
151 end
152
153 extern class FullSensor `{ASensorEvent*`}
154 super ASensorLight
155 super ASensorProximity
156
157 fun temperature: Float `{return self->temperature;`}
158 fun pressure: Float `{return self->pressure;`}
159 fun data: Pointer `{return self->data;`}
160 fun vector: ASensorVector `{return &(self->vector);`}
161 fun acceleration: ASensorVector `{return &(self->acceleration);`}
162 fun magnetic: ASensorVector `{return &(self->magnetic);`}
163 end
164
165 # Extern class referencing a ASensorVector, attribute of ASensorRef
166 extern class ASensorVector `{ASensorVector*`}
167
168 fun v: Pointer `{return self->v;`}
169 fun x: Float `{ return self->x;`}
170 fun y: Float `{return self->y;`}
171 fun z: Float `{return self->z;`}
172 fun azimuth: Float `{return self->azimuth;`}
173 fun pitch: Float `{return self->pitch;`}
174 fun roll: Float `{return self->roll;`}
175 fun status: Int `{return self->status;`}
176 fun reserved: Pointer `{return self->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 self->acceleration.x;`}
184 fun y: Float `{return self->acceleration.y;`}
185 fun z: Float `{return self->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 self->magnetic.x;`}
193 fun y: Float `{return self->magnetic.y;`}
194 fun z: Float `{ return self->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 self->vector.x;`}
202 fun y: Float `{return self->vector.y;`}
203 fun z: Float `{return self->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 self->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 self->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 self+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(self);
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(self, &event);
352 break;
353 case ASENSOR_TYPE_MAGNETIC_FIELD:
354 App_extern_input_sensor_magnetic_field(self, &event);
355 break;
356 case ASENSOR_TYPE_GYROSCOPE:
357 App_extern_input_sensor_gyroscope(self, &event);
358 break;
359 case ASENSOR_TYPE_LIGHT:
360 App_extern_input_sensor_light(self, &event);
361 break;
362 case ASENSOR_TYPE_PROXIMITY:
363 App_extern_input_sensor_proximity(self, &event);
364 break;
365 }
366 }
367 }
368 }
369 `}
370 end