2 * Copyright © 2012 Keith Packard <keithp@keithp.com>
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; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
18 package org.altusmetrum.micropeak;
23 import org.altusmetrum.AltosLib.*;
25 public class MicroData {
26 public int ground_pressure;
27 public int min_pressure;
28 public int[] pressures;
29 private double time_step;
30 private double ground_altitude;
31 private ArrayList<Integer> bytes;
34 class FileEndedException extends Exception {
37 class NonHexcharException extends Exception {
40 class InvalidCrcException extends Exception {
43 private int getc(InputStream f) throws IOException, FileEndedException {
47 throw new FileEndedException();
52 private int get_nonwhite(InputStream f) throws IOException, FileEndedException {
57 if (!Character.isWhitespace(c))
62 private int get_hexc(InputStream f) throws IOException, FileEndedException, NonHexcharException {
63 int c = get_nonwhite(f);
65 if ('0' <= c && c <= '9')
67 if ('a' <= c && c <= 'f')
69 if ('A' <= c && c <= 'F')
71 throw new NonHexcharException();
74 private static final int POLY = 0x8408;
76 private int log_crc(int crc, int b) {
79 for (i = 0; i < 8; i++) {
80 if (((crc & 0x0001) ^ (b & 0x0001)) != 0)
81 crc = (crc >> 1) ^ POLY;
91 private int get_hex(InputStream f) throws IOException, FileEndedException, NonHexcharException {
97 file_crc = log_crc(file_crc, h);
101 private boolean find_header(InputStream f) throws IOException {
104 if (get_nonwhite(f) == 'M' && get_nonwhite(f) == 'P')
107 } catch (FileEndedException fe) {
112 private int get_32(InputStream f) throws IOException, FileEndedException, NonHexcharException {
114 for (int i = 0; i < 4; i++) {
115 v += get_hex(f) << (i * 8);
120 private int get_16(InputStream f) throws IOException, FileEndedException, NonHexcharException {
122 for (int i = 0; i < 2; i++) {
123 v += get_hex(f) << (i * 8);
128 private int swap16(int i) {
129 return ((i << 8) & 0xff00) | ((i >> 8) & 0xff);
132 public boolean crc_valid;
134 int mix_in (int high, int low) {
135 return high - (high & 0xffff) + low;
138 boolean closer (int target, int a, int b) {
139 return Math.abs (target - a) < Math.abs(target - b);
142 public double altitude(int i) {
143 return AltosConvert.pressure_to_altitude(pressures[i]);
149 return n * fact(n-1);
152 int choose(int n, int k) {
153 return fact(n) / (fact(k) * fact(n-k));
157 public double avg_altitude(int center, int dist) {
158 int start = center - dist;
159 int stop = center + dist;
163 if (stop >= pressures.length)
164 stop = pressures.length - 1;
171 for (int i = start; i <= stop; i++) {
172 int k = i - (center - dist);
173 int c = choose (n, k);
175 sum += c * pressures[i];
179 double pres = sum / div;
181 double alt = AltosConvert.pressure_to_altitude(pres);
185 public double height(int i) {
186 return altitude(i) - ground_altitude;
189 static final int speed_avg = 3;
190 static final int accel_avg = 5;
192 private double avg_speed(int center, int dist) {
196 double ai = avg_altitude(center, dist);
197 double aj = avg_altitude(center - 1, dist);
198 double s = (ai - aj) / time_step;
203 public double speed(int i) {
204 return avg_speed(i, speed_avg);
207 public double acceleration(int i) {
210 return (avg_speed(i, accel_avg) - avg_speed(i-1, accel_avg)) / time_step;
213 public double time(int i) {
214 return i * time_step;
217 public void save (OutputStream f) throws IOException {
222 public MicroData (InputStream f) throws IOException {
223 bytes = new ArrayList<Integer>();
225 throw new IOException();
228 ground_pressure = get_32(f);
229 min_pressure = get_32(f);
230 int nsamples = get_16(f);
231 pressures = new int[nsamples + 1];
233 ground_altitude = AltosConvert.pressure_to_altitude(ground_pressure);
234 int cur = ground_pressure;
236 for (int i = 0; i < nsamples; i++) {
238 int same = mix_in(cur, k);
239 int up = mix_in(cur + 0x10000, k);
240 int down = mix_in(cur - 0x10000, k);
242 if (closer (cur, same, up)) {
243 if (closer (cur, same, down))
248 if (closer (cur, up, down))
254 pressures[i+1] = cur;
257 int current_crc = swap16(~file_crc & 0xffff);
260 crc_valid = crc == current_crc;
263 } catch (FileEndedException fe) {
264 throw new IOException();
265 } catch (NonHexcharException ne) {
266 throw new IOException();