• 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 <atomic.h>
18 #include <gpio.h>
19 #include <isr.h>
20 #include <nanohubPacket.h>
21 #include <plat/exti.h>
22 #include <plat/gpio.h>
23 #include <platform.h>
24 #include <plat/syscfg.h>
25 #include <plat/rtc.h>
26 #include <sensors.h>
27 #include <seos.h>
28 #include <halIntf.h>
29 #include <slab.h>
30 #include <heap.h>
31 #include <i2c.h>
32 #include <timer.h>
33 #include <variant/sensType.h>
34 #include <cpu/cpuMath.h>
35 #include <calibration/magnetometer/mag_cal.h>
36 #include <floatRt.h>
37 
38 #include <stdlib.h>
39 #include <string.h>
40 #include <variant/variant.h>
41 
42 #define ST_MAG40_APP_ID            APP_ID_MAKE(NANOHUB_VENDOR_STMICRO, 3)
43 
44 /* Sensor registers */
45 #define ST_MAG40_WAI_REG_ADDR      0x4F
46 #define ST_MAG40_WAI_REG_VAL       0x40
47 
48 #define ST_MAG40_CFG_A_REG_ADDR    0x60
49 #define ST_MAG40_TEMP_COMP_EN      0x80
50 #define ST_MAG40_SOFT_RESET_BIT    0x20
51 #define ST_MAG40_ODR_10_HZ         0x00
52 #define ST_MAG40_ODR_20_HZ         0x04
53 #define ST_MAG40_ODR_50_HZ         0x08
54 #define ST_MAG40_ODR_100_HZ        0x0C
55 #define ST_MAG40_POWER_ON          0x00
56 #define ST_MAG40_POWER_IDLE        0x03
57 
58 #define ST_MAG40_CFG_B_REG_ADDR    0x61
59 #define ST_MAG40_OFF_CANC          0x02
60 
61 #define ST_MAG40_CFG_C_REG_ADDR    0x62
62 #define ST_MAG40_I2C_DIS           0x20
63 #define ST_MAG40_BDU_ON            0x10
64 #define ST_MAG40_SELFTEST_EN       0x02
65 #define ST_MAG40_INT_MAG           0x01
66 
67 #define ST_MAG40_OUTXL_REG_ADDR    0x68
68 
69 /* Enable auto-increment of the I2C subaddress (to allow I2C multiple ops) */
70 #define ST_MAG40_I2C_AUTO_INCR     0x80
71 
72 enum st_mag40_SensorEvents
73 {
74     EVT_COMM_DONE = EVT_APP_START + 1,
75     EVT_SENSOR_INTERRUPT,
76 };
77 
78 enum st_mag40_TestState {
79     MAG_SELFTEST_INIT,
80     MAG_SELFTEST_RUN_ST_OFF,
81     MAG_SELFTEST_INIT_ST_EN,
82     MAG_SELFTEST_RUN_ST_ON,
83     MAG_SELFTEST_VERIFY,
84     MAG_SELFTEST_DONE,
85 };
86 
87 enum st_mag40_SensorState {
88     SENSOR_BOOT,
89     SENSOR_VERIFY_ID,
90     SENSOR_INITIALIZATION,
91     SENSOR_IDLE,
92     SENSOR_MAG_CONFIGURATION,
93     SENSOR_READ_SAMPLES,
94     SENSOR_SELF_TEST,
95 };
96 
97 enum st_mag40_subState {
98     NO_SUBSTATE = 0,
99 
100     INIT_START,
101     INIT_ENABLE_DRDY,
102     INIT_I2C_DISABLE_ACCEL,
103     INIT_DONE,
104 
105     CONFIG_POWER_UP,
106     CONFIG_POWER_UP_2,
107 
108     CONFIG_POWER_DOWN,
109     CONFIG_POWER_DOWN_2,
110 
111     CONFIG_SET_RATE,
112     CONFIG_SET_RATE_2,
113 
114     CONFIG_DONE,
115 };
116 
117 struct TestResultData {
118     struct HostHubRawPacket header;
119     struct SensorAppEventHeader data_header;
120 } __attribute__((packed));
121 
122 #ifndef ST_MAG40_I2C_BUS_ID
123 #error "ST_MAG40_I2C_BUS_ID is not defined; please define in variant.h"
124 #endif
125 
126 #ifndef ST_MAG40_I2C_SPEED
127 #error "ST_MAG40_I2C_SPEED is not defined; please define in variant.h"
128 #endif
129 
130 #ifndef ST_MAG40_I2C_ADDR
131 #error "ST_MAG40_I2C_ADDR is not defined; please define in variant.h"
132 #endif
133 
134 #ifndef ST_MAG40_INT_PIN
135 #error "ST_MAG40_INT_PIN is not defined; please define in variant.h"
136 #endif
137 
138 #ifndef ST_MAG40_INT_IRQ
139 #error "ST_MAG40_INT_IRQ is not defined; please define in variant.h"
140 #endif
141 
142 #ifndef ST_MAG40_ROT_MATRIX
143 #error "ST_MAG40_ROT_MATRIX is not defined; please define in variant.h"
144 #endif
145 
146 #define ST_MAG40_X_MAP(x, y, z, r11, r12, r13, r21, r22, r23, r31, r32, r33) \
147                                                       ((r11 == 1 ? x : (r11 == -1 ? -x : 0)) + \
148                                                        (r12 == 1 ? y : (r12 == -1 ? -y : 0)) + \
149                                                        (r13 == 1 ? z : (r13 == -1 ? -z : 0)))
150 
151 #define ST_MAG40_Y_MAP(x, y, z, r11, r12, r13, r21, r22, r23, r31, r32, r33) \
152                                                       ((r21 == 1 ? x : (r21 == -1 ? -x : 0)) + \
153                                                        (r22 == 1 ? y : (r22 == -1 ? -y : 0)) + \
154                                                        (r23 == 1 ? z : (r23 == -1 ? -z : 0)))
155 
156 #define ST_MAG40_Z_MAP(x, y, z, r11, r12, r13, r21, r22, r23, r31, r32, r33) \
157                                                       ((r31 == 1 ? x : (r31 == -1 ? -x : 0)) + \
158                                                        (r32 == 1 ? y : (r32 == -1 ? -y : 0)) + \
159                                                        (r33 == 1 ? z : (r33 == -1 ? -z : 0)))
160 
161 #define ST_MAG40_REMAP_X_DATA(...)                     ST_MAG40_X_MAP(__VA_ARGS__)
162 #define ST_MAG40_REMAP_Y_DATA(...)                     ST_MAG40_Y_MAP(__VA_ARGS__)
163 #define ST_MAG40_REMAP_Z_DATA(...)                     ST_MAG40_Z_MAP(__VA_ARGS__)
164 
165 /* Self Test macros */
166 #define ST_MAG40_ST_NUM_OF_SAMPLES        50
167 #define ST_MAG40_ST_MIN_THRESHOLD         10 /* 15 mGa */
168 #define ST_MAG40_ST_MAX_THRESHOLD        333 /* 500 mGa */
169 
170 #define INFO_PRINT(fmt, ...) \
171     do { \
172         osLog(LOG_INFO, "%s " fmt, "[ST_MAG40]", ##__VA_ARGS__); \
173     } while (0);
174 
175 #define DEBUG_PRINT(fmt, ...) \
176     do { \
177         if (ST_MAG40_DBG_ENABLED) { \
178             osLog(LOG_DEBUG, "%s " fmt, "[ST_MAG40]", ##__VA_ARGS__); \
179         } \
180     } while (0);
181 
182 #define ERROR_PRINT(fmt, ...) \
183     do { \
184         osLog(LOG_ERROR, "%s " fmt, "[ST_MAG40]", ##__VA_ARGS__); \
185     } while (0);
186 
187 /* DO NOT MODIFY, just to avoid compiler error if not defined using FLAGS */
188 #ifndef ST_MAG40_DBG_ENABLED
189 #define ST_MAG40_DBG_ENABLED                           0
190 #endif /* ST_MAG40_DBG_ENABLED */
191 
192 #define ST_MAG40_MAX_PENDING_I2C_REQUESTS   4
193 #define ST_MAG40_MAX_I2C_TRANSFER_SIZE      6
194 #define ST_MAG40_MAX_MAG_EVENTS             20
195 
196 struct I2cTransfer
197 {
198     size_t tx;
199     size_t rx;
200     int err;
201     uint8_t txrxBuf[ST_MAG40_MAX_I2C_TRANSFER_SIZE];
202     bool last;
203     bool inUse;
204     uint32_t delay;
205 };
206 
207 /* Task structure */
208 struct st_mag40_Task {
209     uint32_t tid;
210 
211     struct SlabAllocator *magDataSlab;
212 
213     uint64_t timestampInt;
214 
215     volatile uint8_t state; //task state, type enum st_mag40_SensorState, do NOT change this directly
216     uint8_t subState;
217 
218     /* sensor flags */
219     uint8_t samplesToDiscard;
220     uint32_t rate;
221     uint64_t latency;
222     bool magOn;
223     bool pendingInt;
224     uint8_t pendingSubState;
225 
226     uint8_t currentODR;
227 
228 #if defined(ST_MAG40_CAL_ENABLED)
229     struct MagCal moc;
230 #endif
231 
232     unsigned char       sens_buf[7];
233 
234     struct I2cTransfer transfers[ST_MAG40_MAX_PENDING_I2C_REQUESTS];
235 
236     /* Communication functions */
237     void (*comm_tx)(uint8_t addr, uint8_t data, uint32_t delay, bool last);
238     void (*comm_rx)(uint8_t addr, uint16_t len, uint32_t delay, bool last);
239 
240     /* irq */
241     struct Gpio *Int1;
242     struct ChainedIsr Isr1;
243 
244     /* Self Test */
245     enum st_mag40_TestState mag_test_state;
246     uint32_t mag_selftest_num;
247     int32_t dataST[3];
248     int32_t dataNOST[3];
249 
250     /* sensors */
251     uint32_t magHandle;
252 };
253 
254 static struct st_mag40_Task mTask;
255 
256 static void sensorMagConfig(void);
257 
258 #define PRI_STATE PRIi32
getStateName(int32_t s)259 static int32_t getStateName(int32_t s) {
260     return s;
261 }
262 
263 // Atomic get state
264 #define GET_STATE() (atomicReadByte(&mTask.state))
265 
266 // Atomic set state, this set the state to arbitrary value, use with caution
267 #define SET_STATE(s) do{\
268         DEBUG_PRINT("set state %" PRI_STATE "\n", getStateName(s));\
269         atomicWriteByte(&mTask.state, (s));\
270     }while(0)
271 
272 // Atomic switch state from IDLE to desired state.
trySwitchState(enum st_mag40_SensorState newState)273 static bool trySwitchState(enum st_mag40_SensorState newState) {
274 #if DBG_STATE
275     bool ret = atomicCmpXchgByte(&mTask.state, SENSOR_IDLE, newState);
276     uint8_t prevState = ret ? SENSOR_IDLE : GET_STATE();
277     DEBUG_PRINT("switch state %" PRI_STATE "->%" PRI_STATE ", %s\n",
278             getStateName(prevState), getStateName(newState), ret ? "ok" : "failed");
279     return ret;
280 #else
281     return atomicCmpXchgByte(&mTask.state, SENSOR_IDLE, newState);
282 #endif
283 }
284 
magAllocateEvt(struct TripleAxisDataEvent ** evPtr)285 static bool magAllocateEvt(struct TripleAxisDataEvent **evPtr)
286 {
287     struct TripleAxisDataEvent *ev;
288 
289     ev = *evPtr = slabAllocatorAlloc(mTask.magDataSlab);
290     if (!ev) {
291         ERROR_PRINT("Failed to allocate mag event memory");
292         return false;
293     }
294 
295     memset(&ev->samples[0].firstSample, 0x00, sizeof(struct SensorFirstSample));
296     return true;
297 }
298 
magFreeEvt(void * ptr)299 static void magFreeEvt(void *ptr)
300 {
301     slabAllocatorFree(mTask.magDataSlab, ptr);
302 }
303 
304 // Allocate a buffer and mark it as in use with the given state, or return NULL
305 // if no buffers available. Must *not* be called from interrupt context.
allocXfer(void)306 static struct I2cTransfer *allocXfer(void)
307 {
308     size_t i;
309 
310     for (i = 0; i < ARRAY_SIZE(mTask.transfers); i++) {
311         if (!mTask.transfers[i].inUse) {
312             mTask.transfers[i].inUse = true;
313             return &mTask.transfers[i];
314         }
315     }
316 
317     ERROR_PRINT("Ran out of i2c buffers!");
318     return NULL;
319 }
320 
releaseXfer(struct I2cTransfer * xfer)321 static inline void releaseXfer(struct I2cTransfer *xfer)
322 {
323     xfer->inUse = false;
324 }
325 
326 static void i2cCallback(void *cookie, size_t tx, size_t rx, int err);
327 
328 /* delayed callback */
i2cDelayCallback(uint32_t timerId,void * data)329 static void i2cDelayCallback(uint32_t timerId, void *data)
330 {
331     struct I2cTransfer *xfer = data;
332 
333     i2cCallback((void *)xfer, xfer->tx, xfer->rx, xfer->err);
334 }
335 
i2cCallback(void * cookie,size_t tx,size_t rx,int err)336 static void i2cCallback(void *cookie, size_t tx, size_t rx, int err)
337 {
338     struct I2cTransfer *xfer = cookie;
339 
340     /* Do not run callback if not the last one in a set of i2c transfers */
341     if (xfer && !xfer->last) {
342         releaseXfer(xfer);
343         return;
344     }
345 
346     /* delay callback if it is the case */
347     if (xfer->delay > 0) {
348         xfer->tx = tx;
349         xfer->rx = rx;
350         xfer->err = err;
351 
352         if (!timTimerSet(xfer->delay * 1000, 0, 50, i2cDelayCallback, xfer, true)) {
353             ERROR_PRINT("Cannot do delayed i2cCallback\n");
354             goto handle_now;
355         }
356 
357         xfer->delay = 0;
358         return;
359     }
360 
361 handle_now:
362     xfer->tx = tx;
363     xfer->rx = rx;
364     xfer->err = err;
365 
366     osEnqueuePrivateEvt(EVT_COMM_DONE, cookie, NULL, mTask.tid);
367     if (err != 0)
368         ERROR_PRINT("i2c error (tx: %d, rx: %d, err: %d)\n", tx, rx, err);
369 }
370 
i2c_read(uint8_t addr,uint16_t len,uint32_t delay,bool last)371 static void i2c_read(uint8_t addr, uint16_t len, uint32_t delay, bool last)
372 {
373     struct I2cTransfer *xfer = allocXfer();
374 
375     if (xfer != NULL) {
376         xfer->delay = delay;
377         xfer->last = last;
378         xfer->txrxBuf[0] = ST_MAG40_I2C_AUTO_INCR | addr;
379         i2cMasterTxRx(ST_MAG40_I2C_BUS_ID, ST_MAG40_I2C_ADDR, xfer->txrxBuf, 1, xfer->txrxBuf, len, i2cCallback, xfer);
380     }
381 }
382 
i2c_write(uint8_t addr,uint8_t data,uint32_t delay,bool last)383 static void i2c_write(uint8_t addr, uint8_t data, uint32_t delay, bool last)
384 {
385     struct I2cTransfer *xfer = allocXfer();
386 
387     if (xfer != NULL) {
388         xfer->delay = delay;
389         xfer->last = last;
390         xfer->txrxBuf[0] = addr;
391         xfer->txrxBuf[1] = data;
392         i2cMasterTx(ST_MAG40_I2C_BUS_ID, ST_MAG40_I2C_ADDR, xfer->txrxBuf, 2, i2cCallback, xfer);
393     }
394 }
395 
396 #define DEC_INFO_BIAS(name, type, axis, inter, samples, rates, raw, scale, bias) \
397     .sensorName = name, \
398     .sensorType = type, \
399     .numAxis = axis, \
400     .interrupt = inter, \
401     .minSamples = samples, \
402     .supportedRates = rates, \
403     .rawType = raw, \
404     .rawScale = scale, \
405     .biasType = bias
406 
407 #define DEC_INFO(name, type, axis, inter, samples, rates, raw, scale) \
408     .sensorName = name, \
409     .sensorType = type, \
410     .numAxis = axis, \
411     .interrupt = inter, \
412     .minSamples = samples, \
413     .supportedRates = rates, \
414     .rawType = raw, \
415     .rawScale = scale,
416 
417 static uint32_t st_mag40_Rates[] = {
418     SENSOR_HZ(10.0f),
419     SENSOR_HZ(20.0f),
420     SENSOR_HZ(50.0f),
421     SENSOR_HZ(100.0f),
422     0
423 };
424 
425 static uint32_t st_mag40_regVal[] = {
426     ST_MAG40_ODR_10_HZ,
427     ST_MAG40_ODR_20_HZ,
428     ST_MAG40_ODR_50_HZ,
429     ST_MAG40_ODR_100_HZ,
430 };
431 
st_mag40_computeOdr(uint32_t rate)432 static uint8_t st_mag40_computeOdr(uint32_t rate)
433 {
434     int i;
435 
436     for (i = 0; i < (ARRAY_SIZE(st_mag40_Rates) - 1); i++) {
437         if (st_mag40_Rates[i] == rate)
438             break;
439     }
440     if (i == (ARRAY_SIZE(st_mag40_Rates) -1 )) {
441         ERROR_PRINT("ODR not valid! Choosed smallest ODR available\n");
442         i = 0;
443     }
444 
445     return i;
446 }
447 
448 
449 static const struct SensorInfo st_mag40_SensorInfo =
450 {
451 #if defined(ST_MAG40_CAL_ENABLED)
452     DEC_INFO_BIAS("Magnetometer", SENS_TYPE_MAG, NUM_AXIS_THREE, NANOHUB_INT_NONWAKEUP,
453         600, st_mag40_Rates, 0, 0, SENS_TYPE_MAG_BIAS)
454 #else
455     DEC_INFO("Magnetometer", SENS_TYPE_MAG, NUM_AXIS_THREE, NANOHUB_INT_NONWAKEUP,
456         600, st_mag40_Rates, 0, 0)
457 #endif
458 };
459 
460 /* Sensor Operations */
magPower(bool on,void * cookie)461 static bool magPower(bool on, void *cookie)
462 {
463     INFO_PRINT("magPower %s\n", on ? "on" : "off");
464     if (trySwitchState(SENSOR_MAG_CONFIGURATION)) {
465         mTask.subState = on ? CONFIG_POWER_UP : CONFIG_POWER_DOWN;
466         sensorMagConfig();
467     } else {
468         mTask.pendingSubState = on ? CONFIG_POWER_UP : CONFIG_POWER_DOWN;
469     }
470 
471     return true;
472 }
473 
magFwUpload(void * cookie)474 static bool magFwUpload(void *cookie)
475 {
476     return sensorSignalInternalEvt(mTask.magHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
477 }
478 
magSetRate(uint32_t rate,uint64_t latency,void * cookie)479 static bool magSetRate(uint32_t rate, uint64_t latency, void *cookie)
480 {
481     uint8_t num = 0;
482 
483     INFO_PRINT("magSetRate %lu Hz - %llu ns\n", rate, latency);
484 
485     num = st_mag40_computeOdr(rate);
486     mTask.currentODR = st_mag40_regVal[num];
487     mTask.rate = rate;
488     mTask.latency = latency;
489     mTask.samplesToDiscard = 2;
490 
491     if (trySwitchState(SENSOR_MAG_CONFIGURATION)) {
492         mTask.subState = CONFIG_SET_RATE;
493         sensorMagConfig();
494     } else {
495         mTask.pendingSubState = CONFIG_SET_RATE;
496     }
497 
498     return true;
499 }
500 
magFlush(void * cookie)501 static bool magFlush(void *cookie)
502 {
503     INFO_PRINT("magFlush\n");
504     return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_MAG), SENSOR_DATA_EVENT_FLUSH, NULL);
505 }
506 
magCfgData(void * data,void * cookie)507 static bool magCfgData(void *data, void *cookie)
508 {
509 #if defined(ST_MAG40_CAL_ENABLED)
510     const struct AppToSensorHalDataPayload *p = data;
511 
512     if (p->type == HALINTF_TYPE_MAG_CAL_BIAS && p->size == sizeof(struct MagCalBias)) {
513         const struct MagCalBias *d = p->magCalBias;
514         INFO_PRINT("magCfgData: calibration %ldnT, %ldnT, %ldnT\n",
515                 (int32_t)(d->bias[0] * 1000),
516                 (int32_t)(d->bias[1] * 1000),
517                 (int32_t)(d->bias[2] * 1000));
518 
519         mTask.moc.x_bias = d->bias[0];
520         mTask.moc.y_bias = d->bias[1];
521         mTask.moc.z_bias = d->bias[2];
522     } else if (p->type == HALINTF_TYPE_MAG_LOCAL_FIELD && p->size == sizeof(struct MagLocalField)) {
523         const struct MagLocalField *d = p->magLocalField;
524         INFO_PRINT("magCfgData: local field strength %dnT, dec %ddeg, inc %ddeg\n",
525                 (int)(d->strength * 1000),
526                 (int)(d->declination * 180 / M_PI + 0.5f),
527                 (int)(d->inclination * 180 / M_PI + 0.5f));
528 
529         // Passing local field information to mag calibration routine
530 #ifdef DIVERSITY_CHECK_ENABLED
531         diversityCheckerLocalFieldUpdate(&mTask.moc.diversity_checker, d->strength);
532 #endif
533         // TODO: pass local field information to rotation vector sensor.
534     } else {
535         ERROR_PRINT("magCfgData: unknown type 0x%04x, size %d", p->type, p->size);
536     }
537 #endif /* ST_MAG40_CAL_ENABLED */
538 
539     return true;
540 }
541 
sendTestResult(uint8_t status,uint8_t sensorType)542 static void sendTestResult(uint8_t status, uint8_t sensorType)
543 {
544     struct TestResultData *data = heapAlloc(sizeof(struct TestResultData));
545     if (!data) {
546         ERROR_PRINT("Couldn't alloc test result packet");
547         return;
548     }
549 
550     data->header.appId = ST_MAG40_APP_ID;
551     data->header.dataLen = (sizeof(struct TestResultData) - sizeof(struct HostHubRawPacket));
552     data->data_header.msgId = SENSOR_APP_MSG_ID_TEST_RESULT;
553     data->data_header.sensorType = sensorType;
554     data->data_header.status = status;
555 
556     if (!osEnqueueEvtOrFree(EVT_APP_TO_HOST, data, heapFree))
557         ERROR_PRINT("Couldn't send test result packet");
558 }
559 
magTestHandling(struct I2cTransfer * xfer)560 static void magTestHandling(struct I2cTransfer *xfer)
561 {
562     int32_t dataGap[3];
563 
564     switch(mTask.mag_test_state) {
565     case MAG_SELFTEST_INIT:
566         mTask.mag_selftest_num = 0;
567         memset(mTask.dataNOST, 0, 3 * sizeof(int32_t));
568 
569         mTask.mag_test_state = MAG_SELFTEST_RUN_ST_OFF;
570         mTask.comm_tx(ST_MAG40_CFG_A_REG_ADDR, ST_MAG40_ODR_100_HZ, 0, false);
571         mTask.comm_tx(ST_MAG40_CFG_B_REG_ADDR, ST_MAG40_OFF_CANC, 0, false);
572         mTask.comm_tx(ST_MAG40_CFG_C_REG_ADDR, ST_MAG40_BDU_ON, 0, true);
573         break;
574 
575     case MAG_SELFTEST_RUN_ST_OFF:
576         if (mTask.mag_selftest_num++ > 0) {
577             uint8_t *raw = &xfer->txrxBuf[0];
578 
579             mTask.dataNOST[0] += (*(int16_t *)&raw[0]);
580             mTask.dataNOST[1] += (*(int16_t *)&raw[2]);
581             mTask.dataNOST[2] += (*(int16_t *)&raw[4]);
582         }
583 
584         if (mTask.mag_selftest_num <= ST_MAG40_ST_NUM_OF_SAMPLES) {
585             mTask.comm_rx(ST_MAG40_OUTXL_REG_ADDR, 6, 10000, true);
586 
587             break;
588         }
589 
590         mTask.dataNOST[0] /= ST_MAG40_ST_NUM_OF_SAMPLES;
591         mTask.dataNOST[1] /= ST_MAG40_ST_NUM_OF_SAMPLES;
592         mTask.dataNOST[2] /= ST_MAG40_ST_NUM_OF_SAMPLES;
593         mTask.mag_test_state = MAG_SELFTEST_INIT_ST_EN;
594         /* fall through */
595 
596     case MAG_SELFTEST_INIT_ST_EN:
597         mTask.mag_selftest_num = 0;
598         memset(mTask.dataST, 0, 3 * sizeof(int32_t));
599 
600         mTask.mag_test_state = MAG_SELFTEST_RUN_ST_ON;
601         mTask.comm_tx(ST_MAG40_CFG_C_REG_ADDR, ST_MAG40_BDU_ON | ST_MAG40_SELFTEST_EN, 0, true);
602         break;
603 
604     case MAG_SELFTEST_RUN_ST_ON:
605         if (mTask.mag_selftest_num++ > 0) {
606             uint8_t *raw = &xfer->txrxBuf[0];
607 
608             mTask.dataST[0] += (*(int16_t *)&raw[0]);
609             mTask.dataST[1] += (*(int16_t *)&raw[2]);
610             mTask.dataST[2] += (*(int16_t *)&raw[4]);
611         }
612 
613         if (mTask.mag_selftest_num <= ST_MAG40_ST_NUM_OF_SAMPLES) {
614             mTask.comm_rx(ST_MAG40_OUTXL_REG_ADDR, 6, 10000, true);
615 
616             break;
617         }
618 
619         mTask.dataST[0] /= ST_MAG40_ST_NUM_OF_SAMPLES;
620         mTask.dataST[1] /= ST_MAG40_ST_NUM_OF_SAMPLES;
621         mTask.dataST[2] /= ST_MAG40_ST_NUM_OF_SAMPLES;
622         mTask.mag_test_state = MAG_SELFTEST_VERIFY;
623 
624         /* fall through */
625 
626     case MAG_SELFTEST_VERIFY:
627         dataGap[0] = abs(mTask.dataST[0] - mTask.dataNOST[0]);
628         dataGap[1] = abs(mTask.dataST[1] - mTask.dataNOST[1]);
629         dataGap[2] = abs(mTask.dataST[2] - mTask.dataNOST[2]);
630 
631         if (dataGap[0] >= ST_MAG40_ST_MIN_THRESHOLD &&
632             dataGap[0] <= ST_MAG40_ST_MAX_THRESHOLD &&
633             dataGap[1] >= ST_MAG40_ST_MIN_THRESHOLD &&
634             dataGap[1] <= ST_MAG40_ST_MAX_THRESHOLD &&
635             dataGap[2] >= ST_MAG40_ST_MIN_THRESHOLD &&
636             dataGap[2] <= ST_MAG40_ST_MAX_THRESHOLD)
637                 sendTestResult(SENSOR_APP_EVT_STATUS_SUCCESS, SENS_TYPE_MAG);
638         else
639                 sendTestResult(SENSOR_APP_EVT_STATUS_ERROR, SENS_TYPE_MAG);
640 
641         mTask.mag_test_state = MAG_SELFTEST_DONE;
642         mTask.comm_tx(ST_MAG40_CFG_A_REG_ADDR, ST_MAG40_TEMP_COMP_EN | ST_MAG40_POWER_IDLE, 0, false);
643         mTask.comm_tx(ST_MAG40_CFG_C_REG_ADDR, ST_MAG40_BDU_ON | ST_MAG40_INT_MAG, 0, true);
644         break;
645 
646     case MAG_SELFTEST_DONE:
647         break;
648     }
649 }
650 
magSelfTest(void * cookie)651 static bool magSelfTest(void *cookie)
652 {
653     INFO_PRINT("magSelfTest\n");
654 
655     if (!mTask.magOn && trySwitchState(SENSOR_SELF_TEST)) {
656         mTask.mag_test_state = MAG_SELFTEST_INIT;
657         magTestHandling(NULL);
658         return true;
659     } else {
660         ERROR_PRINT("cannot test mag because sensor is busy\n");
661         sendTestResult(SENSOR_APP_EVT_STATUS_BUSY, SENS_TYPE_MAG);
662         return false;
663     }
664 }
665 
666 #define DEC_OPS(power, firmware, rate, flush, test, cal, cfg) \
667     .sensorPower = power, \
668     .sensorFirmwareUpload = firmware, \
669     .sensorSetRate = rate, \
670     .sensorFlush = flush, \
671     .sensorCalibrate = cal, \
672     .sensorSelfTest = test, \
673     .sensorCfgData = cfg
674 
675 static const struct SensorOps st_mag40_SensorOps =
676 {
677     DEC_OPS(magPower, magFwUpload, magSetRate, magFlush, magSelfTest, NULL, magCfgData),
678 };
679 
enableInterrupt(struct Gpio * pin,struct ChainedIsr * isr)680 static void enableInterrupt(struct Gpio *pin, struct ChainedIsr *isr)
681 {
682     gpioConfigInput(pin, GPIO_SPEED_LOW, GPIO_PULL_NONE);
683     syscfgSetExtiPort(pin);
684     extiEnableIntGpio(pin, EXTI_TRIGGER_RISING);
685     extiChainIsr(ST_MAG40_INT_IRQ, isr);
686 }
687 
disableInterrupt(struct Gpio * pin,struct ChainedIsr * isr)688 static void disableInterrupt(struct Gpio *pin, struct ChainedIsr *isr)
689 {
690     extiUnchainIsr(ST_MAG40_INT_IRQ, isr);
691     extiDisableIntGpio(pin);
692 }
693 
st_mag40_int1_isr(struct ChainedIsr * isr)694 static bool st_mag40_int1_isr(struct ChainedIsr *isr)
695 {
696     if (!extiIsPendingGpio(mTask.Int1))
697         return false;
698 
699     /* Start sampling for a value */
700     if (!osEnqueuePrivateEvt(EVT_SENSOR_INTERRUPT, NULL, NULL, mTask.tid))
701         ERROR_PRINT("st_mag40_int1_isr: osEnqueuePrivateEvt() failed\n");
702 
703     extiClearPendingGpio(mTask.Int1);
704     return true;
705 }
706 
707 #define TIME_NS_TO_US(ns)    cpuMathU64DivByU16(ns, 1000)
708 #define kScale_mag      0.15f /* in uT - (1.5f / 10) */
709 
parseRawData(uint8_t * raw)710 static void parseRawData(uint8_t *raw)
711 {
712     struct TripleAxisDataEvent *magSample;
713 
714     int32_t raw_x = (*(int16_t *)&raw[0]);
715     int32_t raw_y = (*(int16_t *)&raw[2]);
716     int32_t raw_z = (*(int16_t *)&raw[4]);
717     float x, y, z;
718     float xs, ys, zs;
719     bool newMagnCalibData;
720 #if defined(ST_MAG40_CAL_ENABLED)
721     float xi, yi, zi;
722 #endif
723 
724     mTask.timestampInt = sensorGetTime();
725 
726     /* Discard samples generated during sensor turn-on time */
727     if (mTask.samplesToDiscard > 0) {
728         mTask.samplesToDiscard--;
729         return;
730     }
731 
732     /* in uT */
733     xs = (float)raw_x * kScale_mag;
734     ys = (float)raw_y * kScale_mag;
735     zs = (float)raw_z * kScale_mag;
736 
737     /* rotate axes */
738     x = ST_MAG40_REMAP_X_DATA(xs, ys, zs, ST_MAG40_ROT_MATRIX);
739     y = ST_MAG40_REMAP_Y_DATA(xs, ys, zs, ST_MAG40_ROT_MATRIX);
740     z = ST_MAG40_REMAP_Z_DATA(xs, ys, zs, ST_MAG40_ROT_MATRIX);
741 
742 #if defined(ST_MAG40_CAL_ENABLED)
743     magCalRemoveSoftiron(&mTask.moc, x, y, z, &xi, &yi, &zi);
744 
745     newMagnCalibData = magCalUpdate(&mTask.moc, TIME_NS_TO_US(mTask.timestampInt), xi, yi, zi);
746 
747     magCalRemoveBias(&mTask.moc, xi, yi, zi, &x, &y, &z);
748 #endif
749 
750     if (magAllocateEvt(&magSample) == false)
751         return;
752 
753     magSample->referenceTime = mTask.timestampInt;
754     magSample->samples[0].deltaTime = 0;
755     magSample->samples[0].firstSample.numSamples = 1;
756     magSample->samples[0].x = x;
757     magSample->samples[0].y = y;
758     magSample->samples[0].z = z;
759 
760 #if defined(ST_MAG40_CAL_ENABLED)
761     if (newMagnCalibData) {
762         magSample->samples[1].deltaTime = 0;
763         magCalGetBias(&mTask.moc,
764                      &magSample->samples[1].x,
765                      &magSample->samples[1].y,
766                      &magSample->samples[1].z);
767 
768         magSample->referenceTime = mTask.timestampInt;
769         magSample->samples[0].firstSample.numSamples = 2;
770         magSample->samples[0].firstSample.biasCurrent = true;
771         magSample->samples[0].firstSample.biasPresent = 1;
772         magSample->samples[0].firstSample.biasSample = 1;
773     }
774 #endif
775 
776     osEnqueueEvtOrFree(sensorGetMyEventType(SENS_TYPE_MAG), magSample, magFreeEvt);
777 }
778 
779 static uint8_t *wai;
780 
int2Evt(void)781 static void int2Evt(void)
782 {
783     if (trySwitchState(SENSOR_READ_SAMPLES)) {
784         mTask.comm_rx(ST_MAG40_OUTXL_REG_ADDR, 6, 0, true);
785     } else {
786         mTask.pendingInt = true;
787     }
788 }
789 
processPendingEvt(void)790 static void processPendingEvt(void)
791 {
792     if (mTask.pendingInt) {
793         mTask.pendingInt = false;
794         int2Evt();
795         return;
796     }
797 
798     if (mTask.pendingSubState != NO_SUBSTATE) {
799         if (trySwitchState(SENSOR_MAG_CONFIGURATION)) {
800             mTask.subState = mTask.pendingSubState;
801             mTask.pendingSubState = NO_SUBSTATE;
802             sensorMagConfig();
803         }
804     }
805 }
806 
sensorMagConfig(void)807 static void sensorMagConfig(void)
808 {
809     uint8_t tmp;
810 
811     switch (mTask.subState) {
812     case CONFIG_POWER_UP:
813         mTask.subState = CONFIG_POWER_UP_2;
814         mTask.comm_tx(ST_MAG40_CFG_B_REG_ADDR, ST_MAG40_OFF_CANC, 0, false);
815         mTask.comm_tx(ST_MAG40_CFG_A_REG_ADDR,
816                       ST_MAG40_TEMP_COMP_EN | ST_MAG40_POWER_ON | mTask.currentODR, 0, true);
817         break;
818 
819     case CONFIG_POWER_UP_2:
820         mTask.subState = CONFIG_DONE;
821         mTask.magOn = true;
822         sensorSignalInternalEvt(mTask.magHandle,
823             SENSOR_INTERNAL_EVT_POWER_STATE_CHG, true, 0);
824         break;
825 
826     case CONFIG_POWER_DOWN:
827         mTask.subState = CONFIG_POWER_DOWN_2;
828         mTask.comm_tx(ST_MAG40_CFG_A_REG_ADDR,
829                       ST_MAG40_TEMP_COMP_EN | ST_MAG40_POWER_IDLE | mTask.currentODR, 0, true);
830         break;
831 
832     case CONFIG_POWER_DOWN_2:
833         mTask.subState = CONFIG_DONE;
834         mTask.magOn = false;
835         sensorSignalInternalEvt(mTask.magHandle,
836             SENSOR_INTERNAL_EVT_POWER_STATE_CHG, false, 0);
837         break;
838 
839     case CONFIG_SET_RATE:
840         mTask.subState = CONFIG_SET_RATE_2;
841         tmp = mTask.magOn ? ST_MAG40_POWER_ON : ST_MAG40_POWER_IDLE;
842         tmp |= mTask.currentODR;
843         mTask.comm_tx(ST_MAG40_CFG_A_REG_ADDR, ST_MAG40_TEMP_COMP_EN | tmp, 0, true);
844         break;
845 
846     case CONFIG_SET_RATE_2:
847         mTask.subState = CONFIG_DONE;
848         sensorSignalInternalEvt(mTask.magHandle,
849                 SENSOR_INTERNAL_EVT_RATE_CHG, mTask.rate, mTask.latency);
850         break;
851 
852     default:
853         /* Something weird happened */
854         ERROR_PRINT("sensorMagConfig() subState=%d\n", mTask.subState);
855         mTask.subState = CONFIG_DONE;
856         break;
857     }
858 }
859 
860 /* initial sensor configuration */
sensorInit(void)861 static void sensorInit(void)
862 {
863     switch (mTask.subState) {
864     case INIT_START:
865         mTask.subState = INIT_ENABLE_DRDY;
866         mTask.comm_tx(ST_MAG40_CFG_A_REG_ADDR,
867                     ST_MAG40_SOFT_RESET_BIT, 0, true);
868         break;
869 
870     case INIT_ENABLE_DRDY:
871         mTask.subState = INIT_DONE;
872         mTask.comm_rx(ST_MAG40_OUTXL_REG_ADDR, 6, 0, false);
873         mTask.comm_tx(ST_MAG40_CFG_C_REG_ADDR,
874                     ST_MAG40_BDU_ON | ST_MAG40_INT_MAG, 0, true);
875         break;
876 
877     default:
878         /* Something weird happened */
879         ERROR_PRINT("sensorInit() subState=%d\n", mTask.subState);
880         mTask.subState = INIT_DONE;
881         break;
882     }
883 }
884 
handleCommDoneEvt(const void * evtData)885 static void handleCommDoneEvt(const void* evtData)
886 {
887     bool returnIdle = false;
888     struct I2cTransfer *xfer = (struct I2cTransfer *)evtData;
889 
890     switch (GET_STATE()) {
891     case SENSOR_BOOT:
892         SET_STATE(SENSOR_VERIFY_ID);
893 
894         mTask.comm_rx(ST_MAG40_WAI_REG_ADDR, 1, 0, true);
895         break;
896 
897     case SENSOR_VERIFY_ID:
898         /* Check the sensor ID */
899         wai = &xfer->txrxBuf[0];
900 
901         if (ST_MAG40_WAI_REG_VAL != wai[0]) {
902             DEBUG_PRINT("WAI returned is: %02x\n\n", *wai);
903             SET_STATE(SENSOR_BOOT);
904             mTask.comm_tx(ST_MAG40_CFG_A_REG_ADDR,
905                         ST_MAG40_SOFT_RESET_BIT, 0, true);
906             break;
907         }
908 
909         INFO_PRINT( "Device ID is correct! (%02x)\n", *wai);
910         SET_STATE(SENSOR_INITIALIZATION);
911         mTask.subState = INIT_START;
912         sensorInit();
913 
914         break;
915 
916     case SENSOR_INITIALIZATION:
917         if (mTask.subState == INIT_DONE) {
918             INFO_PRINT( "Initialization completed\n");
919             returnIdle = true;
920             sensorRegisterInitComplete(mTask.magHandle);
921         } else {
922             sensorInit();
923         }
924 
925         break;
926 
927     case SENSOR_MAG_CONFIGURATION:
928         if (mTask.subState != CONFIG_DONE)
929             sensorMagConfig();
930         if (mTask.subState == CONFIG_DONE)
931             returnIdle = true;
932         break;
933 
934     case SENSOR_READ_SAMPLES:
935         returnIdle = true;
936 
937         if (gpioGet(mTask.Int1)) {
938             ERROR_PRINT("error read sensor, retry!\n");
939         }
940         if (mTask.magOn)
941             parseRawData(&xfer->txrxBuf[0]);
942         break;
943 
944     case SENSOR_SELF_TEST:
945         if (mTask.mag_test_state == MAG_SELFTEST_DONE)
946             returnIdle = true;
947         else
948             magTestHandling(xfer);
949 
950         break;
951 
952     case SENSOR_IDLE:
953     default:
954         break;
955     }
956 
957     releaseXfer(xfer);
958 
959     if (returnIdle) {
960         SET_STATE(SENSOR_IDLE);
961         processPendingEvt();
962     }
963 }
964 
handleEvent(uint32_t evtType,const void * evtData)965 static void handleEvent(uint32_t evtType, const void* evtData)
966 {
967     switch (evtType) {
968     case EVT_APP_START:
969         INFO_PRINT("EVT_APP_START\n");
970         osEventUnsubscribe(mTask.tid, EVT_APP_START);
971 
972         SET_STATE(SENSOR_BOOT);
973         mTask.comm_tx(ST_MAG40_CFG_A_REG_ADDR,
974                         ST_MAG40_SOFT_RESET_BIT, 0, true);
975 
976         break;
977 
978     case EVT_COMM_DONE:
979         handleCommDoneEvt(evtData);
980         break;
981 
982     case EVT_SENSOR_INTERRUPT:
983         int2Evt();
984         break;
985 
986     default:
987         break;
988     }
989 
990 }
991 
startTask(uint32_t task_id)992 static bool startTask(uint32_t task_id)
993 {
994     size_t slabSize;
995 
996     mTask.tid = task_id;
997 
998     INFO_PRINT("I2C DRIVER started\n");
999 
1000     mTask.magOn = false;
1001     mTask.pendingInt = false;
1002     mTask.pendingSubState = NO_SUBSTATE;
1003 
1004     mTask.currentODR = ST_MAG40_ODR_10_HZ;
1005     mTask.timestampInt = 0;
1006 
1007     slabSize = sizeof(struct TripleAxisDataEvent) + sizeof(struct TripleAxisDataPoint);
1008 #if defined(ST_MAG40_CAL_ENABLED)
1009     slabSize += sizeof(struct TripleAxisDataPoint);
1010 #endif
1011 
1012     mTask.magDataSlab = slabAllocatorNew(slabSize, 4, ST_MAG40_MAX_MAG_EVENTS);
1013     if (!mTask.magDataSlab) {
1014         ERROR_PRINT("Failed to allocate magDataSlab memory\n");
1015         return false;
1016     }
1017 
1018     /* Init the communication part */
1019     i2cMasterRequest(ST_MAG40_I2C_BUS_ID, ST_MAG40_I2C_SPEED);
1020 
1021     mTask.comm_tx = i2c_write;
1022     mTask.comm_rx = i2c_read;
1023 
1024     /* irq */
1025     mTask.Int1 = gpioRequest(ST_MAG40_INT_PIN);
1026     gpioConfigInput(mTask.Int1, GPIO_SPEED_LOW, GPIO_PULL_NONE);
1027     mTask.Isr1.func = st_mag40_int1_isr;
1028     enableInterrupt(mTask.Int1, &mTask.Isr1);
1029 
1030 #if defined(ST_MAG40_CAL_ENABLED)
1031 #ifdef DIVERSITY_CHECK_ENABLED
1032     initMagCal(&mTask.moc,
1033             0.0f, 0.0f, 0.0f,      // bias x, y, z
1034             1.0f, 0.0f, 0.0f,      // c00, c01, c02
1035             0.0f, 1.0f, 0.0f,      // c10, c11, c12
1036             0.0f, 0.0f, 1.0f,      // c20, c21, c22
1037             3000000,               // min_batch_window_in_micros
1038             8,                     // min_num_diverse_vectors
1039             1,                     // max_num_max_distance
1040             6.0f,                  // var_threshold
1041             10.0f,                 // max_min_threshold
1042             48.f,                  // local_field
1043             0.5f,                  // threshold_tuning_param
1044             2.552f);               // max_distance_tuning_param
1045 #else
1046     initMagCal(&mTask.moc,
1047             0.0f, 0.0f, 0.0f,      // bias x, y, z
1048             1.0f, 0.0f, 0.0f,      // c00, c01, c02
1049             0.0f, 1.0f, 0.0f,      // c10, c11, c12
1050             0.0f, 0.0f, 1.0f,      // c20, c21, c22
1051             3000000);              // min_batch_window_in_micros
1052 #endif /* DIVERSITY_CHECK_ENABLED */
1053 #endif /* ST_MAG40_CAL_ENABLED */
1054 
1055     mTask.magHandle =
1056             sensorRegister(&st_mag40_SensorInfo, &st_mag40_SensorOps, NULL, false);
1057 
1058     osEventSubscribe(mTask.tid, EVT_APP_START);
1059 
1060     return true;
1061 }
1062 
endTask(void)1063 static void endTask(void)
1064 {
1065     INFO_PRINT("ended\n");
1066 #if defined(ST_MAG40_CAL_ENABLED)
1067     magCalDestroy(&mTask.moc);
1068 #endif /* ST_MAG40_CAL_ENABLED */
1069     slabAllocatorDestroy(mTask.magDataSlab);
1070     disableInterrupt(mTask.Int1, &mTask.Isr1);
1071 }
1072 
1073 INTERNAL_APP_INIT(ST_MAG40_APP_ID, 0, startTask, endTask, handleEvent);
1074