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