update Sensor presence detection mecanism to the bug20 kernel API
[bug:com_buglabs_bug_jni_sensor.git] / src / c / Sensor.cpp
1 /*******************************************************************************
2  * Copyright (c) 2008, 2009 Bug Labs, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *    - Redistributions of source code must retain the above copyright notice,
8  *      this list of conditions and the following disclaimer.
9  *    - Redistributions in binary form must reproduce the above copyright
10  *      notice, this list of conditions and the following disclaimer in the
11  *      documentation and/or other materials provided with the distribution.
12  *    - Neither the name of Bug Labs, Inc. nor the names of its contributors may be
13  *      used to endorse or promote products derived from this software without
14  *      specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *******************************************************************************/
28
29 // TODO: replace perror_msg calls with IOExceptions (see BUGbee jni for how to do that)
30
31 #include "jni/com_buglabs_bug_jni_sensor_Sensor.h"
32
33 extern "C" {
34 #include <linux/bmi/bmi_sensor.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <sys/ioctl.h>
38 #include <unistd.h>
39 }
40 #include "CharDevice.h"
41
42 //
43 // Helpers
44 //
45
46 static void perror_msg_and_die(char *s) {
47         printf("sensor: %s\n", s);
48         exit(-1);
49 }
50
51 // print error message
52 static void perror_msg(char *s) {
53         printf("sensor: %s\n", s);
54 }
55
56 static jfieldID getFieldID(JNIEnv *env,
57                 jobject jobj,
58                 const char *name,
59                 const char *type) {
60         return env->GetFieldID(env->GetObjectClass(jobj), name, type);
61 }
62
63 static void setBooleanField(JNIEnv * env, jobject jobj, const char *name, bool b)
64 {
65         env->SetBooleanField(jobj, getFieldID(env, jobj, name, "Z"), b);
66 }
67 static void setIntegerField(JNIEnv * env, jobject jobj, const char *name, int b)
68 {
69         env->SetIntField(jobj, getFieldID(env, jobj, name, "I"), b);
70 }
71
72 //
73 // Presence Detection
74 //
75
76 static void updatePresence(JNIEnv * env, jobject jobj, const char *field, unsigned char presence) {
77         printf("Detected %s as %spresent\n", field, ( presence == 0x1 ) ? "" : "not ");
78         setBooleanField(env, jobj, field, ( presence  == 0x1 ) );
79 }
80
81 JNIEXPORT void JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_setPresentFlags
82   (JNIEnv * env, jobject jobj) {
83         struct sensor_presence sensor;
84         const int ret = ioctl( getFileDescriptorField(env, jobj), BMI_SENSOR_PRESENCE, &sensor);
85         if (ret < 0)
86         {
87                 printf("sensors elements detection ioctl BMI_SENSOR_PRESENCE failed for %s: error %d\n",
88                        getFileDescriptorField(env, jobj), ret);
89         }
90         else
91         {
92                 updatePresence(env, jobj, "adcPresent", sensor.adc);
93                 updatePresence(env, jobj, "accelPresent", sensor.acc);
94                 updatePresence(env, jobj, "plPresent", sensor.pl );
95                 updatePresence(env, jobj, "dlightPresent", sensor.dl );
96                 updatePresence(env, jobj, "tempPresent", sensor.temp );
97                 updatePresence(env, jobj, "motionPresent", sensor.motion );
98                 updatePresence(env, jobj, "dcompPresent", sensor.dcomp );
99                 updatePresence(env, jobj, "acompPresent", sensor.acomp );
100                 updatePresence(env, jobj, "alightPresent", sensor.alight );
101                 updatePresence(env, jobj, "aproxPresent", sensor.aprox );
102                 updatePresence(env, jobj, "humidityPresent", sensor.humidity );
103                 updatePresence(env, jobj, "soundPresent", sensor.sound );
104                 //updatePresence(env, jobj, "acc302Present",  );
105         }
106 }
107
108 //
109 // LEDs
110 //
111
112 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_redLEDOff
113 (JNIEnv * env, jobject jobj) {
114         return ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_RLEDOFF, 0);
115 }
116
117 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_redLEDOn
118 (JNIEnv * env, jobject jobj) {
119         return ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_RLEDON, 0);
120
121 }
122
123 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_greenLEDOff
124 (JNIEnv * env, jobject jobj) {
125         return ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_GLEDOFF, 0);
126 }
127
128 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_greenLEDOn
129 (JNIEnv * env, jobject jobj) {
130         return ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_GLEDON, 0);
131 }
132
133 //
134 // Temperature
135 //
136
137 // TODO: should this be in Java-land instead?
138 static int convertTemperatureReadingToC(unsigned int sensor_data) {
139         return (128 * ((sensor_data & 0x8000) >> 15))
140                 + (64 * ((sensor_data & 0x4000) >> 14))
141                 + (32 * ((sensor_data & 0x2000) >> 13))
142                 + (16 * ((sensor_data & 0x1000) >> 12))
143                 + (8 * ((sensor_data & 0x0800) >> 11))
144                 + (4 * ((sensor_data & 0x0400) >> 10))
145                 + (2 * ((sensor_data & 0x0200) >> 9))
146                 + (1 * ((sensor_data & 0x0100) >> 8));
147 }
148
149 // TODO: is whole number temperature in Celsius sufficient accuracy?
150 // TODO: do we need the unsigned remote reading (allows higher reading)
151 JNIEXPORT void JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_requestTemperature
152   (JNIEnv *env, jobject jobj) {
153         struct sensor_temp_rw temp;
154
155         // Ensure temperature sensor is STOPped
156         temp.address = SENSOR_TEMP_CONF1_WR;
157         temp.d1 = SENSOR_TEMP_CONF1_STOP;
158         if (ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_TEMPWR, &temp) < 0)
159                 perror_msg("cannot write Temperature sensor (CONF1)");
160
161         // Request a one-shot temperature reading
162         temp.address = SENSOR_TEMP_ONE_SHOT;
163         temp.d1 = 0x0;
164         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_TEMPWR, &temp) < 0)
165                 perror_msg("cannot write Temperature sensor (ONE_SHOT)");
166
167         unsigned int sensor_data = 0;
168         // Temperature Read signed local - see data sheet
169         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_TEMPRD_SL, &sensor_data) < 0)
170                 perror_msg("cannot read Temperature sensor (SL)");
171         setIntegerField(env, jobj, "lastLocalTemperature", convertTemperatureReadingToC(sensor_data));
172
173         // Temperature Read signed remote - see data sheet
174         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_TEMPRD_SR, &sensor_data) < 0)
175                 perror_msg("cannot read Temperature sensor (SR)");
176         setIntegerField(env, jobj, "lastRemoteTemperature", convertTemperatureReadingToC(sensor_data));
177
178 #if 0
179         // Temperature Read unsigned remote - see data sheet
180         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_TEMPRD_UR, &sensor_data) < 0)
181                 perror_msg("cannot read Temperature sensor (UR)");
182 #endif
183 }
184
185 //
186 // Humidity
187 //
188
189 JNIEXPORT void JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_turnHumiditySensorOn
190   (JNIEnv *env, jobject jobj)
191 {
192         // enable the sensor itself
193         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_HUM_PWR_EN, BMI_SENSOR_ON) < 0)
194                 perror_msg("cannot enable Humidity sensor power");
195 }
196
197 JNIEXPORT void JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_turnHumiditySensorOff
198   (JNIEnv *env, jobject jobj)
199 {
200         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_HUM_PWR_EN, BMI_SENSOR_OFF) < 0)
201                 perror_msg("cannot disable Humidity sensor power");
202 }
203
204 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_getHumidity
205   (JNIEnv *env, jobject jobj)
206 {
207         // TODO: figure out what sleep calls are required
208         sleep(1);
209         // trigger the ADC to read from the humidity sensor's channel
210         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_ADCWR, SENSOR_ADC_HUMIDITY | SENSOR_ADC_PD_OFF) < 0)
211                 perror_msg("cannot write ADC (Humidity)");
212         sleep(1);
213
214         // get back the reading just taken
215         unsigned int sensor_data;
216         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_ADCRD, &sensor_data) < 0)
217                 perror_msg("cannot read ADC (Humidity)");
218
219         return ((((sensor_data * 10000)/ 4096) - 1600) / 62);
220 }
221
222 //
223 // Analog Compass
224 //
225
226 JNIEXPORT void JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_resetCompass
227   (JNIEnv *env, jobject jobj)
228 {
229         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_ACOMPRST) < 0)
230                 perror_msg("cannot reset analog compass");
231 }
232
233 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_getCompassHx
234   (JNIEnv *env, jobject jobj)
235 {
236         unsigned int sensor_data;
237         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_ACOMPXRD, &sensor_data) < 0)
238                 perror_msg("cannot read analog compass X");
239         return sensor_data;
240 }
241
242 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_getCompassHy
243   (JNIEnv *env, jobject jobj)
244 {
245         unsigned int sensor_data;
246         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_ACOMPYRD, &sensor_data) < 0)
247                 perror_msg("cannot read analog compass Y");
248         return sensor_data;
249 }
250
251 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_getCompassHz
252   (JNIEnv *env, jobject jobj)
253 {
254         unsigned int sensor_data;
255         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_ACOMPZRD, &sensor_data) < 0)
256                 perror_msg("cannot read analog compass Z");
257         return sensor_data;
258 }
259
260 //
261 // Digital Light
262 //
263
264 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_lightWrite
265   (JNIEnv *env, jobject jobj,
266                   jboolean interruptWait,
267                   jbyte adcCoreEnable,
268                   jbyte adcPowerDown,
269                   jbyte mode,
270                   jbyte resolution,
271                   jbyte gain,
272                   jbyte intThHi,
273                   jbyte intThLo,
274                   jbyte intPersist)
275 {
276                 perror_msg("cannot write to digital light sensor");
277                 return -1;
278 }
279
280 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_lightReadRaw
281 (JNIEnv *env, jobject jobj)
282 {
283         unsigned int sensor_data;
284         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_ALIGHTRD, &sensor_data) < 0)
285                 perror_msg("cannot read analog light sensor");
286         return sensor_data;
287 }
288
289 JNIEXPORT void JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_lightInterruptClear
290 (JNIEnv *env, jobject jobj)
291 {
292         perror_msg("cannot clear interrupt for digital light sensor");
293 }
294
295 //
296 // Analog Proximity
297 //
298
299 JNIEXPORT void JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_setProximityBurstDuration
300   (JNIEnv *env, jobject jobj, jint durationMs)
301 {
302         const unsigned long param = durationMs;
303         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_APROXRD, &param) < 0)
304                 perror_msg("cannot read analog proximity sensor");
305 }
306
307 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_proximityRead
308   (JNIEnv *env, jobject jobj)
309 {
310         unsigned int sensor_data;
311         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_APROXRD, &sensor_data) < 0)
312                 perror_msg("cannot read analog proximity sensor");
313         return sensor_data & 0xffff;
314 }
315
316 //
317 // Suspend / Resume
318 //
319
320 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_suspend
321 (JNIEnv *env, jobject jobj)
322 {
323         return ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_SUSPEND, 0);
324 }
325
326
327 JNIEXPORT jint JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_resume
328 (JNIEnv *env, jobject jobj)
329 {
330         return ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_RESUME, 0);
331 }
332
333 //
334 // ADXL345 Accelerometer
335 //
336
337 JNIEXPORT void JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_accelRriteRegister
338   (JNIEnv *env, jobject jobj, jbyte jaddress, jbyte jvalue)
339 {
340         struct sensor_acc_rw acc;
341         acc.address = jaddress;
342         acc.count = 1;
343         acc.data[0] = jvalue;
344         acc.data[1] = 0;
345
346         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_ACCWR, &acc) < 0)
347                 perror_msg("cannot write accelerometer register");
348 }
349
350 JNIEXPORT jbyte JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_accelReadRegister
351   (JNIEnv *env, jobject jobj, jbyte jaddress)
352 {
353         struct sensor_acc_rw acc;
354         acc.address = jaddress;
355         acc.count = 1;
356         acc.data[0] = 0;
357         acc.data[1] = 0;
358
359         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_ACCRD, &acc) < 0)
360                 perror_msg("cannot read accelerometer register");
361
362         return acc.data[0];
363 }
364
365 JNIEXPORT jshort JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_accelReadX
366   (JNIEnv *env, jobject jobj)
367 {
368         unsigned int sensor_data;
369         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_ACCXRD, &sensor_data) < 0)
370                 perror_msg("cannot read accelerometer X");
371         // data is returned in an unsigned int, but the value is 16-bit two's complement
372         return (short) sensor_data;
373 }
374
375 JNIEXPORT jshort JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_accelReadY
376   (JNIEnv *env, jobject jobj)
377 {
378         unsigned int sensor_data;
379         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_ACCYRD, &sensor_data) < 0)
380                 perror_msg("cannot read accelerometer Y");
381         return (short) sensor_data;
382 }
383
384 JNIEXPORT jshort JNICALL Java_com_buglabs_bug_jni_sensor_Sensor_accelReadZ
385   (JNIEnv *env, jobject jobj)
386 {
387         unsigned int sensor_data;
388         if(ioctl(getFileDescriptorField(env, jobj), BMI_SENSOR_ACCZRD, &sensor_data) < 0)
389                 perror_msg("cannot read accelerometer Z");
390         return (short) sensor_data;
391 }