• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdlib.h>
18 #include <string.h>
19 #include <timer.h>
20 #include <heap.h>
21 #include <plat/inc/rtc.h>
22 #include <plat/inc/syscfg.h>
23 #include <hostIntf.h>
24 #include <nanohubPacket.h>
25 #include <floatRt.h>
26 
27 #include <seos.h>
28 
29 #include <nanohub_math.h>
30 #include <algos/fusion.h>
31 #include <sensors.h>
32 #include <variant/inc/sensType.h>
33 #include <limits.h>
34 #include <slab.h>
35 
36 #define ORIENTATION_APP_VERSION 1
37 
38 #define MAX_NUM_COMMS_EVENT_SAMPLES 15 // at most 15 samples can fit in one comms_event
39 #define NUM_COMMS_EVENTS_IN_FIFO    2  // This controls how often the hub needs to wake up
40                                        // in batching
41 
42 // needs to be greater than max raw sensor rate ratio
43 #define FIFO_DEPTH                  (NUM_COMMS_EVENTS_IN_FIFO * MAX_NUM_COMMS_EVENT_SAMPLES)
44 
45 /*
46  * FIFO_MARGIN: max raw sensor rate ratio is 8:1.
47  * If 2 batchs of high rate data comes before 1 low rate data, there can be at max 15 samples left
48  * in the FIFO
49  */
50 #define FIFO_MARGIN                 15
51 #define MAX_NUM_SAMPLES             (FIFO_MARGIN + FIFO_DEPTH) // actual input sample fifo depth
52 #define EVT_SENSOR_ACC_DATA_RDY     sensorGetMyEventType(SENS_TYPE_ACCEL)
53 #define EVT_SENSOR_GYR_DATA_RDY     sensorGetMyEventType(SENS_TYPE_GYRO)
54 #define EVT_SENSOR_MAG_DATA_RDY     sensorGetMyEventType(SENS_TYPE_MAG)
55 #define EVT_SENSOR_MAG_BIAS         sensorGetMyEventType(SENS_TYPE_MAG_BIAS)
56 
57 #define kGravityEarth               9.80665f
58 #define kRad2deg                    (180.0f / M_PI)
59 #define MIN_GYRO_RATE_HZ            SENSOR_HZ(100.0f)
60 #define MAX_MAG_RATE_HZ             SENSOR_HZ(50.0f)
61 
62 enum
63 {
64     FUSION_FLAG_ENABLED             = 0x01,
65     FUSION_FLAG_INITIALIZED         = 0x08,
66     FUSION_FLAG_GAME_ENABLED        = 0x10,
67     FUSION_FLAG_GAME_INITIALIZED    = 0x20
68 };
69 
70 enum RawSensorType
71 {
72     ACC,
73     GYR,
74     MAG,
75     NUM_OF_RAW_SENSOR
76 };
77 
78 enum FusionSensorType
79 {
80     ORIENT,
81     GRAVITY,
82     GEOMAG,
83     LINEAR,
84     GAME,
85     ROTAT,
86     NUM_OF_FUSION_SENSOR
87 };
88 
89 
90 struct FusionSensorSample {
91     uint64_t time;
92     float x, y, z;
93 };
94 
95 struct FusionSensor {
96     uint32_t handle;
97     struct TripleAxisDataEvent *ev;
98     uint64_t prev_time;
99     uint64_t latency;
100     uint32_t rate;
101     bool active;
102     bool use_gyro_data;
103     bool use_mag_data;
104     uint8_t idx;
105 };
106 
107 struct FusionTask {
108     uint32_t tid;
109     uint32_t accelHandle;
110     uint32_t gyroHandle;
111     uint32_t magHandle;
112 
113     struct Fusion fusion;
114     struct Fusion game;
115 
116     struct FusionSensor sensors[NUM_OF_FUSION_SENSOR];
117     struct FusionSensorSample samples[NUM_OF_RAW_SENSOR][MAX_NUM_SAMPLES];
118     size_t sample_indices[NUM_OF_RAW_SENSOR];
119     size_t sample_counts[NUM_OF_RAW_SENSOR];
120     uint32_t counters[NUM_OF_RAW_SENSOR];
121     uint64_t ResamplePeriodNs[NUM_OF_RAW_SENSOR];
122     uint64_t last_time[NUM_OF_RAW_SENSOR];
123     struct TripleAxisDataPoint last_sample[NUM_OF_RAW_SENSOR];
124 
125     uint32_t flags;
126 
127     uint32_t raw_sensor_rate[NUM_OF_RAW_SENSOR];
128     uint64_t raw_sensor_latency;
129 
130     uint8_t accel_client_cnt;
131     uint8_t gyro_client_cnt;
132     uint8_t mag_client_cnt;
133 };
134 
135 static uint32_t FusionRates[] = {
136     SENSOR_HZ(12.5f),
137     SENSOR_HZ(25.0f),
138     SENSOR_HZ(50.0f),
139     SENSOR_HZ(100.0f),
140     SENSOR_HZ(200.0f),
141     0,
142 };
143 
144 //should match "supported rates in length" and be the timer length for that rate in nanosecs
145 static const uint64_t rateTimerVals[] = {
146     1000000000ULL / 12.5f,
147     1000000000ULL / 25,
148     1000000000ULL / 50,
149     1000000000ULL / 100,
150     1000000000ULL / 200,
151 };
152 
153 static struct FusionTask mTask;
154 
155 #define DEC_INFO_RATE(name, rates, type, axis, inter, samples) \
156     .sensorName = name, \
157     .supportedRates = rates, \
158     .sensorType = type, \
159     .numAxis = axis, \
160     .interrupt = inter, \
161     .minSamples = samples
162 
163 static const struct SensorInfo mSi[NUM_OF_FUSION_SENSOR] =
164 {
165     { DEC_INFO_RATE("Orientation", FusionRates, SENS_TYPE_ORIENTATION, NUM_AXIS_THREE,
166             NANOHUB_INT_NONWAKEUP, 20) },
167     { DEC_INFO_RATE("Gravity", FusionRates, SENS_TYPE_GRAVITY, NUM_AXIS_THREE,
168             NANOHUB_INT_NONWAKEUP, 20) },
169     { DEC_INFO_RATE("Geomagnetic Rotation Vector", FusionRates, SENS_TYPE_GEO_MAG_ROT_VEC,
170             NUM_AXIS_THREE, NANOHUB_INT_NONWAKEUP, 20) },
171     { DEC_INFO_RATE("Linear Acceleration", FusionRates, SENS_TYPE_LINEAR_ACCEL, NUM_AXIS_THREE,
172             NANOHUB_INT_NONWAKEUP, 20) },
173     { DEC_INFO_RATE("Game Rotation Vector", FusionRates, SENS_TYPE_GAME_ROT_VECTOR, NUM_AXIS_THREE,
174             NANOHUB_INT_NONWAKEUP, 300) },
175     { DEC_INFO_RATE("Rotation Vector", FusionRates, SENS_TYPE_ROTATION_VECTOR, NUM_AXIS_THREE,
176             NANOHUB_INT_NONWAKEUP, 20) },
177 };
178 
179 static struct SlabAllocator *mDataSlab;
180 
dataEvtFree(void * ptr)181 static void dataEvtFree(void *ptr)
182 {
183     slabAllocatorFree(mDataSlab, ptr);
184 }
185 
fillSamples(struct TripleAxisDataEvent * ev,enum RawSensorType index)186 static void fillSamples(struct TripleAxisDataEvent *ev, enum RawSensorType index)
187 {
188     bool bad_timestamp;
189     size_t i, w, n, num_samples;
190     struct TripleAxisDataPoint *curr_sample, *next_sample;
191     uint32_t counter;
192     uint64_t ResamplePeriodNs, curr_time, next_time;
193     uint64_t sample_spacing_ns;
194     float weight_next;
195 
196     if (index == GYR && mTask.gyro_client_cnt == 0) {
197         return;
198     }
199     if (index == MAG && mTask.mag_client_cnt == 0) {
200         return;
201     }
202 
203     n = mTask.sample_counts[index];
204     i = mTask.sample_indices[index];
205     counter = mTask.counters[index];
206     ResamplePeriodNs = mTask.ResamplePeriodNs[index];
207     w = (mTask.sample_indices[index] + n) % MAX_NUM_SAMPLES;
208 
209     // check if this sensor was used before
210     if (mTask.last_time[index] == ULONG_LONG_MAX) {
211         curr_sample = ev->samples;
212         next_sample = curr_sample + 1;
213         num_samples = ev->samples[0].firstSample.numSamples;
214         curr_time = ev->referenceTime;
215     } else {
216         curr_sample = &mTask.last_sample[index];
217         next_sample = ev->samples;
218         num_samples = ev->samples[0].firstSample.numSamples + 1;
219         curr_time = mTask.last_time[index];
220     }
221 
222     while (num_samples > 1) {
223 
224         if (next_sample == ev->samples)
225             next_time = ev->referenceTime;
226         else
227             next_time = curr_time + next_sample->deltaTime;
228 
229         // error handling for non-chronological accel timestamps
230         sample_spacing_ns = (next_time > curr_time) ?  (next_time - curr_time) : 0;
231 
232         // This can happen during sensor config changes
233         bad_timestamp = (sample_spacing_ns > 10 * ResamplePeriodNs);
234 
235         // Check to see if we need to move the interpolation window or
236         // interpolate
237         if ((counter >= sample_spacing_ns) || bad_timestamp) {
238             num_samples--;
239             counter -= (bad_timestamp ? counter : sample_spacing_ns);
240             curr_sample = next_sample;
241             next_sample++;
242 
243             curr_time = next_time;
244         } else {
245             weight_next = (float)counter / floatFromUint64(sample_spacing_ns);
246 
247             mTask.samples[index][w].x = curr_sample->x + weight_next *
248                 (next_sample->x - curr_sample->x);
249             mTask.samples[index][w].y = curr_sample->y + weight_next *
250                 (next_sample->y - curr_sample->y);
251             mTask.samples[index][w].z = curr_sample->z + weight_next *
252                 (next_sample->z - curr_sample->z);
253             mTask.samples[index][w].time = curr_time + counter;
254 
255             // Move the read index when buffer is full
256             if (++n > MAX_NUM_SAMPLES) {
257                 n = MAX_NUM_SAMPLES;
258 
259                 if (++i == MAX_NUM_SAMPLES) {
260                     i = 0;
261                 }
262             }
263 
264             // Reset the write index
265             if (++w == MAX_NUM_SAMPLES) {
266                 w = 0;
267             }
268 
269             // Move to the next resample
270             counter += ResamplePeriodNs;
271         }
272     }
273 
274     mTask.sample_counts[index] = n;
275     mTask.sample_indices[index] = i;
276     mTask.counters[index] = counter;
277     mTask.last_sample[index] = *curr_sample;
278     mTask.last_time[index] = curr_time;
279 }
280 
allocateDataEvt(struct FusionSensor * mSensor,uint64_t time)281 static bool allocateDataEvt(struct FusionSensor *mSensor, uint64_t time)
282 {
283     mSensor->ev = slabAllocatorAlloc(mDataSlab);
284     if (mSensor->ev == NULL) {
285         // slab allocation failed
286         osLog(LOG_ERROR, "ORIENTATION: slabAllocatorAlloc() Failed\n");
287         return false;
288     }
289 
290     // delta time for the first sample is sample count
291     memset(&mSensor->ev->samples[0].firstSample, 0x00, sizeof(struct SensorFirstSample));
292     mSensor->ev->referenceTime = time;
293     mSensor->prev_time = time;
294 
295     return true;
296 }
297 
addSample(struct FusionSensor * mSensor,uint64_t time,float x,float y,float z)298 static void addSample(struct FusionSensor *mSensor, uint64_t time, float x, float y, float z)
299 {
300     struct TripleAxisDataPoint *sample;
301 
302     if (mSensor->ev == NULL) {
303         if (!allocateDataEvt(mSensor, time))
304             return;
305     }
306 
307     if (mSensor->ev->samples[0].firstSample.numSamples >= MAX_NUM_COMMS_EVENT_SAMPLES) {
308         osLog(LOG_ERROR, "ORIENTATION: BAD_INDEX\n");
309         return;
310     }
311 
312     sample = &mSensor->ev->samples[mSensor->ev->samples[0].firstSample.numSamples++];
313 
314     if (mSensor->ev->samples[0].firstSample.numSamples > 1) {
315         sample->deltaTime = time > mSensor->prev_time ? (time - mSensor->prev_time) : 0;
316         mSensor->prev_time = time;
317     }
318 
319     sample->x = x;
320     sample->y = y;
321     sample->z = z;
322 
323     if (mSensor->ev->samples[0].firstSample.numSamples == MAX_NUM_COMMS_EVENT_SAMPLES) {
324         osEnqueueEvtOrFree(
325                 EVENT_TYPE_BIT_DISCARDABLE | sensorGetMyEventType(mSi[mSensor->idx].sensorType),
326                 mSensor->ev, dataEvtFree);
327         mSensor->ev = NULL;
328     }
329 }
330 
updateOutput(ssize_t last_accel_sample_index,uint64_t last_sensor_time)331 static void updateOutput(ssize_t last_accel_sample_index, uint64_t last_sensor_time)
332 {
333     struct Vec4 attitude;
334     struct Vec3 g, a;
335     struct Mat33 R;  // direction-cosine/rotation matrix, inertial -> device
336     bool   rInited;  // indicates if matrix R has been initialzed. for avoiding repeated computation
337 
338     if (fusionHasEstimate(&mTask.game)) {
339         rInited = false;
340         if (mTask.sensors[GAME].active) {
341             fusionGetAttitude(&mTask.game, &attitude);
342             addSample(&mTask.sensors[GAME],
343                     last_sensor_time,
344                     attitude.x,
345                     attitude.y,
346                     attitude.z);
347         }
348 
349         if (mTask.sensors[GRAVITY].active) {
350             fusionGetRotationMatrix(&mTask.game, &R);
351             rInited = true;
352             initVec3(&g, R.elem[0][2], R.elem[1][2], R.elem[2][2]);
353             vec3ScalarMul(&g, kGravityEarth);
354             addSample(&mTask.sensors[GRAVITY],
355                     last_sensor_time,
356                     g.x, g.y, g.z);
357         }
358 
359         if (last_accel_sample_index >= 0
360                 && mTask.sensors[LINEAR].active) {
361             if (!rInited) {
362                 fusionGetRotationMatrix(&mTask.game, &R);
363             }
364             initVec3(&g, R.elem[0][2], R.elem[1][2], R.elem[2][2]);
365             vec3ScalarMul(&g, kGravityEarth);
366             initVec3(&a,
367                     mTask.samples[0][last_accel_sample_index].x,
368                     mTask.samples[0][last_accel_sample_index].y,
369                     mTask.samples[0][last_accel_sample_index].z);
370 
371             addSample(&mTask.sensors[LINEAR],
372                     mTask.samples[0][last_accel_sample_index].time,
373                     a.x - g.x,
374                     a.y - g.y,
375                     a.z - g.z);
376         }
377     }
378 
379     if (fusionHasEstimate(&mTask.fusion)) {
380         fusionGetAttitude(&mTask.fusion, &attitude);
381 
382         if (mTask.sensors[ORIENT].active) {
383             fusionGetRotationMatrix(&mTask.fusion, &R);
384             // x, y, z = yaw, pitch, roll
385             float x = atan2f(-R.elem[0][1], R.elem[0][0]) * kRad2deg;
386             float y = atan2f(-R.elem[1][2], R.elem[2][2]) * kRad2deg;
387             float z = asinf(R.elem[0][2]) * kRad2deg;
388 
389             if (x < 0.0f) {
390                 x += 360.0f;
391             }
392 
393             addSample(&mTask.sensors[ORIENT],
394                     last_sensor_time, x, y, z);
395         }
396 
397         if (mTask.sensors[GEOMAG].active) {
398             addSample(&mTask.sensors[GEOMAG],
399                     last_sensor_time,
400                     attitude.x,
401                     attitude.y,
402                     attitude.z);
403         }
404 
405         if (mTask.sensors[ROTAT].active) {
406             addSample(&mTask.sensors[ROTAT],
407                     last_sensor_time,
408                     attitude.x,
409                     attitude.y,
410                     attitude.z);
411         }
412 
413     }
414 }
415 
drainSamples()416 static void drainSamples()
417 {
418     size_t i = mTask.sample_indices[ACC];
419     size_t j = 0;
420     size_t k = 0;
421     size_t which;
422     struct Vec3 a, w, m;
423     float dT;
424     uint64_t a_time, g_time, m_time;
425 
426     if (mTask.gyro_client_cnt > 0)
427         j = mTask.sample_indices[GYR];
428 
429     if (mTask.mag_client_cnt > 0)
430         k = mTask.sample_indices[MAG];
431 
432     while (mTask.sample_counts[ACC] > 0
433             && (!(mTask.gyro_client_cnt > 0) || mTask.sample_counts[GYR] > 0)
434             && (!(mTask.mag_client_cnt > 0) || mTask.sample_counts[MAG] > 0)) {
435         a_time = mTask.samples[ACC][i].time;
436         g_time = mTask.gyro_client_cnt > 0 ? mTask.samples[GYR][j].time
437                             : ULONG_LONG_MAX;
438         m_time = mTask.mag_client_cnt > 0 ? mTask.samples[MAG][k].time
439                             : ULONG_LONG_MAX;
440 
441         // priority with same timestamp: gyro > acc > mag
442         if (g_time <= a_time && g_time <= m_time) {
443             which = GYR;
444         } else if (a_time <= m_time) {
445             which = ACC;
446         } else {
447             which = MAG;
448         }
449 
450         dT = floatFromUint64(mTask.ResamplePeriodNs[which]) * 1e-9f;
451         switch (which) {
452         case ACC:
453             initVec3(&a, mTask.samples[ACC][i].x, mTask.samples[ACC][i].y, mTask.samples[ACC][i].z);
454 
455             if (mTask.flags & FUSION_FLAG_ENABLED)
456                 fusionHandleAcc(&mTask.fusion, &a, dT);
457 
458             if (mTask.flags & FUSION_FLAG_GAME_ENABLED)
459                 fusionHandleAcc(&mTask.game, &a, dT);
460 
461             updateOutput(i, mTask.samples[ACC][i].time);
462 
463             --mTask.sample_counts[ACC];
464             if (++i == MAX_NUM_SAMPLES)
465                 i = 0;
466             break;
467         case GYR:
468             initVec3(&w, mTask.samples[GYR][j].x, mTask.samples[GYR][j].y, mTask.samples[GYR][j].z);
469 
470             if (mTask.flags & FUSION_FLAG_ENABLED)
471                 fusionHandleGyro(&mTask.fusion, &w, dT);
472 
473             if (mTask.flags & FUSION_FLAG_GAME_ENABLED)
474                 fusionHandleGyro(&mTask.game, &w, dT);
475 
476             --mTask.sample_counts[GYR];
477             if (++j == MAX_NUM_SAMPLES)
478                 j = 0;
479             break;
480         case MAG:
481             initVec3(&m, mTask.samples[MAG][k].x, mTask.samples[MAG][k].y, mTask.samples[MAG][k].z);
482 
483             fusionHandleMag(&mTask.fusion, &m, dT);
484 
485             --mTask.sample_counts[MAG];
486             if (++k == MAX_NUM_SAMPLES)
487                 k = 0;
488             break;
489         }
490     }
491 
492     mTask.sample_indices[ACC] = i;
493 
494     if (mTask.gyro_client_cnt > 0)
495         mTask.sample_indices[GYR] = j;
496 
497     if (mTask.mag_client_cnt > 0)
498         mTask.sample_indices[MAG] = k;
499 
500     for (i = ORIENT; i < NUM_OF_FUSION_SENSOR; i++) {
501         if (mTask.sensors[i].ev != NULL) {
502             osEnqueueEvtOrFree(EVENT_TYPE_BIT_DISCARDABLE | sensorGetMyEventType(mSi[i].sensorType),
503                                mTask.sensors[i].ev, dataEvtFree);
504             mTask.sensors[i].ev = NULL;
505         }
506     }
507 }
508 
configureFusion()509 static void configureFusion()
510 {
511     if (mTask.sensors[ORIENT].active
512             || mTask.sensors[ROTAT].active
513             || mTask.sensors[GEOMAG].active) {
514         mTask.flags |= FUSION_FLAG_ENABLED;
515         initFusion(&mTask.fusion,
516                 (mTask.mag_client_cnt > 0 ? FUSION_USE_MAG : 0) |
517                 (mTask.gyro_client_cnt > 0 ? FUSION_USE_GYRO : 0) |
518                 ((mTask.flags & FUSION_FLAG_INITIALIZED) ? 0 : FUSION_REINITIALIZE));
519         mTask.flags |= FUSION_FLAG_INITIALIZED;
520     } else {
521         mTask.flags &= ~FUSION_FLAG_ENABLED;
522         mTask.flags &= ~FUSION_FLAG_INITIALIZED;
523     }
524 }
525 
configureGame()526 static void configureGame()
527 {
528     if (mTask.sensors[GAME].active || mTask.sensors[GRAVITY].active ||
529             mTask.sensors[LINEAR].active) {
530         mTask.flags |= FUSION_FLAG_GAME_ENABLED;
531         initFusion(&mTask.game, FUSION_USE_GYRO |
532                 ((mTask.flags & FUSION_FLAG_INITIALIZED) ? 0 : FUSION_REINITIALIZE));
533         mTask.flags |= FUSION_FLAG_GAME_INITIALIZED;
534     } else {
535         mTask.flags &= ~FUSION_FLAG_GAME_ENABLED;
536         mTask.flags &= ~FUSION_FLAG_GAME_INITIALIZED;
537     }
538 }
539 
fusionSetRateAcc(void)540 static void fusionSetRateAcc(void)
541 {
542     int i;
543     if  (mTask.accelHandle == 0) {
544         mTask.sample_counts[ACC] = 0;
545         mTask.sample_indices[ACC] = 0;
546         mTask.counters[ACC] = 0;
547         mTask.last_time[ACC] = ULONG_LONG_MAX;
548         for (i = 0; sensorFind(SENS_TYPE_ACCEL, i, &mTask.accelHandle) != NULL; i++) {
549             if (sensorRequest(mTask.tid, mTask.accelHandle, mTask.raw_sensor_rate[ACC],
550                         mTask.raw_sensor_latency)) {
551                 osEventSubscribe(mTask.tid, EVT_SENSOR_ACC_DATA_RDY);
552                 break;
553             }
554         }
555     } else {
556         sensorRequestRateChange(mTask.tid, mTask.accelHandle, mTask.raw_sensor_rate[ACC],
557                 mTask.raw_sensor_latency);
558     }
559 }
560 
fusionSetRateGyr(void)561 static void fusionSetRateGyr(void)
562 {
563     int i;
564     if (mTask.gyroHandle == 0) {
565         mTask.sample_counts[GYR] = 0;
566         mTask.sample_indices[GYR] = 0;
567         mTask.counters[GYR] = 0;
568         mTask.last_time[GYR] = ULONG_LONG_MAX;
569         for (i = 0; sensorFind(SENS_TYPE_GYRO, i, &mTask.gyroHandle) != NULL; i++) {
570             if (sensorRequest(mTask.tid, mTask.gyroHandle, mTask.raw_sensor_rate[GYR],
571                         mTask.raw_sensor_latency)) {
572                 osEventSubscribe(mTask.tid, EVT_SENSOR_GYR_DATA_RDY);
573                 break;
574             }
575         }
576     } else {
577         sensorRequestRateChange(mTask.tid, mTask.gyroHandle, mTask.raw_sensor_rate[GYR],
578                 mTask.raw_sensor_latency);
579     }
580 }
581 
fusionSetRateMag(void)582 static void fusionSetRateMag(void)
583 {
584     int i;
585     if (mTask.magHandle == 0) {
586         mTask.sample_counts[MAG] = 0;
587         mTask.sample_indices[MAG] = 0;
588         mTask.counters[MAG] = 0;
589         mTask.last_time[MAG] = ULONG_LONG_MAX;
590         for (i = 0; sensorFind(SENS_TYPE_MAG, i, &mTask.magHandle) != NULL; i++) {
591             if (sensorRequest(mTask.tid, mTask.magHandle, mTask.raw_sensor_rate[MAG],
592                         mTask.raw_sensor_latency)) {
593                 osEventSubscribe(mTask.tid, EVT_SENSOR_MAG_DATA_RDY);
594                 osEventSubscribe(mTask.tid, EVT_SENSOR_MAG_BIAS);
595                 break;
596             }
597         }
598     } else {
599         sensorRequestRateChange(mTask.tid, mTask.magHandle, mTask.raw_sensor_rate[MAG],
600                 mTask.raw_sensor_latency);
601     }
602 }
603 
fusionSetRate(uint32_t rate,uint64_t latency,void * cookie)604 static bool fusionSetRate(uint32_t rate, uint64_t latency, void *cookie)
605 {
606     struct FusionSensor *mSensor = &mTask.sensors[(int)cookie];
607     int i;
608     uint32_t max_rate = 0;
609     uint32_t gyr_rate, mag_rate;
610     uint64_t min_resample_period = ULONG_LONG_MAX;
611 
612     mSensor->rate = rate;
613     mSensor->latency = latency;
614 
615     for (i = ORIENT; i < NUM_OF_FUSION_SENSOR; i++) {
616         if (mTask.sensors[i].active) {
617             max_rate = max_rate > mTask.sensors[i].rate ? max_rate : mTask.sensors[i].rate;
618         }
619     }
620 
621     if (mTask.accel_client_cnt > 0) {
622         mTask.raw_sensor_rate[ACC] = max_rate;
623         mTask.ResamplePeriodNs[ACC] = sensorTimerLookupCommon(FusionRates, rateTimerVals, max_rate);
624         min_resample_period = mTask.ResamplePeriodNs[ACC] < min_resample_period ?
625             mTask.ResamplePeriodNs[ACC] : min_resample_period;
626     }
627 
628     if (mTask.gyro_client_cnt > 0) {
629         gyr_rate = max_rate > MIN_GYRO_RATE_HZ ? max_rate : MIN_GYRO_RATE_HZ;
630         mTask.raw_sensor_rate[GYR] = gyr_rate;
631         mTask.ResamplePeriodNs[GYR] = sensorTimerLookupCommon(FusionRates, rateTimerVals, gyr_rate);
632         min_resample_period = mTask.ResamplePeriodNs[GYR] < min_resample_period ?
633             mTask.ResamplePeriodNs[GYR] : min_resample_period;
634     }
635 
636     if (mTask.mag_client_cnt > 0) {
637         mag_rate = max_rate < MAX_MAG_RATE_HZ ? max_rate : MAX_MAG_RATE_HZ;
638         mTask.raw_sensor_rate[MAG] = mag_rate;
639         mTask.ResamplePeriodNs[MAG] = sensorTimerLookupCommon(FusionRates, rateTimerVals, mag_rate);
640         min_resample_period = mTask.ResamplePeriodNs[MAG] < min_resample_period ?
641             mTask.ResamplePeriodNs[MAG] : min_resample_period;
642     }
643 
644     // This guarantees that local raw sensor FIFOs won't overflow.
645     mTask.raw_sensor_latency = min_resample_period * (FIFO_DEPTH - 1);
646 
647     for (i = ORIENT; i < NUM_OF_FUSION_SENSOR; i++) {
648         if (mTask.sensors[i].active) {
649             mTask.raw_sensor_latency = mTask.sensors[i].latency < mTask.raw_sensor_latency ?
650                 mTask.sensors[i].latency : mTask.raw_sensor_latency;
651         }
652     }
653 
654     if (mTask.accel_client_cnt > 0)
655         fusionSetRateAcc();
656     if (mTask.gyro_client_cnt > 0)
657         fusionSetRateGyr();
658     if (mTask.mag_client_cnt > 0)
659         fusionSetRateMag();
660     if (mSensor->rate > 0)
661         sensorSignalInternalEvt(mSensor->handle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
662 
663     return true;
664 }
665 
fusionPower(bool on,void * cookie)666 static bool fusionPower(bool on, void *cookie)
667 {
668     struct FusionSensor *mSensor = &mTask.sensors[(int)cookie];
669     int idx;
670 
671     mSensor->active = on;
672     if (on == false) {
673         mTask.accel_client_cnt--;
674         if (mSensor->use_gyro_data)
675             mTask.gyro_client_cnt--;
676         if (mSensor->use_mag_data)
677             mTask.mag_client_cnt--;
678 
679         // if client_cnt == 0 and Handle == 0, nothing need to be done.
680         // if client_cnt > 0 and Handle == 0, something else is turning it on, all will be done.
681         if (mTask.accel_client_cnt == 0 && mTask.accelHandle != 0) {
682             sensorRelease(mTask.tid, mTask.accelHandle);
683             mTask.accelHandle = 0;
684             osEventUnsubscribe(mTask.tid, EVT_SENSOR_ACC_DATA_RDY);
685         }
686 
687         if (mTask.gyro_client_cnt == 0 && mTask.gyroHandle != 0) {
688             sensorRelease(mTask.tid, mTask.gyroHandle);
689             mTask.gyroHandle = 0;
690             osEventUnsubscribe(mTask.tid, EVT_SENSOR_GYR_DATA_RDY);
691         }
692 
693         if (mTask.mag_client_cnt == 0 && mTask.magHandle != 0) {
694             sensorRelease(mTask.tid, mTask.magHandle);
695             mTask.magHandle = 0;
696             osEventUnsubscribe(mTask.tid, EVT_SENSOR_MAG_DATA_RDY);
697         }
698 
699         idx = mSensor->idx;
700         (void) fusionSetRate(0, ULONG_LONG_MAX, (void *)idx);
701     } else {
702         mTask.accel_client_cnt++;
703         if (mSensor->use_gyro_data)
704             mTask.gyro_client_cnt++;
705         if (mSensor->use_mag_data)
706             mTask.mag_client_cnt++;
707     }
708 
709     configureFusion();
710     configureGame();
711     sensorSignalInternalEvt(mSensor->handle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, on, 0);
712 
713     return true;
714 }
715 
fusionFirmwareUpload(void * cookie)716 static bool fusionFirmwareUpload(void *cookie)
717 {
718     struct FusionSensor *mSensor = &mTask.sensors[(int)cookie];
719 
720     sensorSignalInternalEvt(mSensor->handle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
721     return true;
722 }
723 
fusionFlush(void * cookie)724 static bool fusionFlush(void *cookie)
725 {
726     struct FusionSensor *mSensor = &mTask.sensors[(int)cookie];
727     uint32_t evtType = sensorGetMyEventType(mSi[mSensor->idx].sensorType);
728 
729     osEnqueueEvt(evtType, SENSOR_DATA_EVENT_FLUSH, NULL);
730     return true;
731 }
732 
fusionHandleEvent(uint32_t evtType,const void * evtData)733 static void fusionHandleEvent(uint32_t evtType, const void* evtData)
734 {
735     struct TripleAxisDataEvent *ev;
736     int i;
737 
738     if (evtData == SENSOR_DATA_EVENT_FLUSH)
739         return;
740 
741     switch (evtType) {
742     case EVT_APP_START:
743         // check for gyro and mag
744         osEventUnsubscribe(mTask.tid, EVT_APP_START);
745         if (!sensorFind(SENS_TYPE_GYRO, 0, &mTask.gyroHandle)) {
746             for (i = ORIENT; i < NUM_OF_FUSION_SENSOR; i++)
747                 mTask.sensors[i].use_gyro_data = false;
748         }
749         mTask.gyroHandle = 0;
750         if (!sensorFind(SENS_TYPE_MAG, 0, &mTask.magHandle)) {
751             for (i = ORIENT; i < NUM_OF_FUSION_SENSOR; i++)
752                 mTask.sensors[i].use_mag_data = false;
753         }
754         mTask.magHandle = 0;
755         break;
756     case EVT_SENSOR_ACC_DATA_RDY:
757         ev = (struct TripleAxisDataEvent *)evtData;
758         fillSamples(ev, ACC);
759         drainSamples();
760         break;
761     case EVT_SENSOR_GYR_DATA_RDY:
762         ev = (struct TripleAxisDataEvent *)evtData;
763         fillSamples(ev, GYR);
764         drainSamples();
765         break;
766     case EVT_SENSOR_MAG_BIAS:
767         ev = (struct TripleAxisDataEvent *)evtData;
768         if (ev->samples[0].firstSample.biasPresent && mTask.flags & FUSION_FLAG_ENABLED) {
769             //it is a user initiated mag cal event
770             fusionSetMagTrust(&mTask.fusion, MANUAL_MAG_CAL);
771         }
772         break;
773     case EVT_SENSOR_MAG_DATA_RDY:
774         ev = (struct TripleAxisDataEvent *)evtData;
775         fillSamples(ev, MAG);
776         drainSamples();
777         break;
778     }
779 }
780 
781 static const struct SensorOps mSops =
782 {
783     .sensorPower = fusionPower,
784     .sensorFirmwareUpload = fusionFirmwareUpload,
785     .sensorSetRate = fusionSetRate,
786     .sensorFlush = fusionFlush,
787 };
788 
fusionStart(uint32_t tid)789 static bool fusionStart(uint32_t tid)
790 {
791     size_t i, slabSize;
792 
793     mTask.tid = tid;
794     mTask.flags = 0;
795 
796     for (i = 0; i < NUM_OF_RAW_SENSOR; i++) {
797          mTask.sample_counts[i] = 0;
798          mTask.sample_indices[i] = 0;
799     }
800 
801     for (i = ORIENT; i < NUM_OF_FUSION_SENSOR; i++) {
802         mTask.sensors[i].handle = sensorRegister(&mSi[i], &mSops, (void *)i, true);
803         mTask.sensors[i].idx = i;
804         mTask.sensors[i].use_gyro_data = true;
805         mTask.sensors[i].use_mag_data = true;
806     }
807 
808     mTask.sensors[GEOMAG].use_gyro_data = false;
809     mTask.sensors[GAME].use_mag_data = false;
810     mTask.sensors[GRAVITY].use_mag_data = false;
811     mTask.sensors[LINEAR].use_mag_data = false;
812 
813     mTask.accel_client_cnt = 0;
814     mTask.gyro_client_cnt = 0;
815     mTask.mag_client_cnt = 0;
816 
817     slabSize = sizeof(struct TripleAxisDataEvent)
818         + MAX_NUM_COMMS_EVENT_SAMPLES * sizeof(struct TripleAxisDataPoint);
819 
820     // worst case 6 output sensors * (N + 1) comms_events
821     mDataSlab = slabAllocatorNew(slabSize, 4, 6 * (NUM_COMMS_EVENTS_IN_FIFO + 1));
822     if (!mDataSlab) {
823         osLog(LOG_ERROR, "ORIENTATION: slabAllocatorNew() FAILED\n");
824         return false;
825     }
826 
827     osEventSubscribe(mTask.tid, EVT_APP_START);
828 
829     return true;
830 }
831 
fusionEnd()832 static void fusionEnd()
833 {
834     mTask.flags &= ~FUSION_FLAG_INITIALIZED;
835     mTask.flags &= ~FUSION_FLAG_GAME_INITIALIZED;
836     slabAllocatorDestroy(mDataSlab);
837 }
838 
839 INTERNAL_APP_INIT(
840         APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, 4),
841         ORIENTATION_APP_VERSION,
842         fusionStart,
843         fusionEnd,
844         fusionHandleEvent);
845