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