Home | History | Annotate | Download | only in st_mag40
      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
    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.
    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 
    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 
    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.
    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 
    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 */
    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 
    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 
    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 
    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 
    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 */
    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 
    474 static bool magFwUpload(void *cookie)
    475 {
    476     return sensorSignalInternalEvt(mTask.magHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
    477 }
    478 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    688 static void disableInterrupt(struct Gpio *pin, struct ChainedIsr *isr)
    689 {
    690     extiUnchainIsr(ST_MAG40_INT_IRQ, isr);
    691     extiDisableIntGpio(pin);
    692 }
    693 
    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 
    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 
    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 
    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 
    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 */
    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 
    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 
    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 
    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 
   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