diff options
author | Bdale Garbee <bdale@gag.com> | 2017-09-18 20:35:00 -0600 |
---|---|---|
committer | Bdale Garbee <bdale@gag.com> | 2017-09-18 20:35:00 -0600 |
commit | b12e982259817328e348f1aaa91c5c824891e7b9 (patch) | |
tree | 52ae2d2068fd637dd03938d592e8a7492e49ab9f | |
parent | b1cf0dab1e28433e06ab02cec033951ea0149ea3 (diff) | |
parent | e87d56b665ca30a3e5920c23cd60c99b84341aa2 (diff) |
Merge branch 'master' into branch-1.8
44 files changed, 1779 insertions, 528 deletions
diff --git a/Makefile.am b/Makefile.am index cac02c62..4f47417e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,6 +64,7 @@ fat_altos = \ src/teledongle-v0.2/teledongle-v0.2-$(VERSION).ihx \ src/teledongle-v3.0/teledongle-v3.0-$(VERSION).ihx \ src/telegps-v1.0/telegps-v1.0-$(VERSION).ihx \ + src/telegps-v2.0/telegps-v2.0-$(VERSION).ihx \ src/telemega-v1.0/telemega-v1.0-$(VERSION).ihx \ src/telemega-v2.0/telemega-v2.0-$(VERSION).ihx \ src/telemetrum-v1.0/telemetrum-v1.0-$(VERSION).ihx \ @@ -95,11 +95,8 @@ These are Bdale's notes on how to do a release. --with-fat-dir=/home/bdale/web/altusmetrum/ make && make fat - this pushes packages for each platform and application - to web site, including auto-generated mdwn files and - release notes in html format. + - store a stable copy of ARM binaries for production use - # store a stable copy of ARM binaries for production use cp src/chaoskey-v1.0/{*.elf,*.ihx} \ src/easymega-v1.0/{*.elf,*.ihx} \ src/easymini-v1.0/{*.elf,*.ihx} \ @@ -108,6 +105,7 @@ These are Bdale's notes on how to do a release. src/telebt-v4.0/{*.elf,*.ihx} \ src/teledongle-v3.0/{*.elf,*.ihx} \ src/telegps-v1.0/{*.elf,*.ihx} \ + src/telegps-v2.0/{*.elf,*.ihx} \ src/telemega-v1.0/{*.elf,*.ihx} \ src/telemega-v2.0/{*.elf,*.ihx} \ src/telemetrum-v2.0/{*.elf,*.ihx} \ @@ -118,9 +116,10 @@ These are Bdale's notes on how to do a release. src/easymini-v1.0/flash-loader/*.elf \ src/easymini-v2.0/flash-loader/{*.elf,*.bin} \ src/telebt-v3.0/flash-loader/*.elf \ - src/telebt-v4.0/flash-loader/*.elf \ + src/telebt-v4.0/flash-loader/{*.elf,*.bin} \ src/teledongle-v3.0/flash-loader/*.elf \ src/telegps-v1.0/flash-loader/*.elf \ + src/telegps-v2.0/flash-loader/*.elf \ src/telemega-v1.0/flash-loader/*.elf \ src/telemega-v2.0/flash-loader/*.elf \ src/telemetrum-v2.0/flash-loader/*.elf \ @@ -129,26 +128,23 @@ These are Bdale's notes on how to do a release. (cd ~/altusmetrumllc ; git add Binaries ; git commit -a) (cd ~/altusmetrumllc ; git push) - - copy the relevant release notes .html file from doc/ to - /home/bdale/web/altusmetrum/AltOS/releases/<rev> - - Push new release to web site make fat-install (cd doc ; make publish) - (cd ~/web/altusmetrum/ && git add AltOS/releases - TeleGPS/releases MicroPeak/releases && git commit -m'Release - <rev>' && git push origin master) + (cd ~/web/altusmetrum/ && \ + git add */releases && git commit -m'Release <rev>' && \ + git push origin master) + + - upload the Debian package - this pushes fresh documents to the web site + - clean up sudo debian/rules clean git push origin master branch-<version> debian pristine-tar git push --tags - push commits and leave the build tree in an uncluttered state - Testing before a release To verify that a build works, the following need to be checked diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 924ab4c9..0776fa00 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -77,6 +77,75 @@ class SavedState { } } +class Tracker implements CharSequence, Comparable { + int serial; + String call; + double frequency; + + String display; + + public Tracker(int serial, String call, double frequency) { + if (call == null) + call = "none"; + + this.serial = serial; + this.call = call; + this.frequency = frequency; + if (frequency == 0.0) + display = "Auto"; + else if (frequency == AltosLib.MISSING) { + display = String.format("%-8.8s %6d", call, serial); + } else { + display = String.format("%-8.8s %7.3f %6d", call, frequency, serial); + } + } + + public Tracker(AltosState s) { + this(s == null ? 0 : s.cal_data().serial, + s == null ? null : s.cal_data().callsign, + s == null ? 0.0 : s.frequency); + } + + /* CharSequence */ + public char charAt(int index) { + return display.charAt(index); + } + + public int length() { + return display.length(); + } + + public CharSequence subSequence(int start, int end) throws IndexOutOfBoundsException { + return display.subSequence(start, end); + } + + public String toString() { + return display.toString(); + } + + /* Comparable */ + public int compareTo (Object other) { + Tracker o = (Tracker) other; + if (frequency == 0.0) { + if (o.frequency == 0.0) + return 0; + return -1; + } + if (o.frequency == 0.0) + return 1; + + int a = serial - o.serial; + int b = call.compareTo(o.call); + int c = (int) Math.signum(frequency - o.frequency); + + if (b != 0) + return b; + if (c != 0) + return c; + return a; + } +} + public class AltosDroid extends FragmentActivity implements AltosUnitsListener, LocationListener { // Actions sent to the telemetry server at startup time @@ -151,7 +220,8 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener, private Timer timer; TelemetryState telemetry_state; - Integer[] serials; + Tracker[] trackers; + UsbDevice pending_usb_device; boolean start_with_usb; @@ -323,8 +393,20 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener, AltosPreferences.register_units_listener(this); } - serials = telemetry_state.states.keySet().toArray(new Integer[0]); - Arrays.sort(serials); + int num_trackers = 0; + for (AltosState s : telemetry_state.states.values()) { + num_trackers++; + } + + trackers = new Tracker[num_trackers + 1]; + + int n = 0; + trackers[n++] = new Tracker(0, "auto", 0.0); + + for (AltosState s : telemetry_state.states.values()) + trackers[n++] = new Tracker(s); + + Arrays.sort(trackers); update_title(telemetry_state); @@ -955,11 +1037,11 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener, } if (serial != 0) { - for (i = 0; i < serials.length; i++) - if (serials[i] == serial) + for (i = 0; i < trackers.length; i++) + if (trackers[i].serial == serial) break; - if (i == serials.length) { + if (i == trackers.length) { AltosDebug.debug("attempt to select unknown tracker %d\n", serial); return; } @@ -972,17 +1054,22 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener, void touch_trackers(Integer[] serials) { AlertDialog.Builder builder_tracker = new AlertDialog.Builder(this); builder_tracker.setTitle("Select Tracker"); - final String[] trackers = new String[serials.length + 1]; - trackers[0] = "Auto"; - for (int i = 0; i < serials.length; i++) - trackers[i+1] = String.format("%d", serials[i]); - builder_tracker.setItems(trackers, + + final Tracker[] my_trackers = new Tracker[serials.length + 1]; + + my_trackers[0] = new Tracker(null); + + for (int i = 0; i < serials.length; i++) { + AltosState s = telemetry_state.states.get(serials[i]); + my_trackers[i+1] = new Tracker(s); + } + builder_tracker.setItems(my_trackers, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { if (item == 0) select_tracker(0); else - select_tracker(Integer.parseInt(trackers[item])); + select_tracker(my_trackers[item].serial); } }); AlertDialog alert_tracker = builder_tracker.create(); @@ -1040,20 +1127,17 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener, alert_freq.show(); return true; case R.id.select_tracker: - if (serials != null) { - String[] trackers = new String[serials.length+1]; - trackers[0] = "Auto"; - for (int i = 0; i < serials.length; i++) - trackers[i+1] = String.format("%d", serials[i]); + if (trackers != null) { AlertDialog.Builder builder_serial = new AlertDialog.Builder(this); builder_serial.setTitle("Select a tracker"); builder_serial.setItems(trackers, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { + System.out.printf("select item %d %s\n", item, trackers[item].display); if (item == 0) select_tracker(0); else - select_tracker(serials[item-1]); + select_tracker(trackers[item].serial); } }); AlertDialog alert_serial = builder_serial.create(); @@ -1062,16 +1146,16 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener, } return true; case R.id.delete_track: - if (serials != null) { - String[] trackers = new String[serials.length]; - for (int i = 0; i < serials.length; i++) - trackers[i] = String.format("%d", serials[i]); + if (trackers != null) { AlertDialog.Builder builder_serial = new AlertDialog.Builder(this); builder_serial.setTitle("Delete a track"); - builder_serial.setItems(trackers, + final Tracker[] my_trackers = new Tracker[trackers.length - 1]; + for (int i = 0; i < trackers.length - 1; i++) + my_trackers[i] = trackers[i+1]; + builder_serial.setItems(my_trackers, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { - delete_track(serials[item]); + delete_track(my_trackers[item].serial); } }); AlertDialog alert_serial = builder_serial.create(); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java index d097a550..69685dc7 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java @@ -60,6 +60,7 @@ public class TelemetryReader extends Thread { while (telemQueue != null) { try { AltosTelemetry telem = read(); + telem.set_frequency(link.frequency); handler.obtainMessage(TelemetryService.MSG_TELEMETRY, telem).sendToTarget(); } catch (ParseException pp) { AltosDebug.error("Parse error: %d \"%s\"", pp.getErrorOffset(), pp.getMessage()); diff --git a/altoslib/AltosAccelCal.java b/altoslib/AltosAccelCal.java new file mode 100644 index 00000000..03d9fbf2 --- /dev/null +++ b/altoslib/AltosAccelCal.java @@ -0,0 +1,217 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.altusmetrum.altoslib_12; + +import java.io.*; +import java.util.concurrent.*; + +public class AltosAccelCal implements Runnable { + + AltosLink link; + AltosAccelCalListener listener; + + boolean remote; + boolean close_on_exit; + double frequency; + String callsign; + + Thread accel_thread; + + AltosConfigData config_data; + + public static final int phase_antenna_up = 0; + public static final int phase_antenna_down = 1; + + void start_link() throws InterruptedException, TimeoutException { + if (remote) { + link.set_radio_frequency(frequency); + link.set_callsign(callsign); + link.start_remote(); + } else + link.flush_input(); + } + + boolean stop_link() throws InterruptedException, TimeoutException { + if (remote) + link.stop_remote(); + return link.reply_abort; + } + + public void set_frequency(double in_frequency) { + frequency = in_frequency; + link.abort_reply(); + } + + public void set_callsign(String in_callsign) { + callsign = in_callsign; + link.abort_reply(); + } + + public void abort() throws InterruptedException { + while (accel_thread.isAlive()) { + accel_thread.interrupt(); + link.abort_reply(); + Thread.sleep(100); + } + accel_thread.join(); + } + + static private final String press_msg = "press a key..."; + + private Semaphore ui_signal_semaphore; + private boolean ui_signal_reply; + + public void signal(boolean reply) { + System.out.printf("Signal cal semaphore %b\n", reply); + ui_signal_reply = reply; + ui_signal_semaphore.release(); + } + + private boolean wait_signal() throws InterruptedException { + System.out.printf("\twait for cal signal...\n"); + ui_signal_semaphore.acquire(); + System.out.printf("\tgot cal signal %b\n", ui_signal_reply); + return ui_signal_reply; + } + + private boolean wait_press(int timeout) throws InterruptedException { + for (;;) { + String line = link.get_reply(timeout); + if (line == null) { + System.out.printf("get_reply timeout\n"); + return false; + } + System.out.printf("got line %s\n", line); + if (line.contains(press_msg)) + return true; + if (line.contains("Invalid")) + return false; + if (line.contains("Syntax")) + return false; + if (line.contains("Calibrating")) + listener.message(this, line); + } + } + + static final int cal_timeout = 20 * 1000; + + public void run() { + System.out.printf("start accel cal procedure\n"); + try { + AltosConfigData new_config = null; + + try { + start_link(); + config_data = link.config_data(); + + /* set back to antenna up for calibration */ + if (config_data.pad_orientation != 0) + link.printf("c o 0\n"); + + /* Start calibration */ + try { + System.out.printf("*** start cal\n"); + link.set_match(press_msg); + link.printf("c a 0\n"); + System.out.printf("*** wait press\n"); + if (!wait_press(cal_timeout)) + throw new TimeoutException("timeout"); + System.out.printf("*** set_phase antenna_up\n"); + listener.set_phase(this, phase_antenna_up); + System.out.printf("*** wait_signal\n"); + if (!wait_signal()) + throw new InterruptedException("aborted"); + link.set_match(press_msg); + System.out.printf("*** send newline\n"); + link.printf("\n"); + System.out.printf("*** wait press\n"); + if (!wait_press(cal_timeout)) + throw new TimeoutException("timeout"); + System.out.printf("***set_phase antenna_down\n"); + listener.set_phase(this, phase_antenna_down); + System.out.printf("*** wait_signal\n"); + if (!wait_signal()) + throw new InterruptedException("aborted"); + System.out.printf("*** send newline and version command\n"); + link.printf("\nv\n"); + } catch (TimeoutException e) { + throw e; + } catch (InterruptedException e) { + throw e; + } + link.set_match(null); + + boolean worked = true; + for (;;) { + String line = link.get_reply(cal_timeout); + if (line == null) + throw new TimeoutException(); + System.out.printf("*** waiting for finish: %s\n", line); + if (line.contains("Invalid")) + worked = false; + if (line.contains("software-version")) + break; + if (line.contains("Calibrating")) + listener.message(this, line); + } + System.out.printf("*** worked: %b\n", worked); + if (worked) + new_config = new AltosConfigData(link); + } finally { + System.out.printf("Restore orientation %d +g %d -g %d\n", + config_data.pad_orientation, + config_data.accel_cal_plus, + config_data.accel_cal_minus); + if (config_data.pad_orientation != AltosLib.MISSING && config_data.pad_orientation != 0) + link.printf("c o %d\n", config_data.pad_orientation); + if (config_data.accel_cal_plus != AltosLib.MISSING && config_data.accel_cal_minus != AltosLib.MISSING) + link.printf("c a %d %d\n", + config_data.accel_cal_plus, config_data.accel_cal_minus); + stop_link(); + } + if (new_config != null) { + System.out.printf("*** +1g %d -1g %d\n", + new_config.accel_cal_plus, + new_config.accel_cal_minus); + listener.cal_done(this, new_config.accel_cal_plus, new_config.accel_cal_minus); + if (!wait_signal()) + throw new InterruptedException("aborted"); + } else + listener.error(this, "Calibration failed"); + } catch (TimeoutException te) { + System.out.printf("timeout"); + listener.error(this, "timeout"); + } catch (InterruptedException ie) { + System.out.printf("interrupted\n"); + listener.error(this, "interrupted"); + } + } + + public void start() { + accel_thread = new Thread(this); + listener.set_thread(this, accel_thread); + accel_thread.start(); + } + + public AltosAccelCal(AltosLink link, AltosAccelCalListener listener) { + this.link = link; + this.listener = listener; + ui_signal_semaphore = new Semaphore(0); + } +} diff --git a/altoslib/AltosAccelCalListener.java b/altoslib/AltosAccelCalListener.java new file mode 100644 index 00000000..17359245 --- /dev/null +++ b/altoslib/AltosAccelCalListener.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.altusmetrum.altoslib_12; + +import java.io.*; +import java.util.concurrent.*; + +public interface AltosAccelCalListener { + public void set_thread(AltosAccelCal cal, Thread thread); + + public void set_phase(AltosAccelCal cal, int phase); + + public void cal_done(AltosAccelCal cal, int plus, int minus); + + public void error(AltosAccelCal cal, String msg); + + public void message(AltosAccelCal cal, String msg); +} diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index 63c34310..dc036867 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -405,7 +405,7 @@ public class AltosConfigData { /* HAS_GYRO */ try { - if (line.startsWith("IMU call along")) { + if (line.startsWith("IMU cal along")) { String[] bits = line.split("\\s+"); if (bits.length >= 8) { accel_zero_along = Integer.parseInt(bits[3]); @@ -525,6 +525,12 @@ public class AltosConfigData { if (pad_orientation != AltosLib.MISSING) pad_orientation = source.pad_orientation(); + if (accel_cal_plus != AltosLib.MISSING) + accel_cal_plus = source.accel_cal_plus(); + + if (accel_cal_minus != AltosLib.MISSING) + accel_cal_minus = source.accel_cal_minus(); + /* HAS_LOG */ if (flight_log_max != AltosLib.MISSING) flight_log_max = source.flight_log_max(); @@ -592,6 +598,7 @@ public class AltosConfigData { dest.set_flight_log_max(flight_log_max); dest.set_ignite_mode(ignite_mode); dest.set_pad_orientation(pad_orientation); + dest.set_accel_cal(accel_cal_plus, accel_cal_minus); dest.set_callsign(callsign); if (npyro != AltosLib.MISSING) dest.set_pyros(pyros); @@ -669,9 +676,10 @@ public class AltosConfigData { link.printf("c e %d\n", radio_enable); /* HAS_ACCEL */ - /* UI doesn't support accel cal */ if (pad_orientation != AltosLib.MISSING) link.printf("c o %d\n", pad_orientation); + if (accel_cal_plus != AltosLib.MISSING && accel_cal_minus != AltosLib.MISSING) + link.printf("c a %d %d\n", accel_cal_plus, accel_cal_minus); /* HAS_LOG */ if (flight_log_max != 0) diff --git a/altoslib/AltosConfigValues.java b/altoslib/AltosConfigValues.java index 170b1112..10478fd4 100644 --- a/altoslib/AltosConfigValues.java +++ b/altoslib/AltosConfigValues.java @@ -74,6 +74,16 @@ public interface AltosConfigValues { public abstract int pad_orientation(); + public abstract void set_accel_cal(int accel_cal_plus, int accel_cal_minus); + + public abstract int accel_cal_plus(); + + public abstract int accel_cal_minus(); + + public abstract void set_dirty(); + + public abstract void set_clean(); + public abstract void set_pyros(AltosPyro[] new_pyros); public abstract AltosPyro[] pyros() throws AltosConfigDataException; diff --git a/altoslib/AltosDataListener.java b/altoslib/AltosDataListener.java index 5f89b3e4..be6d840f 100644 --- a/altoslib/AltosDataListener.java +++ b/altoslib/AltosDataListener.java @@ -20,6 +20,7 @@ public abstract class AltosDataListener { public double time = AltosLib.MISSING; public int state = AltosLib.MISSING; + public double frequency = AltosLib.MISSING; public void set_tick(int tick) { cal_data.set_tick(tick); @@ -55,6 +56,10 @@ public abstract class AltosDataListener { cal_data().set_flight(flight); } + public void set_frequency(double frequency) { + this.frequency = frequency; + } + /* Called after all records are captured */ public void finish() { } diff --git a/altoslib/AltosFlightStats.java b/altoslib/AltosFlightStats.java index c2e4e2a3..ea1a9675 100644 --- a/altoslib/AltosFlightStats.java +++ b/altoslib/AltosFlightStats.java @@ -212,8 +212,11 @@ public class AltosFlightStats { add_times(series, (int) prev.value, prev.time, state.time); prev = state; } - if (prev != null) - add_times(series, (int) prev.value, prev.time, series.accel_series.last().time); + if (prev != null) { + AltosTimeValue last_accel = series.accel_series.last(); + if (last_accel != null) + add_times(series, (int) prev.value, prev.time, last_accel.time); + } } for (int s = 0; s <= AltosLib.ao_flight_invalid; s++) { @@ -245,14 +248,15 @@ public class AltosFlightStats { has_gps = true; lat = pad_lat = gps.lat; lon = pad_lon = gps.lon; - for (AltosGPSTimeValue gtv : series.gps_series) { - gps = gtv.gps; - if (gps.locked && gps.nsat >= 4) { - lat = gps.lat; - lon = gps.lon; + if (series.gps_series != null) { + for (AltosGPSTimeValue gtv : series.gps_series) { + gps = gtv.gps; + if (gps.locked && gps.nsat >= 4) { + lat = gps.lat; + lon = gps.lon; + } } } - } max_height = AltosLib.MISSING; diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 5a802ef1..5413de9d 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -43,6 +43,8 @@ public abstract class AltosLink implements Runnable { public LinkedBlockingQueue<AltosLine> reply_queue = new LinkedBlockingQueue<AltosLine>(); public LinkedBlockingQueue<byte[]> binary_queue = new LinkedBlockingQueue<byte[]>(); + private String match_string = null; + public synchronized void add_monitor(LinkedBlockingQueue<AltosLine> q) { set_monitor(true); monitors.add(q); @@ -112,6 +114,15 @@ public abstract class AltosLink implements Runnable { private int len_read = 0; + private boolean match_bytes(byte[] bytes, int byte_count, String match) { + if (byte_count < match.length()) + return false; + String line = new String(bytes, 0, byte_count, AltosLib.unicode_set); + if (line == null) + return false; + return line.indexOf(match) >= 0; + } + public void run () { int c; byte[] line_bytes = null; @@ -159,6 +170,11 @@ public abstract class AltosLink implements Runnable { line_count = 0; len_read = 0; } + if (match_string != null && match_bytes(line_bytes, line_count, match_string)) { + match_string = null; + add_bytes(line_bytes, line_count); + line_count = 0; + } } } } @@ -166,6 +182,9 @@ public abstract class AltosLink implements Runnable { } } + public void set_match(String match) { + match_string = match; + } public String get_reply(int timeout) throws InterruptedException { boolean can_cancel = can_cancel_reply(); diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 9ee3d57d..39ab10da 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -1060,7 +1060,6 @@ public class AltosState extends AltosDataListener { } public AltosState() { - Thread.dumpStack(); init(); } diff --git a/altoslib/AltosTelemetry.java b/altoslib/AltosTelemetry.java index 7d576942..f17e1171 100644 --- a/altoslib/AltosTelemetry.java +++ b/altoslib/AltosTelemetry.java @@ -38,6 +38,9 @@ public abstract class AltosTelemetry implements AltosDataProvider { /* Mark when we received the packet */ long received_time; + /* Mark frequency packet was received on */ + public double frequency = AltosLib.MISSING; + static boolean cksum(int[] bytes) { int sum = 0x5a; for (int i = 1; i < bytes.length - 1; i++) @@ -50,6 +53,8 @@ public abstract class AltosTelemetry implements AltosDataProvider { listener.set_serial(serial()); if (listener.state == AltosLib.ao_flight_invalid) listener.set_state(AltosLib.ao_flight_startup); + if (frequency != AltosLib.MISSING) + listener.set_frequency(frequency); listener.set_tick(tick()); listener.set_rssi(rssi(), status()); listener.set_received_time(received_time); @@ -108,6 +113,10 @@ public abstract class AltosTelemetry implements AltosDataProvider { return telem; } + public void set_frequency(double frequency) { + this.frequency = frequency; + } + public AltosTelemetry() { this.received_time = System.currentTimeMillis(); } diff --git a/altoslib/AltosTimeSeries.java b/altoslib/AltosTimeSeries.java index b3c432fc..9f3b4d80 100644 --- a/altoslib/AltosTimeSeries.java +++ b/altoslib/AltosTimeSeries.java @@ -151,11 +151,15 @@ public class AltosTimeSeries implements Iterable<AltosTimeValue>, Comparable<Alt } public AltosTimeValue first() { - return values.get(0); + if (values.size() > 0) + return values.get(0); + return null; } public AltosTimeValue last() { - return values.get(values.size() - 1); + if (values.size() > 0) + return values.get(values.size() - 1); + return null; } public double average() { diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 11b5d562..08af9496 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -26,6 +26,8 @@ record_files = \ altoslib_JAVA = \ AltosLib.java \ + AltosAccelCal.java \ + AltosAccelCalListener.java \ AltosCalData.java \ AltosCompanion.java \ AltosConfigData.java \ diff --git a/altosui/AltosConfigFC.java b/altosui/AltosConfigFC.java index beff71b7..5e2aa7f4 100644 --- a/altosui/AltosConfigFC.java +++ b/altosui/AltosConfigFC.java @@ -268,6 +268,13 @@ public class AltosConfigFC implements ActionListener { if (serial_line != null) serial_line.close(); } + else if (cmd.equals("Accel")) { + if (data.pad_orientation != AltosLib.MISSING) { + AltosUIAccelCal accel_ui = new AltosUIAccelCal(owner, serial_line, config_ui); + if (accel_ui != null) + accel_ui.doit(); + } + } } catch (InterruptedException ie) { abort(); } catch (TimeoutException te) { diff --git a/altosui/AltosConfigFCUI.java b/altosui/AltosConfigFCUI.java index c0c37254..1e875dec 100644 --- a/altosui/AltosConfigFCUI.java +++ b/altosui/AltosConfigFCUI.java @@ -49,6 +49,8 @@ public class AltosConfigFCUI JLabel flight_log_max_label; JLabel ignite_mode_label; JLabel pad_orientation_label; + JLabel accel_plus_label; + JLabel accel_minus_label; JLabel callsign_label; JLabel beep_label; JLabel tracker_motion_label; @@ -73,12 +75,15 @@ public class AltosConfigFCUI JComboBox<String> flight_log_max_value; JComboBox<String> ignite_mode_value; JComboBox<String> pad_orientation_value; + JTextField accel_plus_value; + JTextField accel_minus_value; JTextField callsign_value; JComboBox<String> beep_value; JComboBox<String> tracker_motion_value; JComboBox<String> tracker_interval_value; JButton pyro; + JButton accel_cal; JButton save; JButton reset; @@ -250,9 +255,9 @@ public class AltosConfigFCUI } void set_pad_orientation_tool_tip() { - if (pad_orientation_value.isVisible()) + if (pad_orientation_value.isVisible()) { pad_orientation_value.setToolTipText("How will the computer be mounted in the airframe"); - else { + } else { if (is_telemetrum()) pad_orientation_value.setToolTipText("Older TeleMetrum firmware must fly antenna forward"); else if (is_telemini() || is_easymini()) @@ -262,6 +267,16 @@ public class AltosConfigFCUI } } + void set_accel_tool_tips() { + if (accel_plus_value.isVisible()) { + accel_plus_value.setToolTipText("Pad acceleration value in flight orientation"); + accel_minus_value.setToolTipText("Upside-down acceleration value"); + } else { + accel_plus_value.setToolTipText("No accelerometer"); + accel_minus_value.setToolTipText("No accelerometer"); + } + } + void set_beep_tool_tip() { if (beep_value.isVisible()) beep_value.setToolTipText("What frequency the beeper will sound at"); @@ -709,6 +724,57 @@ public class AltosConfigFCUI set_pad_orientation_tool_tip(); row++; + /* Accel plus */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = row; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + accel_plus_label = new JLabel("Accel Plus:"); + pane.add(accel_plus_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = row; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + accel_plus_value = new JTextField(10); + accel_plus_value.setEditable(true); + accel_plus_value.getDocument().addDocumentListener(this); + pane.add(accel_plus_value, c); + row++; + + /* Accel minus */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = row; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + accel_minus_label = new JLabel("Accel Minus:"); + pane.add(accel_minus_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = row; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + accel_minus_value = new JTextField(10); + accel_minus_value.setEditable(true); + accel_minus_value.getDocument().addDocumentListener(this); + pane.add(accel_minus_value, c); + row++; + set_accel_tool_tips(); + /* Beeper */ c = new GridBagConstraints(); c.gridx = 0; c.gridy = row; @@ -800,6 +866,20 @@ public class AltosConfigFCUI pyro.setActionCommand("Pyro"); row++; + /* Accel cal */ + c = new GridBagConstraints(); + c.gridx = 5; c.gridy = row; + c.gridwidth = 5; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + accel_cal = new JButton("Calibrate Accelerometer"); + pane.add(accel_cal, c); + accel_cal.addActionListener(this); + accel_cal.setActionCommand("Accel"); + row++; + /* Buttons */ c = new GridBagConstraints(); c.gridx = 0; c.gridy = row; @@ -873,7 +953,7 @@ public class AltosConfigFCUI return true; } - void set_dirty() { + public void set_dirty() { dirty = true; save.setEnabled(true); } @@ -912,7 +992,8 @@ public class AltosConfigFCUI setVisible(false); dispose(); } - set_clean(); + if (cmd.equals("Save") || cmd.equals("Reset")) + set_clean(); } /* ItemListener interface method */ @@ -943,6 +1024,7 @@ public class AltosConfigFCUI radio_frequency_value.set_product(product); product_value.setText(product); set_pad_orientation_tool_tip(); + set_accel_tool_tips(); set_flight_log_max_tool_tip(); } @@ -1196,6 +1278,7 @@ public class AltosConfigFCUI } pad_orientation_value.setVisible(new_pad_orientation != AltosLib.MISSING); pad_orientation_label.setVisible(new_pad_orientation != AltosLib.MISSING); + accel_cal.setVisible(new_pad_orientation != AltosLib.MISSING); set_pad_orientation_tool_tip(); } @@ -1207,6 +1290,31 @@ public class AltosConfigFCUI return AltosLib.MISSING; } + public void set_accel_cal(int accel_plus, int accel_minus) { + if (accel_plus != AltosLib.MISSING) { + accel_plus_value.setText(String.format("%d", accel_plus)); + accel_minus_value.setText(String.format("%d", accel_minus)); + } + accel_plus_value.setVisible(accel_plus != AltosLib.MISSING); + accel_plus_label.setVisible(accel_plus != AltosLib.MISSING); + accel_minus_value.setVisible(accel_minus != AltosLib.MISSING); + accel_minus_label.setVisible(accel_minus != AltosLib.MISSING); + + set_accel_tool_tips(); + } + + public int accel_cal_plus() { + if (accel_plus_value.isVisible()) + return Integer.parseInt(accel_plus_value.getText()); + return AltosLib.MISSING; + } + + public int accel_cal_minus() { + if (accel_minus_value.isVisible()) + return Integer.parseInt(accel_minus_value.getText()); + return AltosLib.MISSING; + } + public void set_beep(int new_beep) { if (new_beep != AltosLib.MISSING) { int new_freq = (int) Math.floor (AltosConvert.beep_value_to_freq(new_beep) + 0.5); diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index f6c906c6..042f9277 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -48,7 +48,6 @@ public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, Alt if (flight_series.gps_series != null) { for (AltosGPSTimeValue gtv : flight_series.gps_series) { - gtv_last = gtv; AltosGPS gps = gtv.gps; if (gps != null && gps.locked && @@ -57,6 +56,7 @@ public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, Alt map = new AltosUIMap(); map.show(gps, (int) flight_series.value_before(AltosFlightSeries.state_name, gtv.time)); this.gps = gps; + gtv_last = gtv; has_gps = true; } } diff --git a/altosuilib/AltosUIAccelCal.java b/altosuilib/AltosUIAccelCal.java new file mode 100644 index 00000000..af72a21d --- /dev/null +++ b/altosuilib/AltosUIAccelCal.java @@ -0,0 +1,249 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.altusmetrum.altosuilib_12; + +import java.awt.*; +import java.awt.event.*; +import java.beans.*; +import javax.swing.*; +import javax.swing.event.*; +import org.altusmetrum.altoslib_12.*; + +public class AltosUIAccelCal + extends AltosUIDialog + implements AltosAccelCalListener, ActionListener +{ + Frame owner; + AltosLink link; + AltosAccelCal cal; + AltosConfigValues config_values; + Thread thread; + Container pane; + JTextField message; + JButton antenna_up; + JButton antenna_down; + JButton ok; + JButton cancel; + boolean success; + int accel_plus, accel_minus; + + private void make_visible() { + pack(); + cal.start(); + setVisible(true); + } + + public boolean doit() { + success = false; + make_visible(); + return success; + } + + public int accel_cal_plus() { + if (success) + return accel_plus; + return AltosLib.MISSING; + } + + public int accel_cal_minus() { + if (success) + return accel_minus; + return AltosLib.MISSING; + } + + private void setDefaultButton(JButton button) { + this.getRootPane().setDefaultButton(button); + } + + /* AltosAccelCalListener interface */ + public void set_thread(AltosAccelCal cal, Thread thread) { + this.thread = thread; + } + + public void set_phase(AltosAccelCal cal, final int phase) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + switch (phase) { + case AltosAccelCal.phase_antenna_up: + message.setText("Orient antenna upwards and click on Antenna Up"); + antenna_up.setEnabled(true); + setDefaultButton(antenna_up); + antenna_down.setEnabled(false); + ok.setEnabled(false); + break; + case AltosAccelCal.phase_antenna_down: + message.setText("Orient antenna downwards and click on Antenna Down"); + antenna_up.setEnabled(false); + antenna_down.setEnabled(true); + setDefaultButton(antenna_down); + ok.setEnabled(false); + break; + } + } + }); + } + + public void cal_done(AltosAccelCal cal, int plus, int minus) { + accel_plus = plus; + accel_minus = minus; + success = true; + SwingUtilities.invokeLater(new Runnable() { + public void run() { + message.setText(String.format("Calibration succeeded, plus %d minus %d, press OK to continue", accel_plus, accel_minus)); + antenna_up.setEnabled(false); + antenna_down.setEnabled(false); + ok.setEnabled(true); + setDefaultButton(ok); + } + }); + } + + public void message(AltosAccelCal cal, final String msg) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + message.setText(msg); + } + }); + } + + public void error(AltosAccelCal cal, String msg) { + message(cal, msg); + } + + /* ActionListener interface */ + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + + if ("up".equals(cmd)) { + cal.signal(true); + antenna_up.setEnabled(false); + } else if ("down".equals(cmd)) { + cal.signal(true); + antenna_down.setEnabled(false); + this.setDefaultButton(antenna_down); + } else if ("ok".equals(cmd)) { + cal.signal(true); + this.setVisible(false); + if (success) { + config_values.set_accel_cal(accel_plus, accel_minus); + config_values.set_dirty(); + } + try { + cal.abort(); + } catch (InterruptedException ie) { + } + } else if ("cancel".equals(cmd)) { + cal.signal(false); + this.setVisible(false); + try { + cal.abort(); + } catch (InterruptedException ie) { + } + } + } + public AltosUIAccelCal(Frame owner, AltosLink link, AltosConfigValues config_values) { + super(owner, "Calibrate Accelerometer", true); + + this.owner = owner; + this.link = link; + this.config_values = config_values; + + pane = getContentPane(); + pane.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(4,4,4,4); + + int x = 0; + int y = 0; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.WEST; + c.gridx = x; + c.gridy = y; + c.gridwidth = 4; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + message = new JTextField(64); + pane.add(message, c); + + y++; x = 0; + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = x; + c.gridy = y; + c.gridwidth = 1; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + antenna_up = new JButton("Antenna Up"); + antenna_up.setActionCommand("up"); + antenna_up.setEnabled(false); + antenna_up.addActionListener(this); + pane.add(antenna_up, c); + + x++; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = x; + c.gridy = y; + c.gridwidth = 1; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + antenna_down = new JButton("Antenna Down"); + antenna_down.setActionCommand("down"); + antenna_down.setEnabled(false); + antenna_down.addActionListener(this); + pane.add(antenna_down, c); + + x++; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = x; + c.gridy = y; + c.gridwidth = 1; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + ok = new JButton("OK"); + ok.setActionCommand("ok"); + ok.setEnabled(false); + ok.addActionListener(this); + pane.add(ok, c); + + x++; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = x; + c.gridy = y; + c.gridwidth = 1; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + cancel = new JButton("Cancel"); + cancel.setActionCommand("cancel"); + cancel.setEnabled(true); + cancel.addActionListener(this); + pane.add(cancel, c); + + cal = new AltosAccelCal(this.link, this); + } +} diff --git a/altosuilib/Makefile.am b/altosuilib/Makefile.am index 4b5eb524..ce86d21e 100644 --- a/altosuilib/Makefile.am +++ b/altosuilib/Makefile.am @@ -13,6 +13,7 @@ altosuilib_JAVA = \ AltosDevice.java \ AltosDeviceDialog.java \ AltosPositionListener.java \ + AltosUIAccelCal.java \ AltosUIConfigure.java \ AltosUIAxis.java \ AltosUIDataMissing.java \ diff --git a/ao-bringup/test-telegps b/ao-bringup/test-telegps-v1 index 0b275802..0b275802 100755 --- a/ao-bringup/test-telegps +++ b/ao-bringup/test-telegps-v1 diff --git a/ao-bringup/test-telegps-v2 b/ao-bringup/test-telegps-v2 new file mode 100755 index 00000000..b103aed4 --- /dev/null +++ b/ao-bringup/test-telegps-v2 @@ -0,0 +1,52 @@ +#!/bin/sh + +VERSION=2.0 +PRODUCT=TeleGPS +BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'` + +echo "$PRODUCT-v$VERSION Test Program" +echo "Copyright 2014 by Bdale Garbee. Released under GPL v2" +echo +echo "Expectations:" +echo "\t$PRODUCT v$VERSION powered from USB" +echo + +ret=1 +ao-list | while read product serial dev; do + case "$product" in + "$PRODUCT-v$VERSION") + + echo "Testing $product $serial $dev" + + FLASHSIZE=2097152 + + echo "Testing flash" + ../ao-tools/ao-test-flash/ao-test-flash --tty="$dev" "$FLASHSIZE" + + case $? in + 0) + ;; + *) + echo "failed" + exit 1 + esac + + echo "Testing GPS" + ../ao-tools/ao-test-gps/ao-test-gps --tty="$dev" + + case $? in + 0) + ;; + *) + echo "failed" + exit 1 + esac + + echo "$PRODUCT-v$VERSION" serial "$serial" passed functional tests + ret=0 + ;; + *) + echo "Skipping $product $serial $dev" + ;; + esac +done diff --git a/ao-bringup/turnon_telebt b/ao-bringup/turnon_telebt index 912ba459..fb8318b3 100755 --- a/ao-bringup/turnon_telebt +++ b/ao-bringup/turnon_telebt @@ -80,7 +80,7 @@ else fi echo -n "checking BTLE functionality... " -btdev=`sudo timeout -s SIGINT 5s hcitool lescan | awk -F \- '/TeleBT/ { print $2 }'` +btdev=`sudo timeout -s SIGINT 5s hcitool lescan | awk -F \- '/TeleBT/ { print $2 }' | head -n 1` if [ "$btdev" = "$SERIAL" ]; then echo "working!" else diff --git a/ao-bringup/turnon_telegps b/ao-bringup/turnon_telegps index b6da2898..fd879abd 100755 --- a/ao-bringup/turnon_telegps +++ b/ao-bringup/turnon_telegps @@ -1,12 +1,10 @@ #!/bin/sh -if [ -x ../ao-tools/ao-flash/ao-flash-lpc ]; then - FLASH_LPC=../ao-tools/ao-flash/ao-flash-lpc -elif [ -x /usr/bin/ao-flash-lpc ]; then - FLASH_LPC=/usr/bin/ao-flash-lpc +if [ -x /usr/bin/dfu-util ]; then + DFU_UTIL=/usr/bin/dfu-util else - echo "Can't find ao-flash-lpc! Aborting." - exit 1 + echo "Can't find dfu-util! Aborting." + exit 1 fi if [ -x /usr/bin/ao-usbload ]; then @@ -17,16 +15,17 @@ else fi PRODUCT=TeleGPS -VERSION=1.0 -BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'` -echo $FILE +VERSION=2.0 +REPO=~/altusmetrumllc/Binaries + +#BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'` +#echo $FILE echo "$PRODUCT v$VERSION Turn-On and Calibration Program" -echo "Copyright 2014 by Bdale Garbee. Released under GPL v2" +echo "Copyright 2017 by Bdale Garbee. Released under GPL v3+" echo echo "Expectations:" -echo "\t$PRODUCT v$VERSION powered from USB" -echo "\t\twith ST-Link-V2 cabled to debug header" +echo "\t$PRODUCT v$VERSION powered from / attached to USB on this computer" echo case $# in @@ -47,35 +46,31 @@ esac # # Use released versions of everything # -FLASH_FILE=~/altusmetrumllc/Binaries/loaders/telegps-v1.0-altos-flash-*.elf -ALTOS_FILE=~/altusmetrumllc/Binaries/telegps-v1.0-*.elf - -echo $FLASH_LPC $FLASH_FILE +FLASH_FILE=$REPO/loaders/telegps-v2.0-altos-flash-*.bin +ALTOS_FILE=$REPO/telegps-v2.0-*.elf -$FLASH_LPC $FLASH_FILE || exit 1 +$DFU_UTIL -a 0 -s 0x08000000:leave -D $FLASH_FILE || exit 1 sleep 2 -echo $USBLOAD $ALTOS_FILE - $USBLOAD --serial=$SERIAL $ALTOS_FILE || exit 1 -sleep 2 +sleep 3 -dev=`ao-list | awk '/TeleGPS-v'"$VERSION"'/ { print $3; exit(0); }'` +dev=`ao-list | awk '/'"$PRODUCT"'-v'"$VERSION"'/ { print $3; exit(0); }'` case "$dev" in /dev/tty*) - echo "TeleGPS found on $dev" + echo "$PRODUCT found on $dev" ;; *) - echo 'No TeleGPS-v'"$VERSION"' found' + echo 'No '"$PRODUCT"'-v'"$VERSION"' found' exit 1 ;; esac SERIAL=$SERIAL ./cal-freq $dev -./test-telegps +./test-telegps-v2 exit $? diff --git a/ao-bringup/turnon_telegps_v1 b/ao-bringup/turnon_telegps_v1 new file mode 100755 index 00000000..5341acc7 --- /dev/null +++ b/ao-bringup/turnon_telegps_v1 @@ -0,0 +1,81 @@ +#!/bin/sh + +if [ -x ../ao-tools/ao-flash/ao-flash-lpc ]; then + FLASH_LPC=../ao-tools/ao-flash/ao-flash-lpc +elif [ -x /usr/bin/ao-flash-lpc ]; then + FLASH_LPC=/usr/bin/ao-flash-lpc +else + echo "Can't find ao-flash-lpc! Aborting." + exit 1 +fi + +if [ -x /usr/bin/ao-usbload ]; then + USBLOAD=/usr/bin/ao-usbload +else + echo "Can't find ao-usbload! Aborting." + exit 1 +fi + +PRODUCT=TeleGPS +VERSION=1.0 +BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'` +echo $FILE + +echo "$PRODUCT v$VERSION Turn-On and Calibration Program" +echo "Copyright 2014 by Bdale Garbee. Released under GPL v2" +echo +echo "Expectations:" +echo "\t$PRODUCT v$VERSION powered from USB" +echo "\t\twith ST-Link-V2 cabled to debug header" +echo + +case $# in + 1) + SERIAL="$1" + echo "$PRODUCT-$VERSION serial number: $SERIAL" + ;; + 0) + echo -n "$PRODUCT-$VERSION serial number: " + read SERIAL + ;; + *) + echo "Usage: $0 <serial-number>" 1>&2 + exit 1; + ;; +esac + +# +# Use released versions of everything +# +FLASH_FILE=~/altusmetrumllc/Binaries/loaders/telegps-v1.0-altos-flash-*.elf +ALTOS_FILE=~/altusmetrumllc/Binaries/telegps-v1.0-*.elf + +echo $FLASH_LPC $FLASH_FILE + +$FLASH_LPC $FLASH_FILE || exit 1 + +sleep 2 + +echo $USBLOAD $ALTOS_FILE + +$USBLOAD --serial=$SERIAL $ALTOS_FILE || exit 1 + +sleep 2 + +dev=`ao-list | awk '/TeleGPS-v'"$VERSION"'/ { print $3; exit(0); }'` + +case "$dev" in +/dev/tty*) + echo "TeleGPS found on $dev" + ;; +*) + echo 'No TeleGPS-v'"$VERSION"' found' + exit 1 + ;; +esac + +SERIAL=$SERIAL ./cal-freq $dev + +./test-telegps-v1 + +exit $? diff --git a/ao-tools/ao-chaosread/Makefile.am b/ao-tools/ao-chaosread/Makefile.am index 581eb2d2..6ba8885c 100644 --- a/ao-tools/ao-chaosread/Makefile.am +++ b/ao-tools/ao-chaosread/Makefile.am @@ -1,6 +1,6 @@ bin_PROGRAMS=ao-chaosread -AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) +AM_CFLAGS=$(LIBUSB_CFLAGS) -Wall -Wextra ao_chaosread_LDADD=$(LIBUSB_LIBS) diff --git a/ao-tools/ao-chaosread/ao-chaosread.c b/ao-tools/ao-chaosread/ao-chaosread.c index 7808f6c9..6d860139 100644 --- a/ao-tools/ao-chaosread/ao-chaosread.c +++ b/ao-tools/ao-chaosread/ao-chaosread.c @@ -74,7 +74,7 @@ chaoskey_match(libusb_device *dev, char *match_serial) goto out; } - ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, device_serial, match_len + 1); + ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, (unsigned char *) device_serial, match_len + 1); if (ret < 0) { fprintf(stderr, "failed to get serial number: %s\n", libusb_strerror(ret)); @@ -103,7 +103,6 @@ chaoskey_open(char *serial) int ret; ssize_t num; libusb_device **list; - libusb_device *device = NULL; int d; ck = calloc(sizeof (struct chaoskey), 1); @@ -173,12 +172,6 @@ chaoskey_close(struct chaoskey *ck) free(ck); } -void -chaoskey_transfer_callback(struct libusb_transfer *transfer) -{ - struct chaoskey *ck = transfer->user_data; -} - #define ENDPOINT 0x86 int @@ -202,7 +195,9 @@ chaoskey_read(struct chaoskey *ck, void *buffer, int len) } len -= transferred; buf += transferred; + total += transferred; } + return total; } static const struct option options[] = { @@ -283,8 +278,17 @@ main (int argc, char **argv) int i; for (i = 0; i < got / 2; i++) putchar((buf[i] >> 1 & 0xff)); - } else - write(1, buf, got); + } else { + int i; + int ret; + for (i = 0; i < got; i += ret) { + ret = write(1, ((char *) buf) + i, got - i); + if (ret <= 0) { + perror("write"); + exit(1); + } + } + } length -= got; } exit(0); diff --git a/configure.ac b/configure.ac index dc80f6e3..2bf6c7e3 100644 --- a/configure.ac +++ b/configure.ac @@ -18,13 +18,13 @@ dnl dnl Process this file with autoconf to create configure. AC_PREREQ(2.57) -AC_INIT([altos], 1.8.1) -ANDROID_VERSION=15 +AC_INIT([altos], 1.8.2) +ANDROID_VERSION=16 AC_CONFIG_SRCDIR([src/kernel/ao.h]) AM_INIT_AUTOMAKE([foreign dist-bzip2]) AM_MAINTAINER_MODE -RELEASE_DATE=2017-08-27 +RELEASE_DATE=2017-09-18 AC_SUBST(RELEASE_DATE) VERSION_DASH=`echo $VERSION | sed 's/\./-/g'` diff --git a/doc/Makefile b/doc/Makefile index 5b264e02..b1bff848 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -3,6 +3,7 @@ # RELNOTES_INC=\ + release-notes-1.8.2.inc \ release-notes-1.8.1.inc \ release-notes-1.8.inc \ release-notes-1.7.inc \ diff --git a/doc/altusmetrum-docinfo.xml b/doc/altusmetrum-docinfo.xml index 595422f1..c2bc14d1 100644 --- a/doc/altusmetrum-docinfo.xml +++ b/doc/altusmetrum-docinfo.xml @@ -47,6 +47,14 @@ <revhistory> <?dbhtml filename="altusmetrum-revhistory.html"?> <revision> + <revnumber>1.8.2</revnumber> + <date>18 Sep 2017</date> + <revremark> + Support TeleGPS v2.0 hardware. Add accelerometer recalibration + UI. + </revremark> + </revision> + <revision> <revnumber>1.8.1</revnumber> <date>27 Aug 2017</date> <revremark> diff --git a/doc/config-device.inc b/doc/config-device.inc index 35848882..99d5c008 100644 --- a/doc/config-device.inc +++ b/doc/config-device.inc @@ -206,6 +206,22 @@ ifdef::telegps[] in the log. endif::telegps[] +ifdef::telemega,easymega,telemetrum[] + + ==== Calibrate Accelerometer + + This opens a separate window to recalibrate the + accelerometers. Follow the instructions, orienting the + flight computer with the antenna end, or end opposite + the screw terminals, in the case of EasyMega, first up + and then down. + + When the calibration is complete, return to the + Configure Altimeter window and save the new + calibration values. + +endif::telemega,easymega,telemetrum[] + ifdef::telemega,easymega[] ==== Configure Pyro Channels diff --git a/doc/release-notes-1.8.2.inc b/doc/release-notes-1.8.2.inc new file mode 100644 index 00000000..2923ec11 --- /dev/null +++ b/doc/release-notes-1.8.2.inc @@ -0,0 +1,28 @@ += Release Notes for Version 1.8.2 +:toc!: +:doctype: article + + Version 1.8.2 includes support for TeleGPS version 2.0 along + with accelerometer recalibration support in AltosUI. + + 1.8.2 also contains a couple of minor fixes for AltosUI when + analyzing saved data files. + + == AltOS + + AltOS New Features + + * Support for TeleGPS version 2.0 hardware. + + == AltosUI and TeleGPS Applications + + AltosUI and TeleGPS New Features + + * Support for TeleGPS version 2.0. + + * Accelerometer re-calibration user interface. + + AltosUI and TeleGPS Bug Fixes + + * Prevent some crashes when reading older saved flight data + for graphing or KML export. diff --git a/doc/release-notes.inc b/doc/release-notes.inc index adcf57ed..a102b2dc 100644 --- a/doc/release-notes.inc +++ b/doc/release-notes.inc @@ -2,6 +2,10 @@ == Release Notes :leveloffset: 2 + include::release-notes-1.8.2.raw[] + + <<<< + :leveloffset: 2 include::release-notes-1.8.1.raw[] <<<< diff --git a/doc/usage.inc b/doc/usage.inc index 29587b7e..d010f398 100644 --- a/doc/usage.inc +++ b/doc/usage.inc @@ -238,14 +238,16 @@ ifdef::radio[disabled, and the radio goes into transmit-only mode.] ifndef::radio[disabled.] The only way to get out of this - mode is to power the flight computer down. + mode is to power the flight computer down. See below for how to get the flight + computer to come up in Flight/Pad mode at power on. Idle:: The flight computer is ready to communicate over USB ifdef::radio[and in packet mode over the radio.] You can configure the flight computer, download data or display - the current state. + the current state. See below for how to get the flight + computer to come up in Idle mode at power on. ifdef::telemetrum,easymega,telemega[] For flight computers with accelerometers (TeleMetrum, diff --git a/src/Makefile b/src/Makefile index 25e43a0e..661fd333 100644 --- a/src/Makefile +++ b/src/Makefile @@ -35,6 +35,7 @@ ARMM3DIRS=\ megadongle-v0.1 megadongle-v0.1/flash-loader \ telegps-v0.3 telegps-v0.3/flash-loader \ telegps-v1.0 telegps-v1.0/flash-loader \ + telegps-v2.0 telegps-v2.0/flash-loader \ telelco-v0.2 telelco-v0.2/flash-loader \ telelco-v0.3 telelco-v0.3/flash-loader \ telescience-v0.2 telescience-v0.2/flash-loader \ diff --git a/src/drivers/ao_trng_send.c b/src/drivers/ao_trng_send.c index b1227aaa..7cda053d 100644 --- a/src/drivers/ao_trng_send.c +++ b/src/drivers/ao_trng_send.c @@ -153,10 +153,20 @@ ao_trng_send(void) ao_crc_reset(); - ao_delay(TRNG_ENABLE_DELAY); - for (s = 0; s < AO_TRNG_START_WAIT; s++) { - if (ao_trng_get_cooked(buffer[0])) + int i; + uint16_t min, max; + uint16_t buf[AO_USB_IN_SIZE>>1]; + + ao_trng_get_raw(buf); + min = max = buf[0]; + for (i = 1; i < (AO_USB_IN_SIZE>>1); i++) { + uint16_t v = buf[i]; + if (v < min) min = v; + if (v > max) max = v; + } + /* Wait for at least 10 bits of range */ + if ((uint16_t) (max - min) >= 1024) break; ao_delay(AO_MS_TO_TICKS(10)); } diff --git a/src/kernel/ao_pyro.c b/src/kernel/ao_pyro.c index a0881f9e..9543b3ef 100644 --- a/src/kernel/ao_pyro.c +++ b/src/kernel/ao_pyro.c @@ -181,7 +181,7 @@ ao_pyro_ready(struct ao_pyro *pyro) case ao_pyro_state_greater_or_equal: if (ao_flight_state >= pyro->state_greater_or_equal) continue; - DBG("state %d >= %d\n", ao_flight_state, pyro->state_less); + DBG("state %d < %d\n", ao_flight_state, pyro->state_greater_or_equal); break; default: diff --git a/src/telegps-v2.0/ao_pins.h b/src/telegps-v2.0/ao_pins.h index f92564d6..fa175371 100644 --- a/src/telegps-v2.0/ao_pins.h +++ b/src/telegps-v2.0/ao_pins.h @@ -33,11 +33,11 @@ #define IS_FLASH_LOADER 0 #define HAS_BEEP 0 -#define AO_HSE 32000000 +#define AO_HSE 16000000 #define AO_RCC_CFGR_PLLMUL STM_RCC_CFGR_PLLMUL_3 -#define AO_RCC_CFGR2_PLLDIV STM_RCC_CFGR2_PREDIV_2 +#define AO_RCC_CFGR2_PLLDIV STM_RCC_CFGR2_PREDIV_1 #define AO_PLLMUL 3 -#define AO_PLLDIV 2 +#define AO_PLLDIV 1 /* HCLK = 48MHz */ #define AO_AHB_PRESCALER 1 @@ -50,6 +50,9 @@ #define HAS_USB 1 #define AO_USB_DIRECTIO 0 #define AO_PA11_PA12_RMP 1 +#define HAS_USB_CONNECT 1 +#define AO_USB_CONNECT_PORT (&stm_gpiob) +#define AO_USB_CONNECT_PIN 3 #define IS_FLASH_LOADER 0 @@ -110,6 +113,8 @@ struct ao_adc { #define HAS_SERIAL_2 1 #define SERIAL_2_PA2_PA3 1 #define USE_SERIAL_2_STDIN 0 +#define USE_SERIAL_2_FLOW 0 +#define USE_SERIAL_2_SW_FLOW 0 #define ao_gps_getchar ao_serial2_getchar #define ao_gps_putchar ao_serial2_putchar diff --git a/src/test/Makefile b/src/test/Makefile index a0c2d5fe..08808430 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -6,7 +6,10 @@ PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noi ao_aprs_test ao_micropeak_test ao_fat_test ao_aes_test ao_int64_test \ ao_ms5607_convert_test ao_quaternion_test ao_lisp_test -INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quaternion.h +INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quaternion.h ao_eeprom_read.h +TEST_SRC=ao_flight_test.c +TEST_SRC_ALL=ao_flight_test.c ao_eeprom_read.c ao_eeprom_read_old.c +TEST_LIB=-ljson-c KALMAN=make-kalman @@ -19,26 +22,26 @@ clean: install: -ao_flight_test: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h $(INCS) - cc $(CFLAGS) -o $@ $< +ao_flight_test: $(TEST_SRC_ALL) ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h $(INCS) + cc $(CFLAGS) -o $@ $(TEST_SRC) $(TEST_LIB) -ao_flight_test_noisy_accel: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS) - cc -DNOISY_ACCEL=1 $(CFLAGS) -o $@ $< +ao_flight_test_noisy_accel: $(TEST_SRC_ALL) ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS) + cc -DNOISY_ACCEL=1 $(CFLAGS) -o $@ $(TEST_SRC) $(TEST_LIB) -ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS) - cc $(CFLAGS) -o $@ -DHAS_ACCEL=0 ao_flight_test.c +ao_flight_test_baro: $(TEST_SRC_ALL) ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS) + cc $(CFLAGS) -o $@ -DHAS_ACCEL=0 $(TEST_SRC) $(TEST_LIB) -ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS) - cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 ao_flight_test.c +ao_flight_test_accel: $(TEST_SRC_ALL) ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS) + cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 $(TEST_SRC) $(TEST_LIB) -ao_flight_test_mm: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS) - cc -DTELEMEGA=1 $(CFLAGS) -o $@ $< -lm +ao_flight_test_mm: $(TEST_SRC_ALL) ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS) + cc -DTELEMEGA=1 $(CFLAGS) -o $@ $(TEST_SRC) $(TEST_LIB) -lm -ao_flight_test_metrum: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS) - cc -DTELEMETRUM_V2=1 $(CFLAGS) -o $@ $< -lm +ao_flight_test_metrum: $(TEST_SRC_ALL) ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS) + cc -DTELEMETRUM_V2=1 $(CFLAGS) -o $@ $(TEST_SRC) $(TEST_LIB) -lm -ao_flight_test_mini: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS) - cc -DEASYMINI=1 -DHAS_ACCEL=0 $(CFLAGS) -o $@ $< -lm +ao_flight_test_mini: $(TEST_SRC_ALL) ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS) + cc -DEASYMINI=1 -DHAS_ACCEL=0 $(CFLAGS) -o $@ $(TEST_SRC) $(TEST_LIB) -lm ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h cc $(CFLAGS) -o $@ $< diff --git a/src/test/ao_eeprom_read.c b/src/test/ao_eeprom_read.c new file mode 100644 index 00000000..803ef36c --- /dev/null +++ b/src/test/ao_eeprom_read.c @@ -0,0 +1,262 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_eeprom_read.h" +#include <json-c/json.h> +#include <string.h> +#include <errno.h> + +static struct json_object * +ao_eeprom_read_config(FILE *file) +{ + char line[1024]; + struct json_tokener *tok; + struct json_object *obj = NULL; + enum json_tokener_error err; + + tok = json_tokener_new(); + if (!tok) + goto fail_tok; + + for (;;) { + if (fgets(line, sizeof(line), file) == NULL) + goto fail_read; + obj = json_tokener_parse_ex(tok, line, strlen(line)); + err = json_tokener_get_error(tok); + if (err == json_tokener_success) + break; + if (err != json_tokener_continue) + goto fail_read; + } + json_tokener_free(tok); + return obj; +fail_read: + json_tokener_free(tok); +fail_tok: + return NULL; +} + +static int +ao_eeprom_read_byte(FILE *file) +{ + int byte; + if (fscanf(file, "%x", &byte) != 1) + return EOF; + return byte; +} + +static int +ao_eeprom_read_data(FILE *file, struct ao_eeprom *eeprom) +{ + uint8_t *data = NULL, *ndata; + int len = 0; + int size = 0; + int byte; + + data = malloc(size = 64); + if (!data) + goto fail_alloc; + while ((byte = ao_eeprom_read_byte(file)) != EOF) { + if (len == size) { + ndata = realloc(data, size *= 2); + if (!ndata) + goto fail_realloc; + data = ndata; + } + data[len++] = (uint8_t) byte; + } + eeprom->data = data; + eeprom->len = len; + return 1; +fail_realloc: + free(data); +fail_alloc: + return 0; +} + +static int +ao_json_get_int(struct json_object *obj, const char *key, int def) +{ + struct json_object *value; + int i; + + if (!json_object_object_get_ex(obj, key, &value)) + return def; + errno = 0; + i = (int) json_object_get_int(value); + if (errno != 0) + return def; + return i; +} + +static const char * +ao_json_get_string(struct json_object *obj, const char *key, const char *def) +{ + struct json_object *value; + const char *str; + + if (!json_object_object_get_ex(obj, key, &value)) + return def; + errno = 0; + str = json_object_get_string(value); + if (errno) + return def; + if (!str) + return def; + return str; +} + +#if AO_PYRO_NUM +static int +ao_eeprom_get_pyro(struct ao_config *config, struct json_object *obj) +{ + struct json_object *pyros; + struct json_object *pyro; + int i, p; + + if (!json_object_object_get_ex(obj, "pyros", &pyros)) + return 1; + + if (json_object_get_type(pyros) != json_type_array) + return 0; + + for (i = 0; i < json_object_array_length(pyros); i++) { + pyro = json_object_array_get_idx(pyros, i); + if (pyro) { + p = ao_json_get_int(pyro, "channel", -1); + if (0 <= p && p < AO_PYRO_NUM) { + config->pyro[p].flags = ao_json_get_int(pyro, "flags", 0); + config->pyro[p].accel_less = ao_json_get_int(pyro, "accel_less", 0); + config->pyro[p].accel_greater = ao_json_get_int(pyro, "accel_greater", 0); + config->pyro[p].speed_less = ao_json_get_int(pyro, "speed_less", 0); + config->pyro[p].speed_greater = ao_json_get_int(pyro, "speed_greater", 0); + config->pyro[p].height_less = ao_json_get_int(pyro, "height_less", 0); + config->pyro[p].height_greater = ao_json_get_int(pyro, "height_greater", 0); + config->pyro[p].orient_less = ao_json_get_int(pyro, "orient_less", 0); + config->pyro[p].orient_greater = ao_json_get_int(pyro, "orient_greater", 0); + config->pyro[p].time_less = ao_json_get_int(pyro, "time_less", 0); + config->pyro[p].time_greater = ao_json_get_int(pyro, "time_greater", 0); + config->pyro[p].delay = ao_json_get_int(pyro, "delay", 0); + config->pyro[p].state_less = ao_json_get_int(pyro, "state_less", 0); + config->pyro[p].state_greater_or_equal = ao_json_get_int(pyro, "state_greater_or_equal", 0); + config->pyro[p].motor = ao_json_get_int(pyro, "motor", 0); + } + } + } + return 1; +} +#endif + +static int +ao_eeprom_get_ms5607(struct ao_ms5607_prom *ms5607_prom, struct json_object *obj) +{ + struct json_object *ms5607; + + if (!json_object_object_get_ex(obj, "ms5607", &ms5607)) + return 1; + + if (json_object_get_type(ms5607) != json_type_object) + return 0; + + ms5607_prom->reserved = ao_json_get_int(ms5607, "reserved", 0); + ms5607_prom->sens = ao_json_get_int(ms5607, "sens", 0); + ms5607_prom->off = ao_json_get_int(ms5607, "off", 0); + ms5607_prom->tcs = ao_json_get_int(ms5607, "tcs", 0); + ms5607_prom->tco = ao_json_get_int(ms5607, "tco", 0); + ms5607_prom->tref = ao_json_get_int(ms5607, "tref", 0); + ms5607_prom->tempsens = ao_json_get_int(ms5607, "tempsens", 0); + ms5607_prom->crc = ao_json_get_int(ms5607, "crc", 0); + return 1; +} + +static int +ao_eeprom_get_config(struct ao_eeprom *ao_eeprom, struct json_object *obj) +{ + struct ao_config *config = &ao_eeprom->config; + const char *s; + + if (json_object_get_type(obj) != json_type_object) + return 0; + + ao_eeprom->log_format = ao_json_get_int(obj, "log_format", 0); + ao_eeprom->serial_number = ao_json_get_int(obj, "serial", 0); + + config->major = ao_json_get_int(obj, "config_major", 0); + config->minor = ao_json_get_int(obj, "config_minor", 0); + if (config->major == 0 || config->minor == 0) + return 0; + + config->main_deploy = ao_json_get_int(obj, "main_deploy", 250); + config->accel_plus_g = ao_json_get_int(obj, "accel_cal_plus", 0); + + s = ao_json_get_string(obj, "callsign", "N0CALL"); + strncpy(config->callsign, s, sizeof(config->callsign)); + + config->apogee_delay = ao_json_get_int(obj, "apogee_delay", 0); + config->accel_minus_g = ao_json_get_int(obj, "accel_cal_minus", 0); + config->radio_cal = ao_json_get_int(obj, "radio_calibration", 0); + config->flight_log_max = ao_json_get_int(obj, "flight_log_max", 0); + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + config->pad_orientation = ao_json_get_int(obj, "pad_orientation", 0); + config->radio_setting = ao_json_get_int(obj, "radio_setting", 0); + config->radio_enable = ao_json_get_int(obj, "radio_enable", 1); + config->frequency = ao_json_get_int(obj, "frequency", 434550); + config->apogee_lockout = ao_json_get_int(obj, "apogee_lockout", 0); +#if AO_PYRO_NUM + if (!ao_eeprom_get_pyro(config, obj)) + return 0; +#endif + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + + if (!ao_eeprom_get_ms5607(&ao_eeprom->ms5607_prom, obj)) + return 0; + + return 1; +} + +struct ao_eeprom * +ao_eeprom_read(FILE *file) +{ + struct ao_eeprom *ao_eeprom; + struct json_object *obj; + int ret; + + ao_eeprom = calloc(1, sizeof (struct ao_eeprom)); + if (!ao_eeprom) + goto fail_ao_eeprom; + + obj = ao_eeprom_read_config(file); + if (!obj) + goto fail_config; + + ret = ao_eeprom_get_config(ao_eeprom, obj); + json_object_put(obj); + if (!ret) + goto fail_config; + + if (!ao_eeprom_read_data(file, ao_eeprom)) + goto fail_data; + + return ao_eeprom; +fail_data: +fail_config: + free(ao_eeprom); +fail_ao_eeprom: + return NULL; +} diff --git a/src/test/ao_eeprom_read.h b/src/test/ao_eeprom_read.h new file mode 100644 index 00000000..03c327ca --- /dev/null +++ b/src/test/ao_eeprom_read.h @@ -0,0 +1,47 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_EEPROM_READ_H_ +#define _AO_EEPROM_READ_H_ + +#define __pdata +#define __data +#define __xdata +#define __code +#define __reentrant + +#include <stdint.h> +#include <stdio.h> +#include <ao_telemetry.h> +#include <ao_config.h> +#include <ao_ms5607.h> +#include <ao_log.h> + +struct ao_eeprom { + struct ao_config config; + struct ao_ms5607_prom ms5607_prom; + int log_format; + uint16_t serial_number; + uint8_t *data; + uint32_t len; + uint32_t size; +}; + +struct ao_eeprom *ao_eeprom_read(FILE *file); + +struct ao_eeprom *ao_eeprom_read_old(FILE *file); + +void ao_eeprom_free_data(struct ao_eeprom *ao_eeprom); + +#endif /* _AO_EEPROM_READ_H_ */ diff --git a/src/test/ao_eeprom_read_old.c b/src/test/ao_eeprom_read_old.c new file mode 100644 index 00000000..c66ffae5 --- /dev/null +++ b/src/test/ao_eeprom_read_old.c @@ -0,0 +1,172 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao_eeprom_read.h" +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +static int +ao_eeprom_add_u8(struct ao_eeprom *ao_eeprom, uint8_t byte) +{ + if (ao_eeprom->len == ao_eeprom->size) { + uint32_t nsize = ao_eeprom->size * 2; + uint8_t *ndata = realloc(ao_eeprom->data, nsize); + if (!ndata) + return 0; + ao_eeprom->data = ndata; + ao_eeprom->size = nsize; + } + ao_eeprom->data[ao_eeprom->len++] = byte; + return 1; +} + +static int +ao_eeprom_add_u16(struct ao_eeprom *ao_eeprom, uint16_t u16) +{ + if (!ao_eeprom_add_u8(ao_eeprom, u16 & 0xff)) + return 0; + + return ao_eeprom_add_u8(ao_eeprom, u16 >> 8); +} + +struct ao_eeprom * +ao_eeprom_read_old(FILE *file) +{ + struct ao_eeprom *ao_eeprom; + char line[1024]; + char *l; + + ao_eeprom = calloc(1, sizeof (struct ao_eeprom)); + if (!ao_eeprom) + return NULL; + + ao_eeprom->log_format = -1; + ao_eeprom->size = 64; + ao_eeprom->data = malloc(ao_eeprom->size); + if (!ao_eeprom->data) { + free(ao_eeprom); + return NULL; + } + while (fgets(line, sizeof(line), file) != NULL) { + int nword; + char *words[64]; + char *saveptr; + l = line; + for (nword = 0; nword < 64; nword++) { + words[nword] = strtok_r(l, " \t\n", &saveptr); + l = NULL; + if (words[nword] == NULL) + break; + } + if (((ao_eeprom->log_format == AO_LOG_FORMAT_TELEMEGA_OLD || ao_eeprom->log_format == AO_LOG_FORMAT_TELEMEGA) && nword == 30 && strlen(words[0]) == 1) || + ((ao_eeprom->log_format == AO_LOG_FORMAT_EASYMINI1 || ao_eeprom->log_format == AO_LOG_FORMAT_EASYMINI2) && nword == 14 && strlen(words[0]) == 1) || + (ao_eeprom->log_format == AO_LOG_FORMAT_TELEMETRUM && nword == 14 && strlen(words[0]) == 1)) + { + int i; + uint8_t type; + uint16_t tick; + + type = words[0][0]; + tick = strtoul(words[1], NULL, 16); + ao_eeprom_add_u8(ao_eeprom, type); + ao_eeprom_add_u8(ao_eeprom, 0); /* checksum */ + ao_eeprom_add_u16(ao_eeprom, tick); + for (i = 2; i < nword; i++) + ao_eeprom_add_u8(ao_eeprom, strtoul(words[i], NULL, 16)); + } + else if (nword == 4 && strlen(words[0]) == 1) { + uint8_t type; + uint16_t tick, a, b; + type = words[0][0]; + tick = strtoul(words[1], NULL, 16); + a = strtoul(words[2], NULL, 16); + b = strtoul(words[3], NULL, 16); + if (type == 'P') + type = 'A'; + ao_eeprom_add_u8(ao_eeprom, type); + ao_eeprom_add_u8(ao_eeprom, 0); /* checksum */ + ao_eeprom_add_u16(ao_eeprom, tick); + ao_eeprom_add_u16(ao_eeprom, a); + ao_eeprom_add_u16(ao_eeprom, b); + } + else if (nword == 3 && strcmp(words[0], "ms5607") == 0) { + if (strcmp(words[1], "reserved:") == 0) + ao_eeprom->ms5607_prom.reserved = strtoul(words[2], NULL, 10); + else if (strcmp(words[1], "sens:") == 0) + ao_eeprom->ms5607_prom.sens = strtoul(words[2], NULL, 10); + else if (strcmp(words[1], "off:") == 0) + ao_eeprom->ms5607_prom.off = strtoul(words[2], NULL, 10); + else if (strcmp(words[1], "tcs:") == 0) + ao_eeprom->ms5607_prom.tcs = strtoul(words[2], NULL, 10); + else if (strcmp(words[1], "tco:") == 0) + ao_eeprom->ms5607_prom.tco = strtoul(words[2], NULL, 10); + else if (strcmp(words[1], "tref:") == 0) + ao_eeprom->ms5607_prom.tref = strtoul(words[2], NULL, 10); + else if (strcmp(words[1], "tempsens:") == 0) + ao_eeprom->ms5607_prom.tempsens = strtoul(words[2], NULL, 10); + else if (strcmp(words[1], "crc:") == 0) + ao_eeprom->ms5607_prom.crc = strtoul(words[2], NULL, 10); + continue; + } +#if AO_NUM_PYRO + else if (nword >= 3 && strcmp(words[0], "Pyro") == 0) { + int p = strtoul(words[1], NULL, 10); + int i, j; + struct ao_pyro *pyro = &ao_eeprom->config.pyro[p]; + + for (i = 2; i < nword; i++) { + for (j = 0; j < NUM_PYRO_VALUES; j++) + if (!strcmp (words[i], ao_pyro_values[j].name)) + break; + if (j == NUM_PYRO_VALUES) + continue; + pyro->flags |= ao_pyro_values[j].flag; + if (ao_pyro_values[j].offset != NO_VALUE && i + 1 < nword) { + int16_t val = strtoul(words[++i], NULL, 10); + printf("pyro %d condition %s value %d\n", p, words[i-1], val); + *((int16_t *) ((char *) pyro + ao_pyro_values[j].offset)) = val; + } + } + } +#endif + else if (nword == 2 && strcmp(words[0], "log-format") == 0) { + ao_eeprom->log_format = strtoul(words[1], NULL, 10); + } else if (nword == 2 && strcmp(words[0], "serial-number") == 0) { + ao_eeprom->serial_number = strtoul(words[1], NULL, 10); + } else if (nword >= 6 && strcmp(words[0], "Accel") == 0) { + ao_eeprom->config.accel_plus_g = atoi(words[3]); + ao_eeprom->config.accel_minus_g = atoi(words[5]); +#if HAS_GYRO + } else if (nword >= 8 && strcmp(words[0], "IMU") == 0) { + ao_eeprom->config.accel_zero_along = atoi(words[3]); + ao_eeprom->config.accel_zero_across = atoi(words[5]); + ao_eeprom->config.accel_zero_through = atoi(words[7]); +#endif + } else if (nword >= 4 && strcmp(words[0], "Main") == 0) { + ao_eeprom->config.main_deploy = atoi(words[2]); + } else if (nword >= 3 && strcmp(words[0], "Apogee") == 0 && + strcmp(words[1], "lockout:") == 0) { + ao_eeprom->config.apogee_lockout = atoi(words[2]); + } else if (nword >= 3 && strcmp(words[0], "Pad") == 0 && + strcmp(words[1], "orientation:") == 0) { + ao_eeprom->config.pad_orientation = atoi(words[2]); + } + } + return ao_eeprom; +} + diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index 55bfe410..298848d6 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -191,7 +191,7 @@ ao_distance_from_pad(void) double dist, bearing; if (!ao_gps_count) return 0; - + cc_great_circle(ao_gps_first.latitude / 1e7, ao_gps_first.longitude / 1e7, ao_gps_static.latitude / 1e7, @@ -308,6 +308,9 @@ struct ao_task { int ao_flight_debug; +struct ao_eeprom *eeprom; +uint32_t eeprom_offset; + FILE *emulator_in; char *emulator_app; char *emulator_name; @@ -341,14 +344,18 @@ struct ao_cmds { #include <ao_ms5607.h> struct ao_ms5607_prom ao_ms5607_prom; #include "ao_ms5607_convert.c" +#if TELEMEGA #define AO_PYRO_NUM 4 #include <ao_pyro.h> +#endif #else #include "ao_convert.c" #endif #include <ao_config.h> #include <ao_fake_flight.h> +#include <ao_eeprom_read.h> +#include <ao_log.h> #define ao_config_get() @@ -401,12 +408,16 @@ ao_pyro_pin_set(uint8_t pin, uint8_t value) #include "ao_pyro.c" #endif +#include "ao_eeprom_read.c" +#include "ao_eeprom_read_old.c" #define to_double(f) ((f) / 65536.0) static int ao_records_read = 0; static int ao_eof_read = 0; +#if !EASYMINI static int ao_flight_ground_accel; +#endif static int ao_flight_started = 0; static int ao_test_max_height; static double ao_test_max_height_time; @@ -418,11 +429,18 @@ static double ao_test_landed_time; static int landed_set; static double landed_time; static double landed_height; +#if AO_PYRO_NUM +static uint16_t pyros_fired; +#endif #if HAS_MPU6000 static struct ao_mpu6000_sample ao_ground_mpu6000; #endif +#if HAS_ACCEL +int ao_error_h_sq_avg; +#endif + void ao_test_exit(void) { @@ -567,7 +585,7 @@ ao_insert(void) ao_quaternion_normalize(&ao_mag, &ao_mag); ao_quaternion_rotate(&ao_mag_rot, &ao_mag, &ao_rotation); - + float ao_dot; int ao_mag_angle; @@ -722,17 +740,6 @@ void ao_sleep(void *wchan) { if (wchan == &ao_data_head) { - char type = 0; - uint16_t tick = 0; - uint16_t a = 0, b = 0; - uint8_t bytes[1024]; - union ao_telemetry_all telem; - char line[1024]; - char *saveptr; - char *l; - char *words[64]; - int nword; - #if TELEMEGA if (ao_flight_state >= ao_flight_boost && ao_flight_state < ao_flight_landed) ao_pyro_check(); @@ -752,419 +759,183 @@ ao_sleep(void *wchan) return; } - if (!fgets(line, sizeof (line), emulator_in)) { - if (++ao_eof_read >= 1000) { - if (!ao_summary) - printf ("no more data, exiting simulation\n"); - ao_test_exit(); - } - ao_data_static.tick += 10; - ao_insert(); - return; - } - l = line; - for (nword = 0; nword < 64; nword++) { - words[nword] = strtok_r(l, " \t\n", &saveptr); - l = NULL; - if (words[nword] == NULL) - break; - } + if (eeprom) { #if TELEMEGA - if ((log_format == AO_LOG_FORMAT_TELEMEGA_OLD || log_format == AO_LOG_FORMAT_TELEMEGA) && nword == 30 && strlen(words[0]) == 1) { - int i; - struct ao_ms5607_value value; - - type = words[0][0]; - tick = strtoul(words[1], NULL, 16); -// printf ("%c %04x", type, tick); - for (i = 2; i < nword; i++) { - bytes[i - 2] = strtoul(words[i], NULL, 16); -// printf(" %02x", bytes[i-2]); - } -// printf ("\n"); - switch (type) { - case 'F': - ao_flight_number = uint16(bytes, 0); - ao_flight_ground_accel = int16(bytes, 2); - ao_flight_started = 1; - ao_ground_pres = int32(bytes, 4); - ao_ground_height = ao_pa_to_altitude(ao_ground_pres); - ao_ground_accel_along = int16(bytes, 8); - ao_ground_accel_across = int16(bytes, 10); - ao_ground_accel_through = int16(bytes, 12); - ao_ground_roll = int16(bytes, 14); - ao_ground_pitch = int16(bytes, 16); - ao_ground_yaw = int16(bytes, 18); - ao_ground_mpu6000.accel_x = ao_ground_accel_across; - ao_ground_mpu6000.accel_y = ao_ground_accel_along; - ao_ground_mpu6000.accel_z = ao_ground_accel_through; - ao_ground_mpu6000.gyro_x = ao_ground_pitch >> 9; - ao_ground_mpu6000.gyro_y = ao_ground_roll >> 9; - ao_ground_mpu6000.gyro_z = ao_ground_yaw >> 9; - break; - case 'A': - ao_data_static.tick = tick; - ao_data_static.ms5607_raw.pres = int32(bytes, 0); - ao_data_static.ms5607_raw.temp = int32(bytes, 4); - ao_ms5607_convert(&ao_data_static.ms5607_raw, &value); - ao_data_static.mpu6000.accel_x = int16(bytes, 8); - ao_data_static.mpu6000.accel_y = int16(bytes, 10); - ao_data_static.mpu6000.accel_z = int16(bytes, 12); - ao_data_static.mpu6000.gyro_x = int16(bytes, 14); - ao_data_static.mpu6000.gyro_y = int16(bytes, 16); - ao_data_static.mpu6000.gyro_z = int16(bytes, 18); - ao_data_static.hmc5883.x = int16(bytes, 20); - ao_data_static.hmc5883.y = int16(bytes, 22); - ao_data_static.hmc5883.z = int16(bytes, 24); -#if HAS_MMA655X - ao_data_static.mma655x = int16(bytes, 26); - if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP) - ao_data_static.mma655x = ao_data_accel_invert(ao_data_static.mma655x); + struct ao_log_mega *log_mega; #endif - ao_records_read++; - ao_insert(); - return; - case 'G': - ao_gps_prev = ao_gps_static; - ao_gps_static.tick = tick; - ao_gps_static.latitude = int32(bytes, 0); - ao_gps_static.longitude = int32(bytes, 4); - { - int32_t altitude = int32(bytes, 8); - AO_TELEMETRY_LOCATION_SET_ALTITUDE(&ao_gps_static, altitude); - } - ao_gps_static.flags = bytes[13]; - if (!ao_gps_count) - ao_gps_first = ao_gps_static; - ao_gps_count++; - break; - } - continue; - } else if (nword == 3 && strcmp(words[0], "ms5607") == 0) { - if (strcmp(words[1], "reserved:") == 0) - ao_ms5607_prom.reserved = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "sens:") == 0) - ao_ms5607_prom.sens = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "off:") == 0) - ao_ms5607_prom.off = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "tcs:") == 0) - ao_ms5607_prom.tcs = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "tco:") == 0) - ao_ms5607_prom.tco = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "tref:") == 0) - ao_ms5607_prom.tref = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "tempsens:") == 0) - ao_ms5607_prom.tempsens = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "crc:") == 0) - ao_ms5607_prom.crc = strtoul(words[2], NULL, 10); - continue; - } else if (nword >= 3 && strcmp(words[0], "Pyro") == 0) { - int p = strtoul(words[1], NULL, 10); - int i, j; - struct ao_pyro *pyro = &ao_config.pyro[p]; - - for (i = 2; i < nword; i++) { - for (j = 0; j < NUM_PYRO_VALUES; j++) - if (!strcmp (words[i], ao_pyro_values[j].name)) - break; - if (j == NUM_PYRO_VALUES) - continue; - pyro->flags |= ao_pyro_values[j].flag; - if (ao_pyro_values[j].offset != NO_VALUE && i + 1 < nword) { - int16_t val = strtoul(words[++i], NULL, 10); - printf("pyro %d condition %s value %d\n", p, words[i-1], val); - *((int16_t *) ((char *) pyro + ao_pyro_values[j].offset)) = val; - } - } - } +#if TELEMETRUM_V2 + struct ao_log_metrum *log_metrum; #endif #if EASYMINI - if ((log_format == AO_LOG_FORMAT_EASYMINI1 || log_format == AO_LOG_FORMAT_EASYMINI2) && nword == 14 && strlen(words[0]) == 1) { - int i; - struct ao_ms5607_value value; - - type = words[0][0]; - tick = strtoul(words[1], NULL, 16); -// printf ("%c %04x", type, tick); - for (i = 2; i < nword; i++) { - bytes[i - 2] = strtoul(words[i], NULL, 16); -// printf(" %02x", bytes[i-2]); - } -// printf ("\n"); - switch (type) { - case 'F': - ao_flight_started = 1; - ao_flight_number = uint16(bytes, 0); - ao_ground_pres = uint32(bytes, 4); - ao_ground_height = ao_pa_to_altitude(ao_ground_pres); -#if 0 - printf("ground pres %d height %d\n", ao_ground_pres, ao_ground_height); - printf("sens %d off %d tcs %d tco %d tref %d tempsens %d crc %d\n", - ao_ms5607_prom.sens, - ao_ms5607_prom.off, - ao_ms5607_prom.tcs, - ao_ms5607_prom.tco, - ao_ms5607_prom.tref, - ao_ms5607_prom.tempsens, - ao_ms5607_prom.crc); + struct ao_log_mini *log_mini; #endif - break; - case 'A': - ao_data_static.tick = tick; - ao_data_static.ms5607_raw.pres = int24(bytes, 0); - ao_data_static.ms5607_raw.temp = int24(bytes, 3); -#if 0 - printf("raw pres %d temp %d\n", - ao_data_static.ms5607_raw.pres, - ao_data_static.ms5607_raw.temp); +#if TELEMETRUM_V1 + struct ao_log_record *log_record; #endif - ao_ms5607_convert(&ao_data_static.ms5607_raw, &value); -// printf("pres %d height %d\n", value.pres, ao_pa_to_altitude(value.pres)); - ao_records_read++; + + if (eeprom_offset >= eeprom->len) { + if (++ao_eof_read >= 1000) + if (!ao_summary) + printf ("no more data, exiting simulation\n"); + ao_test_exit(); + ao_data_static.tick += 10; ao_insert(); return; } - continue; - } else if (nword == 3 && strcmp(words[0], "ms5607") == 0) { - if (strcmp(words[1], "reserved:") == 0) - ao_ms5607_prom.reserved = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "sens:") == 0) - ao_ms5607_prom.sens = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "off:") == 0) - ao_ms5607_prom.off = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "tcs:") == 0) - ao_ms5607_prom.tcs = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "tco:") == 0) - ao_ms5607_prom.tco = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "tref:") == 0) - ao_ms5607_prom.tref = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "tempsens:") == 0) - ao_ms5607_prom.tempsens = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "crc:") == 0) - ao_ms5607_prom.crc = strtoul(words[2], NULL, 10); - continue; - } + switch (eeprom->log_format) { +#if TELEMEGA + case AO_LOG_FORMAT_TELEMEGA_OLD: + case AO_LOG_FORMAT_TELEMEGA: + log_mega = (struct ao_log_mega *) &eeprom->data[eeprom_offset]; + eeprom_offset += sizeof (*log_mega); + switch (log_mega->type) { + case AO_LOG_FLIGHT: + ao_flight_number = log_mega->u.flight.flight; + ao_flight_ground_accel = log_mega->u.flight.ground_accel; + ao_flight_started = 1; + ao_ground_pres = log_mega->u.flight.ground_pres; + ao_ground_height = ao_pa_to_altitude(ao_ground_pres); + ao_ground_accel_along = log_mega->u.flight.ground_accel_along; + ao_ground_accel_across = log_mega->u.flight.ground_accel_across; + ao_ground_accel_through = log_mega->u.flight.ground_accel_through; + ao_ground_roll = log_mega->u.flight.ground_roll; + ao_ground_pitch = log_mega->u.flight.ground_pitch; + ao_ground_yaw = log_mega->u.flight.ground_yaw; + ao_ground_mpu6000.accel_x = ao_ground_accel_across; + ao_ground_mpu6000.accel_y = ao_ground_accel_along; + ao_ground_mpu6000.accel_z = ao_ground_accel_through; + ao_ground_mpu6000.gyro_x = ao_ground_pitch >> 9; + ao_ground_mpu6000.gyro_y = ao_ground_roll >> 9; + ao_ground_mpu6000.gyro_z = ao_ground_yaw >> 9; + break; + case AO_LOG_STATE: + break; + case AO_LOG_SENSOR: + ao_data_static.tick = log_mega->tick; + ao_data_static.ms5607_raw.pres = log_mega->u.sensor.pres; + ao_data_static.ms5607_raw.temp = log_mega->u.sensor.temp; + ao_data_static.mpu6000.accel_x = log_mega->u.sensor.accel_x; + ao_data_static.mpu6000.accel_y = log_mega->u.sensor.accel_y; + ao_data_static.mpu6000.accel_z = log_mega->u.sensor.accel_z; + ao_data_static.mpu6000.gyro_x = log_mega->u.sensor.gyro_x; + ao_data_static.mpu6000.gyro_y = log_mega->u.sensor.gyro_y; + ao_data_static.mpu6000.gyro_z = log_mega->u.sensor.gyro_z; + ao_data_static.hmc5883.x = log_mega->u.sensor.mag_x; + ao_data_static.hmc5883.y = log_mega->u.sensor.mag_y; + ao_data_static.hmc5883.z = log_mega->u.sensor.mag_z; + ao_data_static.mma655x = log_mega->u.sensor.accel; + if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP) + ao_data_static.mma655x = ao_data_accel_invert(ao_data_static.mma655x); + ao_records_read++; + ao_insert(); + return; + case AO_LOG_TEMP_VOLT: + if (pyros_fired != log_mega->u.volt.pyro) { + printf("pyro changed %x -> %x\n", pyros_fired, log_mega->u.volt.pyro); + pyros_fired = log_mega->u.volt.pyro; + } + break; + case AO_LOG_GPS_TIME: + ao_gps_prev = ao_gps_static; + ao_gps_static.tick = log_mega->tick; + ao_gps_static.latitude = log_mega->u.gps.latitude; + ao_gps_static.longitude = log_mega->u.gps.longitude; + { + int16_t altitude_low = log_mega->u.gps.altitude_low; + int16_t altitude_high = log_mega->u.gps.altitude_high; + int32_t altitude = altitude_low | ((int32_t) altitude_high << 16); + + AO_TELEMETRY_LOCATION_SET_ALTITUDE(&ao_gps_static, altitude); + } + ao_gps_static.flags = log_mega->u.gps.flags; + if (!ao_gps_count) + ao_gps_first = ao_gps_static; + ao_gps_count++; + break; + case AO_LOG_GPS_SAT: + break; + } + break; #endif #if TELEMETRUM_V2 - if (log_format == AO_LOG_FORMAT_TELEMETRUM && nword == 14 && strlen(words[0]) == 1) { - int i; - struct ao_ms5607_value value; - - type = words[0][0]; - tick = strtoul(words[1], NULL, 16); -// printf ("%c %04x", type, tick); - for (i = 2; i < nword; i++) { - bytes[i - 2] = strtoul(words[i], NULL, 16); -// printf(" %02x", bytes[i-2]); - } -// printf ("\n"); - switch (type) { - case 'F': - ao_flight_number = uint16(bytes, 0); - ao_flight_ground_accel = int16(bytes, 2); - ao_flight_started = 1; - ao_ground_pres = int32(bytes, 4); - ao_ground_height = ao_pa_to_altitude(ao_ground_pres); + case AO_LOG_FORMAT_TELEMETRUM: + log_metrum = (struct ao_log_metrum *) &eeprom->data[eeprom_offset]; + eeprom_offset += sizeof (*log_metrum); + switch (log_metrum->type) { + case AO_LOG_FLIGHT: + ao_flight_started = 1; + ao_flight_number = log_metrum->u.flight.flight; + ao_flight_ground_accel = log_metrum->u.flight.ground_accel; + ao_ground_pres = log_metrum->u.flight.ground_pres; + ao_ground_height = ao_pa_to_altitude(ao_ground_pres); + break; + case AO_LOG_SENSOR: + ao_data_static.tick = log_metrum->tick; + ao_data_static.ms5607_raw.pres = log_metrum->u.sensor.pres; + ao_data_static.ms5607_raw.temp = log_metrum->u.sensor.temp; + ao_data_static.mma655x = log_metrum->u.sensor.accel; + ao_records_read++; + ao_insert(); + return; + } break; - case 'A': - ao_data_static.tick = tick; - ao_data_static.ms5607_raw.pres = int32(bytes, 0); - ao_data_static.ms5607_raw.temp = int32(bytes, 4); - ao_ms5607_convert(&ao_data_static.ms5607_raw, &value); - ao_data_static.mma655x = int16(bytes, 8); - ao_records_read++; - ao_insert(); - return; - } - continue; - } else if (nword == 3 && strcmp(words[0], "ms5607") == 0) { - if (strcmp(words[1], "reserved:") == 0) - ao_ms5607_prom.reserved = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "sens:") == 0) - ao_ms5607_prom.sens = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "off:") == 0) - ao_ms5607_prom.off = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "tcs:") == 0) - ao_ms5607_prom.tcs = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "tco:") == 0) - ao_ms5607_prom.tco = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "tref:") == 0) - ao_ms5607_prom.tref = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "tempsens:") == 0) - ao_ms5607_prom.tempsens = strtoul(words[2], NULL, 10); - else if (strcmp(words[1], "crc:") == 0) - ao_ms5607_prom.crc = strtoul(words[2], NULL, 10); - continue; - } #endif -#if TELEMETRUM_V1 - if (nword == 4 && log_format != AO_LOG_FORMAT_TELEMEGA) { - type = words[0][0]; - tick = strtoul(words[1], NULL, 16); - a = strtoul(words[2], NULL, 16); - b = strtoul(words[3], NULL, 16); - if (type == 'P') - type = 'A'; - } -#endif - else if (nword == 2 && strcmp(words[0], "log-format") == 0) { - log_format = strtoul(words[1], NULL, 10); - } else if (nword == 2 && strcmp(words[0], "serial-number") == 0) { - ao_serial_number = strtoul(words[1], NULL, 10); - } else if (nword >= 6 && strcmp(words[0], "Accel") == 0) { - ao_config.accel_plus_g = atoi(words[3]); - ao_config.accel_minus_g = atoi(words[5]); -#ifdef TELEMEGA - } else if (nword >= 8 && strcmp(words[0], "IMU") == 0) { - ao_config.accel_zero_along = atoi(words[3]); - ao_config.accel_zero_across = atoi(words[5]); - ao_config.accel_zero_through = atoi(words[7]); +#if EASYMINI + case AO_LOG_FORMAT_EASYMINI1: + case AO_LOG_FORMAT_EASYMINI2: + case AO_LOG_FORMAT_TELEMINI3: + log_mini = (struct ao_log_mini *) &eeprom->data[eeprom_offset]; + eeprom_offset += sizeof (*log_mini); + switch (log_mini->type) { + case AO_LOG_FLIGHT: + ao_flight_started = 1; + ao_flight_number = log_mini->u.flight.flight; + ao_ground_pres = log_mini->u.flight.ground_pres; + ao_ground_height = ao_pa_to_altitude(ao_ground_pres); + break; + case AO_LOG_SENSOR: + ao_data_static.tick = log_mini->tick; + ao_data_static.ms5607_raw.pres = int24(log_mini->u.sensor.pres, 0); + ao_data_static.ms5607_raw.temp = int24(log_mini->u.sensor.temp, 0); + ao_records_read++; + ao_insert(); + return; + } + break; #endif - } else if (nword >= 4 && strcmp(words[0], "Main") == 0) { - ao_config.main_deploy = atoi(words[2]); - } else if (nword >= 3 && strcmp(words[0], "Apogee") == 0 && - strcmp(words[1], "lockout:") == 0) { - ao_config.apogee_lockout = atoi(words[2]); - } else if (nword >= 3 && strcmp(words[0], "Pad") == 0 && - strcmp(words[1], "orientation:") == 0) { - ao_config.pad_orientation = atoi(words[2]); - } else if (nword >= 36 && strcmp(words[0], "CALL") == 0) { - tick = atoi(words[10]); - if (!ao_flight_started) { - type = 'F'; - a = atoi(words[26]); - ao_flight_started = 1; - } else { - type = 'A'; - a = atoi(words[12]); - b = atoi(words[14]); - } - } else if (nword == 3 && strcmp(words[0], "BARO") == 0) { - tick = strtol(words[1], NULL, 16); - a = 16384 - 328; - b = strtol(words[2], NULL, 10); - type = 'A'; - if (!ao_flight_started) { - ao_flight_ground_accel = 16384 - 328; - ao_config.accel_plus_g = 16384 - 328; - ao_config.accel_minus_g = 16384 + 328; - ao_flight_started = 1; - } - } else if (nword == 2 && strcmp(words[0], "TELEM") == 0) { - __xdata char *hex = words[1]; - char elt[3]; - int i, len; - uint8_t sum; - - len = strlen(hex); - if (len > sizeof (bytes) * 2) { - len = sizeof (bytes)*2; - hex[len] = '\0'; - } - for (i = 0; i < len; i += 2) { - elt[0] = hex[i]; - elt[1] = hex[i+1]; - elt[2] = '\0'; - bytes[i/2] = (uint8_t) strtol(elt, NULL, 16); - } - len = i/2; - if (bytes[0] != len - 2) { - printf ("bad length %d != %d\n", bytes[0], len - 2); - continue; - } - sum = 0x5a; - for (i = 1; i < len-1; i++) - sum += bytes[i]; - if (sum != bytes[len-1]) { - printf ("bad checksum\n"); - continue; - } - if ((bytes[len-2] & 0x80) == 0) { - continue; - } - if (len == 36) { - ao_xmemcpy(&telem, bytes + 1, 32); - tick = telem.generic.tick; - switch (telem.generic.type) { - case AO_TELEMETRY_SENSOR_TELEMETRUM: - case AO_TELEMETRY_SENSOR_TELEMINI: - case AO_TELEMETRY_SENSOR_TELENANO: - if (!ao_flight_started) { - ao_flight_ground_accel = telem.sensor.ground_accel; - ao_config.accel_plus_g = telem.sensor.accel_plus_g; - ao_config.accel_minus_g = telem.sensor.accel_minus_g; - ao_flight_started = 1; - } - type = 'A'; - a = telem.sensor.accel; - b = telem.sensor.pres; +#if TELEMETRUM_V1 + case AO_LOG_FORMAT_FULL: + case AO_LOG_FORMAT_TINY: + log_record = (struct ao_log_record *) &eeprom->data[eeprom_offset]; + eeprom_offset += sizeof (*log_record); + switch (log_record->type) { + case AO_LOG_FLIGHT: + ao_flight_started = 1; + ao_flight_ground_accel = log_record->u.flight.ground_accel; + ao_flight_number = log_record->u.flight.flight; + break; + case AO_LOG_SENSOR: + case 'P': /* ancient telemini */ + ao_data_static.tick = log_record->tick; + ao_data_static.adc.accel = log_record->u.sensor.accel; + ao_data_static.adc.pres_real = log_record->u.sensor.pres; + ao_data_static.adc.pres = log_record->u.sensor.pres; + ao_records_read++; + ao_insert(); + return; + case AO_LOG_TEMP_VOLT: + ao_data_static.tick = log_record->tick;; + ao_data_static.adc.temp = log_record->u.temp_volt.temp; + ao_data_static.adc.v_batt = log_record->u.temp_volt.v_batt; break; } - } else if (len == 99) { - ao_flight_started = 1; - tick = uint16(bytes+1, 21); - ao_flight_ground_accel = int16(bytes+1, 7); - ao_config.accel_plus_g = int16(bytes+1, 17); - ao_config.accel_minus_g = int16(bytes+1, 19); - type = 'A'; - a = int16(bytes+1, 23); - b = int16(bytes+1, 25); - } else if (len == 98) { - ao_flight_started = 1; - tick = uint16(bytes+1, 20); - ao_flight_ground_accel = int16(bytes+1, 6); - ao_config.accel_plus_g = int16(bytes+1, 16); - ao_config.accel_minus_g = int16(bytes+1, 18); - type = 'A'; - a = int16(bytes+1, 22); - b = int16(bytes+1, 24); - } else { - printf("unknown len %d\n", len); - continue; - } - } - if (type != 'F' && !ao_flight_started) - continue; - -#if TELEMEGA || TELEMETRUM_V2 || EASYMINI - (void) a; - (void) b; -#else - switch (type) { - case 'F': - ao_flight_ground_accel = a; - ao_flight_number = b; - if (ao_config.accel_plus_g == 0) { - ao_config.accel_plus_g = a; - ao_config.accel_minus_g = a + 530; + break; +#endif + default: + printf ("invalid log format %d\n", log_format); + ao_test_exit(); } - if (ao_config.main_deploy == 0) - ao_config.main_deploy = 250; - ao_flight_started = 1; - break; - case 'S': - break; - case 'A': - ao_data_static.tick = tick; - ao_data_static.adc.accel = a; - ao_data_static.adc.pres_real = b; - ao_data_static.adc.pres = b; - ao_records_read++; - ao_insert(); - return; - case 'T': - ao_data_static.tick = tick; - ao_data_static.adc.temp = a; - ao_data_static.adc.v_batt = b; - break; - case 'D': - case 'G': - case 'N': - case 'W': - case 'H': - break; } -#endif } } @@ -1190,6 +961,26 @@ void run_flight_fixed(char *name, FILE *f, int summary, char *info) emulator_info = info; ao_summary = summary; + if (strstr(name, ".eeprom") != NULL) { + char c; + + c = getc(f); + ungetc(c, f); + if (c == '{') + eeprom = ao_eeprom_read(f); + else + eeprom = ao_eeprom_read_old(f); + + if (eeprom) { +#if HAS_MS5607 + ao_ms5607_prom = eeprom->ms5607_prom; +#endif + ao_config = eeprom->config; + ao_serial_number = eeprom->serial_number; + log_format = eeprom->log_format; + } + } + ao_flight_init(); ao_flight(); } diff --git a/telegps/TeleGPSConfigUI.java b/telegps/TeleGPSConfigUI.java index 88ced192..87683c2b 100644 --- a/telegps/TeleGPSConfigUI.java +++ b/telegps/TeleGPSConfigUI.java @@ -619,7 +619,7 @@ public class TeleGPSConfigUI return true; } - void set_dirty() { + public void set_dirty() { dirty = true; save.setEnabled(true); } @@ -634,6 +634,17 @@ public class TeleGPSConfigUI super.dispose(); } + public int accel_cal_plus() { + return AltosLib.MISSING; + } + + public int accel_cal_minus() { + return AltosLib.MISSING; + } + + public void set_accel_cal(int accel_plus, int accel_minus) { + } + /* Listen for events from our buttons */ public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); |