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