Home | History | Annotate | Download | only in linux
      1 /**
      2  *   @defgroup  HAL_Outputs
      3  *   @brief     Motion Library - HAL Outputs
      4  *              Sets up common outputs for HAL
      5  *
      6  *   @{
      7  *       @file  datalogger_outputs.c
      8  *       @brief Windows 8 HAL outputs.
      9  */
     10 
     11 #include <string.h>
     12 
     13 #include "datalogger_outputs.h"
     14 #include "ml_math_func.h"
     15 #include "mlmath.h"
     16 #include "start_manager.h"
     17 #include "data_builder.h"
     18 #include "results_holder.h"
     19 
     20 /*
     21     Defines
     22 */
     23 #define ACCEL_CONVERSION (0.000149637603759766f)
     24 
     25 /*
     26     Types
     27 */
     28 struct datalogger_output_s {
     29     int quat_accuracy;
     30     inv_time_t quat_timestamp;
     31     long quat[4];
     32     struct inv_sensor_cal_t sc;
     33 };
     34 
     35 /*
     36     Globals and Statics
     37 */
     38 static struct datalogger_output_s dl_out;
     39 
     40 /*
     41     Functions
     42 */
     43 
     44 /**
     45  *  Raw (uncompensated) angular velocity (LSB) in chip frame.
     46  *  @param[out] values      raw angular velocity in LSB.
     47  *  @param[out] timestamp   Time when sensor was sampled.
     48  */
     49 void inv_get_sensor_type_gyro_raw_short(short *values, inv_time_t *timestamp)
     50 {
     51     struct inv_single_sensor_t *pg = &dl_out.sc.gyro;
     52 
     53     if (values)
     54         memcpy(values, &pg->raw, sizeof(short) * 3);
     55     if (timestamp)
     56         *timestamp = pg->timestamp;
     57 }
     58 
     59 /**
     60  *  Raw (uncompensated) angular velocity (degrees per second) in body frame.
     61  *  @param[out] values      raw angular velocity in dps.
     62  *  @param[out] timestamp   Time when sensor was sampled.
     63  */
     64 void inv_get_sensor_type_gyro_raw_body_float(float *values,
     65         inv_time_t *timestamp)
     66 {
     67     struct inv_single_sensor_t *pg = &dl_out.sc.gyro;
     68     long raw[3];
     69     long raw_body[3];
     70 
     71     raw[0] = (long) pg->raw[0] * (1L << 16);
     72     raw[1] = (long) pg->raw[1] * (1L << 16);
     73     raw[2] = (long) pg->raw[2] * (1L << 16);
     74     inv_convert_to_body_with_scale(pg->orientation, pg->sensitivity,
     75                                    raw, raw_body);
     76     if (values) {
     77         values[0] = inv_q16_to_float(raw_body[0]);
     78         values[1] = inv_q16_to_float(raw_body[1]);
     79         values[2] = inv_q16_to_float(raw_body[2]);
     80     }
     81     if (timestamp)
     82         *timestamp = pg->timestamp;
     83 }
     84 
     85 /**
     86  *  Angular velocity (degrees per second) in body frame.
     87  *  @param[out] values      Angular velocity in dps.
     88  *  @param[out] accuracy    0 (uncalibrated) to 3 (most accurate).
     89  *  @param[out] timestamp   Time when sensor was sampled.
     90  */
     91 void inv_get_sensor_type_gyro_float(float *values, int8_t *accuracy,
     92         inv_time_t *timestamp)
     93 {
     94     long gyro[3];
     95     inv_get_gyro_set(gyro, accuracy, timestamp);
     96 
     97     values[0] = (float)gyro[0] / 65536.f;
     98     values[1] = (float)gyro[1] / 65536.f;
     99     values[2] = (float)gyro[2] / 65536.f;
    100 }
    101 
    102 /**
    103  *  Raw (uncompensated) acceleration (LSB) in chip frame.
    104  *  @param[out] values      raw acceleration in LSB.
    105  *  @param[out] timestamp   Time when sensor was sampled.
    106  */
    107 void inv_get_sensor_type_accel_raw_short(short *values, inv_time_t *timestamp)
    108 {
    109     struct inv_single_sensor_t *pa = &dl_out.sc.accel;
    110 
    111     if (values)
    112         memcpy(values, &pa->raw, sizeof(short) * 3);
    113     if (timestamp)
    114         *timestamp = pa->timestamp;
    115 }
    116 
    117 /**
    118  *  Acceleration (g's) in body frame.
    119  *  Microsoft defines gravity as positive acceleration pointing towards the
    120  *  Earth.
    121  *  @param[out] values      Acceleration in g's.
    122  *  @param[out] accuracy    0 (uncalibrated) to 3 (most accurate).
    123  *  @param[out] timestamp   Time when sensor was sampled.
    124  */
    125 void inv_get_sensor_type_accel_float(float *values, int8_t *accuracy,
    126         inv_time_t *timestamp)
    127 {
    128     long accel[3];
    129     inv_get_accel_set(accel, accuracy, timestamp);
    130 
    131     values[0] = (float) -accel[0] / 65536.f;
    132     values[1] = (float) -accel[1] / 65536.f;
    133     values[2] = (float) -accel[2] / 65536.f;
    134 }
    135 
    136 /**
    137  *  Raw (uncompensated) compass magnetic field  (LSB) in chip frame.
    138  *  @param[out] values      raw magnetic field in LSB.
    139  *  @param[out] timestamp   Time when sensor was sampled.
    140  */
    141 void inv_get_sensor_type_compass_raw_short(short *values, inv_time_t *timestamp)
    142 {
    143     struct inv_single_sensor_t *pc = &dl_out.sc.compass;
    144 
    145     if (values)
    146         memcpy(values, &pc->raw, sizeof(short) * 3);
    147     if (timestamp)
    148         *timestamp = pc->timestamp;
    149 }
    150 
    151 /**
    152  *  Magnetic heading/field strength in body frame.
    153  *  TODO: No difference between mag_north and true_north yet.
    154  *  @param[out] mag_north   Heading relative to magnetic north in degrees.
    155  *  @param[out] true_north  Heading relative to true north in degrees.
    156  *  @param[out] values      Field strength in milligauss.
    157  *  @param[out] accuracy    0 (uncalibrated) to 3 (most accurate).
    158  *  @param[out] timestamp   Time when sensor was sampled.
    159  */
    160 void inv_get_sensor_type_compass_float(float *mag_north, float *true_north,
    161         float *values, int8_t *accuracy, inv_time_t *timestamp)
    162 {
    163     long compass[3];
    164     long q00, q12, q22, q03, t1, t2;
    165 
    166     /* 1 uT = 10 milligauss. */
    167 #define COMPASS_CONVERSION  (10 / 65536.f)
    168     inv_get_compass_set(compass, accuracy, timestamp);
    169     if (values) {
    170         values[0] = (float)compass[0]*COMPASS_CONVERSION;
    171         values[1] = (float)compass[1]*COMPASS_CONVERSION;
    172         values[2] = (float)compass[2]*COMPASS_CONVERSION;
    173     }
    174 
    175     /* TODO: Stolen from euler angle computation. Calculate this only once per
    176      * callback.
    177      */
    178     q00 = inv_q29_mult(dl_out.quat[0], dl_out.quat[0]);
    179     q12 = inv_q29_mult(dl_out.quat[1], dl_out.quat[2]);
    180     q22 = inv_q29_mult(dl_out.quat[2], dl_out.quat[2]);
    181     q03 = inv_q29_mult(dl_out.quat[0], dl_out.quat[3]);
    182     t1 = q12 - q03;
    183     t2 = q22 + q00 - (1L << 30);
    184     if (mag_north) {
    185         *mag_north = atan2f((float) t1, (float) t2) * 180.f / (float) M_PI;
    186         if (*mag_north < 0)
    187             *mag_north += 360;
    188     }
    189     if (true_north) {
    190         if (!mag_north) {
    191             *true_north = atan2f((float) t1, (float) t2) * 180.f / (float) M_PI;
    192             if (*true_north < 0)
    193                 *true_north += 360;
    194         } else {
    195             *true_north = *mag_north;
    196         }
    197     }
    198 }
    199 
    200 #if 0
    201 // put it back when we handle raw temperature
    202 /**
    203  *  Raw temperature (LSB).
    204  *  @param[out] value       raw temperature in LSB (1 element).
    205  *  @param[out] timestamp   Time when sensor was sampled.
    206  */
    207 void inv_get_sensor_type_temp_raw_short(short *value, inv_time_t *timestamp)
    208 {
    209     struct inv_single_sensor_t *pt = &dl_out.sc.temp;
    210     if (value) {
    211         /* no raw temperature, temperature is only handled calibrated
    212         *value = pt->raw[0];
    213         */
    214         *value = pt->calibrated[0];
    215     }
    216     if (timestamp)
    217         *timestamp = pt->timestamp;
    218 }
    219 #endif
    220 
    221 /**
    222  *  Temperature (degree C).
    223  *  @param[out] values      Temperature in degrees C.
    224  *  @param[out] timestamp   Time when sensor was sampled.
    225  */
    226 void inv_get_sensor_type_temperature_float(float *value, inv_time_t *timestamp)
    227 {
    228     struct inv_single_sensor_t *pt = &dl_out.sc.temp;
    229     long ltemp;
    230     if (timestamp)
    231         *timestamp = pt->timestamp;
    232     if (value) {
    233         /* no raw temperature, temperature is only handled calibrated
    234         ltemp = pt->raw[0];
    235         */
    236         ltemp = pt->calibrated[0];
    237         *value = (float) ltemp / (1L << 16);
    238     }
    239 }
    240 
    241 /**
    242  *  Quaternion in body frame.
    243  *  @e inv_get_sensor_type_quaternion_float outputs the data in the following
    244  *  order: X, Y, Z, W.
    245  *  TODO: Windows expects a discontinuity at 180 degree rotations. Will our
    246  *  convention be ok?
    247  *  @param[out] values      Quaternion normalized to one.
    248  *  @param[out] accuracy    0 (uncalibrated) to 3 (most accurate).
    249  *  @param[out] timestamp   Time when sensor was sampled.
    250  */
    251 void inv_get_sensor_type_quat_float(float *values, int *accuracy,
    252                                     inv_time_t *timestamp)
    253 {
    254     values[0] = dl_out.quat[0] / 1073741824.f;
    255     values[1] = dl_out.quat[1] / 1073741824.f;
    256     values[2] = dl_out.quat[2] / 1073741824.f;
    257     values[3] = dl_out.quat[3] / 1073741824.f;
    258     accuracy[0] = dl_out.quat_accuracy;
    259     timestamp[0] = dl_out.quat_timestamp;
    260 }
    261 
    262 /** Gravity vector (gee) in body frame.
    263 * @param[out] values Gravity vector in body frame, length 3, (gee)
    264 * @param[out] accuracy Accuracy of the measurment, 0 is least accurate,
    265                        while 3 is most accurate.
    266 * @param[out] timestamp The timestamp for this sensor. Derived from the
    267                         timestamp sent to inv_build_accel().
    268 */
    269 void inv_get_sensor_type_gravity_float(float *values, int *accuracy,
    270                                        inv_time_t * timestamp)
    271 {
    272     struct inv_single_sensor_t *pa = &dl_out.sc.accel;
    273 
    274     if (values) {
    275         long lgravity[3];
    276         (void)inv_get_gravity(lgravity);
    277         values[0] = (float) lgravity[0] / (1L << 16);
    278         values[1] = (float) lgravity[1] / (1L << 16);
    279         values[2] = (float) lgravity[2] / (1L << 16);
    280     }
    281     if (accuracy)
    282         *accuracy = pa->accuracy;
    283     if (timestamp)
    284         *timestamp = pa->timestamp;
    285 }
    286 
    287 /**
    288 * This corresponds to Sensor.TYPE_ROTATION_VECTOR.
    289 * The rotation vector represents the orientation of the device as a combination
    290 * of an angle and an axis, in which the device has rotated through an angle @f$\theta@f$
    291 * around an axis {x, y, z}. <br>
    292 * The three elements of the rotation vector are
    293 * {x*sin(@f$\theta@f$/2), y*sin(@f$\theta@f$/2), z*sin(@f$\theta@f$/2)}, such that the magnitude of the rotation
    294 * vector is equal to sin(@f$\theta@f$/2), and the direction of the rotation vector is
    295 * equal to the direction of the axis of rotation.
    296 *
    297 * The three elements of the rotation vector are equal to the last three components of a unit quaternion
    298 * {x*sin(@f$\theta@f$/2), y*sin(@f$\theta@f$/2), z*sin(@f$\theta@f$/2)>.
    299 *
    300 * Elements of the rotation vector are unitless. The x,y and z axis are defined in the same way as the acceleration sensor.
    301 * The reference coordinate system is defined as a direct orthonormal basis, where:
    302 
    303     -X is defined as the vector product Y.Z (It is tangential to the ground at the device's current location and roughly points East).
    304     -Y is tangential to the ground at the device's current location and points towards the magnetic North Pole.
    305     -Z points towards the sky and is perpendicular to the ground.
    306 * @param[out] values
    307 * @param[out] accuracy Accuracy 0 to 3, 3 = most accurate
    308 * @param[out] timestamp Timestamp. In (ns) for Android.
    309 */
    310 void inv_get_sensor_type_rotation_vector_float(float *values, int *accuracy,
    311         inv_time_t * timestamp)
    312 {
    313     if (accuracy)
    314         *accuracy = dl_out.quat_accuracy;
    315     if (timestamp)
    316         *timestamp = dl_out.quat_timestamp;
    317     if (values) {
    318         if (dl_out.quat[0] >= 0) {
    319             values[0] = dl_out.quat[1] * INV_TWO_POWER_NEG_30;
    320             values[1] = dl_out.quat[2] * INV_TWO_POWER_NEG_30;
    321             values[2] = dl_out.quat[3] * INV_TWO_POWER_NEG_30;
    322         } else {
    323             values[0] = -dl_out.quat[1] * INV_TWO_POWER_NEG_30;
    324             values[1] = -dl_out.quat[2] * INV_TWO_POWER_NEG_30;
    325             values[2] = -dl_out.quat[3] * INV_TWO_POWER_NEG_30;
    326         }
    327     }
    328 }
    329 
    330 /** Main callback to generate HAL outputs. Typically not called by library users. */
    331 inv_error_t inv_generate_datalogger_outputs(struct inv_sensor_cal_t *sensor_cal)
    332 {
    333     memcpy(&dl_out.sc, sensor_cal, sizeof(struct inv_sensor_cal_t));
    334     inv_get_quaternion_set(dl_out.quat, &dl_out.quat_accuracy,
    335                            &dl_out.quat_timestamp);
    336     return INV_SUCCESS;
    337 }
    338 
    339 /** Turns off generation of HAL outputs. */
    340 inv_error_t inv_stop_datalogger_outputs(void)
    341 {
    342     return inv_unregister_data_cb(inv_generate_datalogger_outputs);
    343 }
    344 
    345 /** Turns on generation of HAL outputs. This should be called after inv_stop_dl_outputs()
    346 * to turn generation of HAL outputs back on. It is automatically called by inv_enable_dl_outputs().*/
    347 inv_error_t inv_start_datalogger_outputs(void)
    348 {
    349     return inv_register_data_cb(inv_generate_datalogger_outputs,
    350         INV_PRIORITY_HAL_OUTPUTS, INV_GYRO_NEW | INV_ACCEL_NEW | INV_MAG_NEW);
    351 }
    352 
    353 /** Initializes hal outputs class. This is called automatically by the
    354 * enable function. It may be called any time the feature is enabled, but
    355 * is typically not needed to be called by outside callers.
    356 */
    357 inv_error_t inv_init_datalogger_outputs(void)
    358 {
    359     memset(&dl_out, 0, sizeof(dl_out));
    360     return INV_SUCCESS;
    361 }
    362 
    363 /** Turns on creation and storage of HAL type results.
    364 */
    365 inv_error_t inv_enable_datalogger_outputs(void)
    366 {
    367     inv_error_t result;
    368     result = inv_init_datalogger_outputs();
    369     if (result)
    370         return result;
    371     return inv_register_mpl_start_notification(inv_start_datalogger_outputs);
    372 }
    373 
    374 /** Turns off creation and storage of HAL type results.
    375 */
    376 inv_error_t inv_disable_datalogger_outputs(void)
    377 {
    378     inv_stop_datalogger_outputs();
    379     return inv_unregister_mpl_start_notification(inv_start_datalogger_outputs);
    380 }
    381 
    382 /**
    383  * @}
    384  */
    385