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 <string.h>
18 #include "bosch_bmm150_slave.h"
19 
bmm150SaveDigData(struct MagTask * magTask,uint8_t * data,size_t offset)20 void bmm150SaveDigData(struct MagTask *magTask, uint8_t *data, size_t offset)
21 {
22     // magnetometer temperature calibration data is read in 3 bursts of 8 byte
23     // length each.
24     memcpy(&magTask->raw_dig_data[offset], data, 8);
25 
26     if (offset == 16) {
27         // we have all the raw data.
28 
29         static const size_t first_reg = BMM150_REG_DIG_X1;
30         magTask->dig_x1 = magTask->raw_dig_data[BMM150_REG_DIG_X1 - first_reg];
31         magTask->dig_y1 = magTask->raw_dig_data[BMM150_REG_DIG_Y1 - first_reg];
32         magTask->dig_x2 = magTask->raw_dig_data[BMM150_REG_DIG_X2 - first_reg];
33         magTask->dig_y2 = magTask->raw_dig_data[BMM150_REG_DIG_Y2 - first_reg];
34         magTask->dig_xy2 = magTask->raw_dig_data[BMM150_REG_DIG_XY2 - first_reg];
35         magTask->dig_xy1 = magTask->raw_dig_data[BMM150_REG_DIG_XY1 - first_reg];
36 
37         magTask->dig_z1 = *(uint16_t *)(&magTask->raw_dig_data[BMM150_REG_DIG_Z1_LSB - first_reg]);
38         magTask->dig_z2 = *(int16_t *)(&magTask->raw_dig_data[BMM150_REG_DIG_Z2_LSB - first_reg]);
39         magTask->dig_z3 = *(int16_t *)(&magTask->raw_dig_data[BMM150_REG_DIG_Z3_LSB - first_reg]);
40         magTask->dig_z4 = *(int16_t *)(&magTask->raw_dig_data[BMM150_REG_DIG_Z4_LSB - first_reg]);
41 
42         magTask->dig_xyz1 = *(uint16_t *)(&magTask->raw_dig_data[BMM150_REG_DIG_XYZ1_LSB - first_reg]);
43     }
44 }
45 
bmm150TempCompensateX(struct MagTask * magTask,int16_t mag_x,uint16_t rhall)46 static int32_t bmm150TempCompensateX(struct MagTask *magTask, int16_t mag_x, uint16_t rhall)
47 {
48     int32_t inter_retval = 0;
49 
50     // some temp var to made the long calculation easier to read
51     int32_t temp_1, temp_2, temp_3, temp_4;
52 
53     // no overflow
54     if (mag_x != BMM150_MAG_FLIP_OVERFLOW_ADCVAL) {
55         if ((rhall != 0) && (magTask->dig_xyz1 != 0)) {
56 
57             inter_retval = ((int32_t)(((uint16_t) ((((int32_t)magTask->dig_xyz1) << 14)
58                 / (rhall != 0 ?  rhall : magTask->dig_xyz1))) - ((uint16_t)0x4000)));
59 
60         } else {
61             inter_retval = BMM150_MAG_OVERFLOW_OUTPUT;
62             return inter_retval;
63         }
64 
65         temp_1 = ((int32_t)magTask->dig_xy2) * ((((int32_t)inter_retval) * ((int32_t)inter_retval)) >> 7);
66         temp_2 = ((int32_t)inter_retval) * ((int32_t)(((int16_t)magTask->dig_xy1) << 7));
67         temp_3 = ((temp_1 + temp_2) >> 9) + ((int32_t)BMM150_CALIB_HEX_LACKS);
68         temp_4 = ((int32_t)mag_x) * ((temp_3 * ((int32_t)(((int16_t)magTask->dig_x2) + ((int16_t)0xa0)))) >> 12);
69 
70         inter_retval = ((int32_t)(temp_4 >> 13)) + (((int16_t)magTask->dig_x1) << 3);
71 
72         // check the overflow output
73         if (inter_retval == (int32_t)BMM150_MAG_OVERFLOW_OUTPUT)
74             inter_retval = BMM150_MAG_OVERFLOW_OUTPUT_S32;
75     } else {
76         // overflow
77         inter_retval = BMM150_MAG_OVERFLOW_OUTPUT;
78     }
79     return inter_retval;
80 }
81 
bmm150TempCompensateY(struct MagTask * magTask,int16_t mag_y,uint16_t rhall)82 static int32_t bmm150TempCompensateY(struct MagTask *magTask, int16_t mag_y, uint16_t rhall)
83 {
84     int32_t inter_retval = 0;
85 
86     // some temp var to made the long calculation easier to read
87     int32_t temp_1, temp_2, temp_3, temp_4;
88 
89     // no overflow
90     if (mag_y != BMM150_MAG_FLIP_OVERFLOW_ADCVAL) {
91         if ((rhall != 0) && (magTask->dig_xyz1 != 0)) {
92 
93             inter_retval = ((int32_t)(((uint16_t)((( (int32_t)magTask->dig_xyz1) << 14)
94                 / (rhall != 0 ?  rhall : magTask->dig_xyz1))) - ((uint16_t)0x4000)));
95 
96         } else {
97             inter_retval = BMM150_MAG_OVERFLOW_OUTPUT;
98             return inter_retval;
99         }
100 
101         temp_1 = ((int32_t)magTask->dig_xy2) * ((((int32_t) inter_retval) * ((int32_t)inter_retval)) >> 7);
102         temp_2 = ((int32_t)inter_retval) * ((int32_t)(((int16_t)magTask->dig_xy1) << 7));
103         temp_3 = ((temp_1 + temp_2) >> 9) + ((int32_t)BMM150_CALIB_HEX_LACKS);
104         temp_4 = ((int32_t)mag_y) * ((temp_3 * ((int32_t)(((int16_t)magTask->dig_y2) + ((int16_t)0xa0)))) >> 12);
105 
106         inter_retval = ((int32_t)(temp_4 >> 13)) + (((int16_t)magTask->dig_y1) << 3);
107 
108         // check the overflow output
109         if (inter_retval == (int32_t)BMM150_MAG_OVERFLOW_OUTPUT)
110             inter_retval = BMM150_MAG_OVERFLOW_OUTPUT_S32;
111     } else {
112         // overflow
113         inter_retval = BMM150_MAG_OVERFLOW_OUTPUT;
114     }
115     return inter_retval;
116 }
117 
bmm150TempCompensateZ(struct MagTask * magTask,int16_t mag_z,uint16_t rhall)118 static int32_t bmm150TempCompensateZ(struct MagTask *magTask, int16_t mag_z, uint16_t rhall)
119 {
120     int32_t retval = 0;
121     if (mag_z != BMM150_MAG_HALL_OVERFLOW_ADCVAL) {
122         if ((rhall != 0) && (magTask->dig_z2 != 0) && (magTask->dig_z1 != 0)) {
123 
124             retval = ((((int32_t)(mag_z - magTask->dig_z4)) << 15)
125                     - ((((int32_t)magTask->dig_z3) * ((int32_t)(((int16_t)rhall) - ((int16_t)magTask->dig_xyz1)))) >> 2));
126 
127             retval /= (magTask->dig_z2
128                     + ((int16_t)(((((int32_t)magTask->dig_z1) * ((((int16_t)rhall) << 1))) + (1 << 15)) >> 16)));
129         }
130     } else {
131         retval = BMM150_MAG_OVERFLOW_OUTPUT;
132     }
133     return retval;
134 }
135 
parseMagData(struct MagTask * magTask,uint8_t * buf,float * x,float * y,float * z)136 void parseMagData(struct MagTask *magTask, uint8_t *buf, float *x, float *y, float *z) {
137     int32_t mag_x = (*(int16_t *)&buf[0]) >> 3;
138     int32_t mag_y = (*(int16_t *)&buf[2]) >> 3;
139     int32_t mag_z = (*(int16_t *)&buf[4]) >> 1;
140     uint32_t mag_rhall = (*(uint16_t *)&buf[6]) >> 2;
141 
142     int32_t raw_x = bmm150TempCompensateX(magTask, mag_x, mag_rhall);
143     int32_t raw_y = bmm150TempCompensateY(magTask, mag_y, mag_rhall);
144     int32_t raw_z = bmm150TempCompensateZ(magTask, mag_z, mag_rhall);
145 
146     *x = (float)raw_x * kScale_mag;
147     *y = (float)raw_y * kScale_mag;
148     *z = (float)raw_z * kScale_mag;
149 }
150