altoslib: Compute orientation from eeprom data files
[fw/altos] / altoslib / AltosCalData.java
1 /*
2  * Copyright © 2017 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 package org.altusmetrum.altoslib_11;
16
17 /*
18  * Calibration and other data needed to construct 'real' values from various data
19  * sources.
20  */
21
22 public class AltosCalData {
23         public int              flight = AltosLib.MISSING;
24
25         public void set_flight(int flight) {
26                 if (flight != AltosLib.MISSING)
27                         this.flight = flight;
28         }
29
30         public String           callsign = null;
31
32         public void set_callsign(String callsign) {
33                 if (callsign != null)
34                         this.callsign = callsign;
35         }
36
37         public String           firmware_version = null;
38
39         public void set_firmware_version(String firmware_version) {
40                 if (firmware_version != null)
41                         this.firmware_version = firmware_version;
42         }
43
44         public String           product = null;
45
46         public void set_product(String product) {
47                 if (product != null)
48                         this.product = product;
49         }
50
51         public int              serial = AltosLib.MISSING;
52
53         public void set_serial(int serial) {
54                 if (serial != AltosLib.MISSING)
55                         this.serial = serial;
56         }
57
58         public int              receiver_serial = AltosLib.MISSING;
59
60         public void set_receiver_serial(int receiver_serial) {
61                 if (receiver_serial != AltosLib.MISSING)
62                         this.receiver_serial = receiver_serial;
63         }
64
65         public int              device_type = AltosLib.MISSING;
66
67         public void set_device_type(int device_type) {
68                 if (device_type != AltosLib.MISSING) {
69                         this.device_type = device_type;
70                         if (product == null)
71                                 set_product(AltosLib.product_name(device_type));
72                 }
73         }
74
75         public int              config_major = AltosLib.MISSING;
76         public int              config_minor = AltosLib.MISSING;
77         public int              flight_log_max = AltosLib.MISSING;
78
79         public void set_config(int major, int minor, int log_max) {
80                 if (major != AltosLib.MISSING)
81                         config_major = major;
82                 if (minor != AltosLib.MISSING)
83                         config_minor = minor;
84                 if (log_max != AltosLib.MISSING)
85                         flight_log_max = log_max;
86         }
87
88         public double           apogee_delay = AltosLib.MISSING;
89         public double           main_deploy = AltosLib.MISSING;
90
91         public void set_flight_params(double apogee_delay, double main_deploy) {
92                 if (apogee_delay != AltosLib.MISSING)
93                         this.apogee_delay = apogee_delay;
94                 if (main_deploy != AltosLib.MISSING)
95                         this.main_deploy = main_deploy;
96         }
97
98         public double           accel_plus_g = AltosLib.MISSING;
99         public double           accel_minus_g = AltosLib.MISSING;
100         public double           ground_accel = AltosLib.MISSING;
101
102         public void set_accel_plus_minus(double plus, double minus) {
103                 if (plus != AltosLib.MISSING && minus != AltosLib.MISSING) {
104                         if (plus == minus)
105                                 return;
106                         accel_plus_g = plus;
107                         accel_minus_g = minus;
108                 }
109         }
110
111         public void set_ground_accel(double ground_accel) {
112                 if (ground_accel != AltosLib.MISSING)
113                         this.ground_accel = ground_accel;
114         }
115
116         /* Raw acceleration value */
117         public double           accel = AltosLib.MISSING;
118
119         public void set_accel(double accel) {
120                 this.accel = accel;
121         }
122
123         public boolean mma655x_inverted = false;
124
125         public void set_mma655x_inverted(boolean inverted) {
126                 mma655x_inverted = inverted;
127         }
128
129         public int pad_orientation = AltosLib.MISSING;
130
131         public void set_pad_orientation(int orientation) {
132                 if (orientation != AltosLib.MISSING)
133                         pad_orientation = orientation;
134         }
135
136         /* Compute acceleration */
137         public double acceleration(double sensor) {
138                 return AltosConvert.acceleration_from_sensor(sensor, accel_plus_g, accel_minus_g, ground_accel);
139         }
140
141         public AltosMs5607      ms5607 = null;
142
143         public void set_ms5607(AltosMs5607 ms5607) {
144                 this.ms5607 = ms5607;
145         }
146
147         public double           ground_pressure = AltosLib.MISSING;
148         public double           ground_altitude = AltosLib.MISSING;
149
150         public void set_ground_pressure(double ground_pressure) {
151                 if (ground_pressure != AltosLib.MISSING) {
152                         this.ground_pressure = ground_pressure;
153                         this.ground_altitude = AltosConvert.pressure_to_altitude(ground_pressure);
154                 }
155         }
156
157         public void set_ground_altitude(double ground_altitude) {
158                 if (ground_altitude != AltosLib.MISSING)
159                         this.ground_altitude = ground_altitude;
160         }
161
162         /* Compute pressure */
163
164         public AltosPresTemp pressure_ms5607(int raw_pres, int raw_temp) {
165                 if (ms5607 == null)
166                         return new AltosPresTemp(AltosLib.MISSING, AltosLib.MISSING);
167                 return ms5607.pres_temp(raw_pres, raw_temp);
168         }
169
170         public int              tick = AltosLib.MISSING;
171         private int             first_tick = AltosLib.MISSING;
172         private int             prev_tick = AltosLib.MISSING;
173
174         public void set_tick(int tick) {
175                 if (tick != AltosLib.MISSING) {
176                         if (prev_tick != AltosLib.MISSING) {
177                                 while (tick < prev_tick - 1000) {
178                                         tick += 65536;
179                                 }
180                         }
181                         if (first_tick == AltosLib.MISSING)
182                                 first_tick = tick;
183                         prev_tick = tick;
184                         this.tick = tick;
185                 }
186         }
187
188         /* Reset all values which change during flight
189          */
190         public void reset() {
191                 state = AltosLib.MISSING;
192                 tick = AltosLib.MISSING;
193                 prev_tick = AltosLib.MISSING;
194                 temp_gps = null;
195                 prev_gps = null;
196                 temp_gps_sat_tick = AltosLib.MISSING;
197                 accel = AltosLib.MISSING;
198         }
199
200         public int              boost_tick = AltosLib.MISSING;
201
202         public void set_boost_tick() {
203                 boost_tick = tick;
204         }
205
206         public double           ticks_per_sec = 100.0;
207
208         public void set_ticks_per_sec(double ticks_per_sec) {
209                 this.ticks_per_sec = ticks_per_sec;
210         }
211
212         public double time() {
213                 if (tick == AltosLib.MISSING)
214                         return AltosLib.MISSING;
215                 if (boost_tick != AltosLib.MISSING)
216                         return (tick - boost_tick) / ticks_per_sec;
217                 if (first_tick != AltosLib.MISSING)
218                         return (tick - first_tick) / ticks_per_sec;
219                 return tick / ticks_per_sec;
220         }
221
222         public double boost_time() {
223                 if (boost_tick == AltosLib.MISSING)
224                         return AltosLib.MISSING;
225                 return boost_tick / ticks_per_sec;
226         }
227
228         public int              state = AltosLib.MISSING;
229
230         public void set_state(int state) {
231                 if (state >= AltosLib.ao_flight_boost && boost_tick == AltosLib.MISSING)
232                         set_boost_tick();
233                 this.state = state;
234         }
235
236         public AltosGPS         gps_pad = null;
237
238         public double           gps_pad_altitude = AltosLib.MISSING;
239
240         public void set_gps(AltosGPS gps) {
241                 if ((state != AltosLib.MISSING && state < AltosLib.ao_flight_boost) || gps_pad == null)
242                         gps_pad = gps;
243                 if (gps_pad_altitude == AltosLib.MISSING && gps.alt != AltosLib.MISSING)
244                         gps_pad_altitude = gps.alt;
245         }
246
247         /*
248          * While receiving GPS data, we construct a temporary GPS state
249          * object and then deliver the result atomically to the listener
250          */
251         AltosGPS                temp_gps = null;
252         AltosGPS                prev_gps = null;
253         int                     temp_gps_sat_tick = AltosLib.MISSING;
254
255         public AltosGPS temp_gps() {
256                 return temp_gps;
257         }
258
259         public void reset_temp_gps() {
260                 if (temp_gps != null) {
261                         if (temp_gps.locked && temp_gps.nsat >= 4)
262                                 set_gps(temp_gps);
263                         prev_gps = temp_gps;
264                         temp_gps = null;
265                 }
266         }
267
268         public boolean gps_pending() {
269                 return temp_gps != null;
270         }
271
272         public AltosGPS make_temp_gps(int tick, boolean sats) {
273                 if (temp_gps == null) {
274                         if (prev_gps != null)
275                                 temp_gps = prev_gps.clone();
276                         else
277                                 temp_gps = new AltosGPS();
278                 }
279                 if (sats) {
280                         if (tick != temp_gps_sat_tick)
281                                 temp_gps.cc_gps_sat = null;
282                         temp_gps_sat_tick = tick;
283                 }
284                 return temp_gps;
285         }
286
287         public double   accel_zero_along, accel_zero_across, accel_zero_through;
288
289         public void set_accel_zero(double zero_along, double zero_across, double zero_through) {
290                 if (zero_along != AltosLib.MISSING) {
291                         accel_zero_along = zero_along;
292                         accel_zero_across = zero_across;
293                         accel_zero_through = zero_through;
294                 }
295         }
296
297         public double accel_along(double counts) {
298                 return AltosIMU.convert_accel(counts - accel_zero_along);
299         }
300
301         public double accel_across(double counts) {
302                 return AltosIMU.convert_accel(counts - accel_zero_across);
303         }
304
305         public double accel_through(double counts) {
306                 return AltosIMU.convert_accel(counts - accel_zero_through);
307         }
308
309         public double   gyro_zero_roll, gyro_zero_pitch, gyro_zero_yaw;
310
311         public void set_gyro_zero(double roll, double pitch, double yaw) {
312                 if (roll != AltosLib.MISSING) {
313                         gyro_zero_roll = roll;
314                         gyro_zero_pitch = pitch;
315                         gyro_zero_yaw = yaw;
316                         imu_wrap_checked = false;
317                 }
318         }
319
320         public double gyro_roll(double counts) {
321                 if (gyro_zero_roll == AltosLib.MISSING || counts == AltosLib.MISSING)
322                         return AltosLib.MISSING;
323
324                 return AltosIMU.gyro_degrees_per_second(counts, gyro_zero_roll);
325         }
326
327         public double gyro_pitch(double counts) {
328                 if (gyro_zero_pitch == AltosLib.MISSING || counts == AltosLib.MISSING)
329                         return AltosLib.MISSING;
330                 return AltosIMU.gyro_degrees_per_second(counts, gyro_zero_pitch);
331         }
332
333         public double gyro_yaw(double counts) {
334                 if (gyro_zero_yaw == AltosLib.MISSING || counts == AltosLib.MISSING)
335                         return AltosLib.MISSING;
336                 return AltosIMU.gyro_degrees_per_second(counts, gyro_zero_yaw);
337         }
338
339         private double gyro_zero_overflow(double first) {
340                 double v = first / 128.0;
341                 if (v < 0)
342                         v = Math.ceil(v);
343                 else
344                         v = Math.floor(v);
345                 if (v != 0)
346                         System.out.printf("Adjusting gyro axis by %g steps\n", v);
347                 return v * 128.0;
348         }
349
350         /* Initial TeleMega log format had only 16 bits for gyro cal, so the top 9 bits got lost as the
351          * cal data are scaled by 512. Use the first sample to adjust the cal value, assuming that it is
352          * from a time of fairly low rotation speed. Fixed in later TeleMega firmware by storing 32 bits
353          * of cal values.
354          */
355         private boolean imu_wrap_checked = false;
356
357         public void check_imu_wrap(double roll, double pitch, double yaw) {
358                 if (!imu_wrap_checked) {
359                         gyro_zero_roll += gyro_zero_overflow(roll);
360                         gyro_zero_pitch += gyro_zero_overflow(pitch);
361                         gyro_zero_yaw += gyro_zero_overflow(yaw);
362                         imu_wrap_checked = true;
363                 }
364         }
365
366         public double mag_along(double along) {
367                 if (along == AltosLib.MISSING)
368                         return AltosLib.MISSING;
369                 return AltosMag.convert_gauss(along);
370         }
371
372         public double mag_across(double across) {
373                 if (across == AltosLib.MISSING)
374                         return AltosLib.MISSING;
375                 return AltosMag.convert_gauss(across);
376         }
377
378         public double mag_through(double through) {
379                 if (through == AltosLib.MISSING)
380                         return AltosLib.MISSING;
381                 return AltosMag.convert_gauss(through);
382         }
383
384         public AltosCalData() {
385         }
386
387         public AltosCalData(AltosConfigData config_data) {
388                 set_serial(config_data.serial);
389                 set_ticks_per_sec(100.0);
390                 set_flight(config_data.flight);
391                 set_callsign(config_data.callsign);
392                 set_config(config_data.config_major, config_data.config_minor, config_data.flight_log_max);
393                 set_firmware_version(config_data.version);
394                 set_flight_params(config_data.apogee_delay / ticks_per_sec, config_data.apogee_lockout / ticks_per_sec);
395                 set_pad_orientation(config_data.pad_orientation);
396                 set_product(config_data.product);
397                 set_accel_plus_minus(config_data.accel_cal_plus, config_data.accel_cal_minus);
398                 set_accel_zero(config_data.accel_zero_along, config_data.accel_zero_across, config_data.accel_zero_through);
399                 set_ms5607(config_data.ms5607);
400                 try {
401                         set_mma655x_inverted(config_data.mma655x_inverted());
402                 } catch (AltosUnknownProduct up) {
403                 }
404                 set_pad_orientation(config_data.pad_orientation);
405         }
406 }