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