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 <ash.h>
18 #include <chre.h>
19 #include <cinttypes>
20 
21 #include "chre/util/nanoapp/log.h"
22 
23 /**
24  * @file
25  * A nanoapp exclusively for testing, which saves locally defined ashCalParam
26  * of accel, gyro and mag to storage and lodas them back to check correctness.
27  * The loaded back asCalParam should be identical to the saved one, subject to
28  * storage quantization error.
29  * It's suggested that a copy of the original storage be made before running
30  * this test nanoapp so the original storage can be retained.
31  * Note that ASH functionality is not required for CHRE.
32  */
33 
34 #define LOG_TAG "[AshWorld]"
35 
36 #ifdef CHRE_NANOAPP_INTERNAL
37 namespace chre {
38 namespace {
39 #endif  // CHRE_NANOAPP_INTERNAL
40 
41 uint32_t gCyclicTimerHandle;
42 uint32_t gCyclicTimerCount;
43 
44 struct ashCalParams accCalParams = {
45   .offset = {0.0, 1.0, 2.0},
46   .offsetTempCelsius = 3.0,
47   .tempSensitivity = {4.0, 5.0, 6.0},
48   .tempIntercept = {7.0, 8.0, 9.0},
49   .scaleFactor = {10.0, 11.0, 12.0},
50   .crossAxis = {13.0, 14.0, 15.0},
51   .offsetSource = 16,
52   .offsetTempCelsiusSource = 17,
53   .tempSensitivitySource = 18,
54   .tempInterceptSource = 19,
55   .scaleFactorSource = 20,
56   .crossAxisSource = 21,
57 };
58 
59 struct ashCalParams gyrCalParams = {
60   .offset = {100.0, 101.0, 102.0},
61   .offsetTempCelsius = 103.0,
62   .tempSensitivity = {104.0, 105.0, 106.0},
63   .tempIntercept = {107.0, 108.0, 109.0},
64   .scaleFactor = {110.0, 111.0, 112.0},
65   .crossAxis = {113.0, 114.0, 115.0},
66   .offsetSource = 116,
67   .offsetTempCelsiusSource = 117,
68   .tempSensitivitySource = 118,
69   .tempInterceptSource = 119,
70   .scaleFactorSource = 120,
71   .crossAxisSource = 121,
72 };
73 
74 struct ashCalParams magCalParams = {
75   .offset = {200.0, 201.0, 202.0},
76   .offsetTempCelsius = 203.0,
77   .tempSensitivity = {204.0, 205.0, 206.0},
78   .tempIntercept = {207.0, 208.0, 209.0},
79   .scaleFactor = {210.0, 211.0, 212.0},
80   .crossAxis = {213.0, 214.0, 215.0},
81   .offsetSource = 216,
82   .offsetTempCelsiusSource = 217,
83   .tempSensitivitySource = 218,
84   .tempInterceptSource = 219,
85   .scaleFactorSource = 220,
86   .crossAxisSource = 221,
87 };
88 
89 struct ashCalInfo accCalInfo = {
90   .bias = {0.1f, -0.1f, 0.2f},
91   .compMatrix = {1.0f, 0.1f, -0.1f, 0.2f, -0.2f, 1.0f, 0.3f, -0.3f, 1.0f},
92   .accuracy = 1,
93 };
94 
95 struct ashCalInfo gyrCalInfo = {
96   .bias = {0.2f, -0.2f, 0.1f},
97   .compMatrix = {1.0f, 0.2f, -0.2f, 0.4f, -0.4f, 1.0f, 0.6f, -0.6f, 1.0f},
98   .accuracy = 2,
99 };
100 
101 struct ashCalInfo magCalInfo = {
102   .bias = {10, -10, 20},
103   .compMatrix = {1.0f, -0.1f, 0.1f, -0.2f, 0.2f, 1.0f, -0.3f, 0.3f, 1.0f},
104   .accuracy = 3,
105 };
106 
nanoappStart()107 bool nanoappStart() {
108   LOGI("App started on platform ID %" PRIx64, chreGetPlatformId());
109 
110   gCyclicTimerHandle = chreTimerSet(3000000000 /* duration: 3sec */,
111       &gCyclicTimerHandle /* data */,
112       false /* oneShot */);
113   gCyclicTimerCount = 0;
114   return true;
115 }
116 
handleTimerEvent(const void * eventData)117 void handleTimerEvent(const void *eventData) {
118   LOGI("Cyclic timer event received %" PRIu32, gCyclicTimerCount);
119   bool success = false;
120   uint64_t tic = 0, toc = 0;
121 
122   uint8_t sensor = CHRE_SENSOR_TYPE_ACCELEROMETER;
123   struct ashCalParams *sensorCalParams = &accCalParams;
124   struct ashCalInfo *sensorCalInfo = &accCalInfo;
125   if ((gCyclicTimerCount / 3) == 1) {
126     sensor = CHRE_SENSOR_TYPE_GYROSCOPE;
127     sensorCalParams = &gyrCalParams;
128     sensorCalInfo = &gyrCalInfo;
129   } else if ((gCyclicTimerCount / 3) == 2) {
130     sensor = CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD;
131     sensorCalParams = &magCalParams;
132     sensorCalInfo = &magCalInfo;
133   }
134 
135   if (gCyclicTimerCount >= 9) {
136     chreTimerCancel(gCyclicTimerHandle);
137     LOGI("Timer cancelled");
138   } else if (gCyclicTimerCount % 3 == 0) {
139     tic = chreGetTime();
140     success = ashSaveCalibrationParams(sensor, sensorCalParams);
141     toc = chreGetTime();
142     LOGI("*** save sensor %" PRIu8 ": %s, time %" PRIu64 " us",
143          sensor, success ? "success" : "failure", (toc - tic) / 1000);
144   } else if (gCyclicTimerCount % 3 == 1) {
145     struct ashCalParams p;
146     tic = chreGetTime();
147     success = ashLoadCalibrationParams(sensor, ASH_CAL_STORAGE_ASH, &p);
148     toc = chreGetTime();
149     LOGI("*** load sensor %" PRIu8 ": %s, time %" PRIu64 " us",
150          sensor, success ? "success" : "fail", (toc - tic) / 1000);
151 
152     LOGI("offset %f %f %f", p.offset[0], p.offset[1], p.offset[2]);
153     LOGI("offsetTempCelsius %f", p.offsetTempCelsius);
154     LOGI("tempSensitivity %f %f %f", p.tempSensitivity[0],
155          p.tempSensitivity[1], p.tempSensitivity[2]);
156     LOGI("tempIntercept %f %f %f", p.tempIntercept[0],
157          p.tempIntercept[1], p.tempIntercept[2]);
158     LOGI("scaleFactor %f %f %f", p.scaleFactor[0],
159          p.scaleFactor[1], p.scaleFactor[2]);
160     LOGI("crossAxis %f %f %f", p.crossAxis[0], p.crossAxis[1], p.crossAxis[2]);
161     LOGI("%" PRIu8 " %" PRIu8 " %" PRIu8 " %" PRIu8 " %" PRIu8 " %" PRIu8,
162          p.offsetSource, p.offsetTempCelsiusSource, p.tempSensitivitySource,
163          p.tempInterceptSource, p.scaleFactorSource, p.crossAxisSource);
164   } else {
165     tic = chreGetTime();
166     success = ashSetCalibration(sensor, sensorCalInfo);
167     toc = chreGetTime();
168     LOGI("*** set sensor %" PRIu8 ": %s, time %" PRIu64 " us",
169          sensor, success ? "success" : "failure", (toc - tic) / 1000);
170   }
171 
172   gCyclicTimerCount++;
173 }
174 
nanoappHandleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)175 void nanoappHandleEvent(uint32_t senderInstanceId,
176                         uint16_t eventType,
177                         const void *eventData) {
178   switch (eventType) {
179     case CHRE_EVENT_TIMER:
180       handleTimerEvent(eventData);
181       break;
182     default:
183       LOGW("Unknown event received");
184       break;
185   }
186 }
187 
nanoappEnd()188 void nanoappEnd() {
189   LOGI("Stopped");
190 }
191 
192 #ifdef CHRE_NANOAPP_INTERNAL
193 }  // anonymous namespace
194 }  // namespace chre
195 
196 #include "chre/util/nanoapp/app_id.h"
197 #include "chre/platform/static_nanoapp_init.h"
198 
199 CHRE_STATIC_NANOAPP_INIT(AshWorld, chre::kAshWorldAppId, 0);
200 #endif  // CHRE_NANOAPP_INTERNAL
201