Merge branch 'master' into micropeak-logging
authorKeith Packard <keithp@keithp.com>
Tue, 25 Dec 2012 22:20:42 +0000 (14:20 -0800)
committerKeith Packard <keithp@keithp.com>
Tue, 25 Dec 2012 22:20:42 +0000 (14:20 -0800)
75 files changed:
altoslib/AltosConfigData.java
altoslib/AltosConfigValues.java [new file with mode: 0644]
altoslib/AltosLink.java
altoslib/AltosMs5607.java
altoslib/AltosMs5607Query.java
altoslib/AltosState.java
altoslib/Makefile.am
altosui/AltosConfig.java
altosui/AltosConfigUI.java
altosui/AltosGraphTime.java
altosui/AltosGraphUI.java
ao-tools/Makefile.am
ao-tools/ao-sky-flash/Makefile.am [new file with mode: 0644]
ao-tools/ao-sky-flash/STI_01.04.42-01.10.23_4x_9600_Bin_20100901.bin [new file with mode: 0644]
ao-tools/ao-sky-flash/STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.bin [new file with mode: 0644]
ao-tools/ao-sky-flash/ao-sky-flash.1 [new file with mode: 0644]
ao-tools/ao-sky-flash/sky_bin.c [new file with mode: 0644]
ao-tools/ao-sky-flash/sky_debug.c [new file with mode: 0644]
ao-tools/ao-sky-flash/sky_flash.c [new file with mode: 0644]
ao-tools/ao-sky-flash/sky_flash.h [new file with mode: 0644]
ao-tools/ao-sky-flash/sky_serial.c [new file with mode: 0644]
ao-tools/ao-sky-flash/sky_srec.c [new file with mode: 0644]
ao-tools/ao-sky-flash/srec_115200.bin [new file with mode: 0644]
ao-tools/ao-sky-flash/srec_9600.bin [new file with mode: 0644]
ao-tools/lib/cc.h
configure.ac
debian/rules
doc/altusmetrum.xsl
src/avr/ao_usb_avr.c
src/cc1111/ao_adc.c
src/cc1111/ao_dbg.c
src/cc1111/ao_serial.c
src/cc1111/ao_usb.c
src/core/ao.h
src/core/ao_cmd.c
src/core/ao_config.c
src/core/ao_data.h
src/core/ao_log.h
src/core/ao_log_mega.c
src/core/ao_log_telem.c
src/core/ao_packet.h
src/core/ao_sample.c
src/core/ao_sample.h
src/core/ao_send_packet.c
src/core/ao_serial.h
src/core/ao_sqrt.c
src/core/ao_stdio.c
src/core/ao_task.c
src/core/ao_task.h
src/core/ao_telemetry.c
src/core/ao_usb.h
src/drivers/ao_aprs.c [new file with mode: 0644]
src/drivers/ao_aprs.h [new file with mode: 0644]
src/drivers/ao_btm.c
src/drivers/ao_cc1120.c
src/drivers/ao_companion.c
src/drivers/ao_gps_skytraq.c
src/drivers/ao_m25.c
src/drivers/ao_packet.c
src/drivers/ao_packet_master.c
src/megadongle-v0.1/ao_pins.h
src/megametrum-v0.1/Makefile
src/megametrum-v0.1/ao_megametrum.c
src/megametrum-v0.1/ao_pins.h
src/stm/ao_arch.h
src/stm/ao_arch_funcs.h
src/stm/ao_serial_stm.c
src/stm/ao_usb_stm.c
src/teleballoon-v1.1/ao_pins.h
src/teleballoon-v1.1/ao_teleballoon.c
src/test/Makefile
src/test/ao_aprs_test.c [new file with mode: 0644]
src/test/ao_flight_test.c
src/test/ao_gps_test.c
src/test/ao_gps_test_skytraq.c

index 45a88783ad3a4a5e33fa023188804a66da6d077f..99b8e39d2042e4279605294acafb6c223d72de5d 100644 (file)
@@ -26,31 +26,56 @@ public class AltosConfigData implements Iterable<String> {
        /* Version information */
        public String   manufacturer;
        public String   product;
-       public String   version;
-       public int      log_format;
        public int      serial;
+       public int      flight;
+       public int      log_format;
+       public String   version;
 
        /* Strings returned */
        public LinkedList<String>       lines;
 
        /* Config information */
-       public int      config_major;
-       public int      config_minor;
+       /* HAS_FLIGHT*/
        public int      main_deploy;
        public int      apogee_delay;
-       public int      radio_channel;
-       public int      radio_setting;
+       public int      apogee_lockout;
+
+       /* HAS_RADIO */
        public int      radio_frequency;
        public String   callsign;
-       public int      accel_cal_plus, accel_cal_minus;
+       public int      radio_enable;
        public int      radio_calibration;
+       /* Old HAS_RADIO values */
+       public int      radio_channel;
+       public int      radio_setting;
+
+       /* HAS_ACCEL */
+       public int      accel_cal_plus, accel_cal_minus;
+       public int      pad_orientation;
+
+       /* HAS_LOG */
        public int      flight_log_max;
+
+       /* HAS_IGNITE */
        public int      ignite_mode;
-       public int      stored_flight;
+
+       /* HAS_AES */
+       public String   aes_key;
+
+       /* AO_PYRO_NUM */
+       public AltosPyro[]      pyros;
+       public int              npyro;
+       public int              pyro;
+
+       /* HAS_APRS */
+       public int              aprs_interval;
+
+       /* Storage info replies */
        public int      storage_size;
        public int      storage_erase_unit;
 
-       public AltosPyro[]      pyros;
+       /* Log listing replies */
+       public int      stored_flight;
 
        public static String get_string(String line, String label) throws  ParseException {
                if (line.startsWith(label)) {
@@ -85,6 +110,9 @@ public class AltosConfigData implements Iterable<String> {
                        if (stored_flight == 0)
                                return 1;
                        return 0;
+               case AltosLib.AO_LOG_FORMAT_TELEMETRY:
+               case AltosLib.AO_LOG_FORMAT_TELESCIENCE:
+                       return 1;
                default:
                        if (flight_log_max <= 0)
                                return 1;
@@ -111,7 +139,7 @@ public class AltosConfigData implements Iterable<String> {
 
                return r;
        }
-       
+
        public int compare_version(String other) {
                int[]   me = parse_version(version);
                int[]   them = parse_version(other);
@@ -130,71 +158,343 @@ public class AltosConfigData implements Iterable<String> {
                return 0;
        }
 
-       public AltosConfigData(AltosLink link) throws InterruptedException, TimeoutException {
-               link.printf("c s\nf\nl\nv\n");
+       public void reset() {
                lines = new LinkedList<String>();
-               radio_setting = 0;
-               radio_frequency = 0;
-               stored_flight = 0;
-               serial = -1;
+
+               manufacturer = "unknown";
+               product = "unknown";
+               serial = 0;
+               flight = 0;
+               log_format = AltosLib.AO_LOG_FORMAT_UNKNOWN;
+               version = "unknown";
+
+               main_deploy = -1;
+               apogee_delay = -1;
+               apogee_lockout = -1;
+
+               radio_frequency = -1;
+               callsign = null;
+               radio_enable = -1;
+               radio_calibration = -1;
+               radio_channel = -1;
+               radio_setting = -1;
+
+               accel_cal_plus = -1;
+               accel_cal_minus = -1;
+               pad_orientation = -1;
+
+               flight_log_max = -1;
+               ignite_mode = -1;
+
+               aes_key = "";
+
+               pyro = 0;
+               npyro = 0;
                pyros = null;
 
-               int npyro = 0;
-               int pyro = 0;
+               aprs_interval = -1;
+
+               storage_size = -1;
+               storage_erase_unit = -1;
+               stored_flight = -1;
+       }
+
+       public void parse_line(String line) {
+               lines.add(line);
+               /* Version replies */
+               try { manufacturer = get_string(line, "manufacturer"); } catch (Exception e) {}
+               try { product = get_string(line, "product"); } catch (Exception e) {}
+               try { serial = get_int(line, "serial-number"); } catch (Exception e) {}
+               try { flight = get_int(line, "current-flight"); } catch (Exception e) {}
+               try { log_format = get_int(line, "log-format"); } catch (Exception e) {}
+               try { version = get_string(line, "software-version"); } catch (Exception e) {}
+
+               /* Version also contains MS5607 info, which we ignore here */
+
+               /* Config show replies */
+
+               /* HAS_FLIGHT */
+               try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {}
+               try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {}
+               try { apogee_lockout = get_int(line, "Apogee lockout:"); } catch (Exception e) {}
+
+               /* HAS_RADIO */
+               try {
+                       radio_frequency = get_int(line, "Frequency:");
+                       if (radio_frequency < 0)
+                               radio_frequency = 434550;
+               } catch (Exception e) {}
+               try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {}
+               try { radio_enable = get_int(line, "Radio enable:"); } catch (Exception e) {}
+               try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {}
+
+               /* Old HAS_RADIO values */
+               try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {}
+               try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {}
+
+               /* HAS_ACCEL */
+               try {
+                       if (line.startsWith("Accel cal")) {
+                               String[] bits = line.split("\\s+");
+                               if (bits.length >= 6) {
+                                       accel_cal_plus = Integer.parseInt(bits[3]);
+                                       accel_cal_minus = Integer.parseInt(bits[5]);
+                               }
+                       }
+               } catch (Exception e) {}
+               try { pad_orientation = get_int(line, "Pad orientation:"); } catch (Exception e) {}
+
+               /* HAS_LOG */
+               try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {}
+
+               /* HAS_IGNITE */
+               try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {}
+
+               /* HAS_AES */
+               try { aes_key = get_string(line, "AES key:"); } catch (Exception e) {}
+
+               /* AO_PYRO_NUM */
+               try {
+                       npyro = get_int(line, "Pyro-count:");
+                       pyros = new AltosPyro[npyro];
+                       pyro = 0;
+               } catch (Exception e) {}
+               if (npyro > 0) {
+                       try {
+                               AltosPyro p = new AltosPyro(pyro, line);
+                               if (pyro < npyro)
+                                       pyros[pyro++] = p;
+                       } catch (Exception e) {}
+               }
+
+               /* HAS_APRS */
+               try { aprs_interval = get_int(line, "APRS interval:"); } catch (Exception e) {}
+
+               /* Storage info replies */
+               try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {}
+               try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {}
+
+               /* Log listing replies */
+               try { get_int(line, "flight"); stored_flight++; }  catch (Exception e) {}
+       }
+
+       public AltosConfigData() {
+               reset();
+       }
+
+       private void read_link(AltosLink link, String finished) throws InterruptedException, TimeoutException {
                for (;;) {
                        String line = link.get_reply();
                        if (line == null)
                                throw new TimeoutException();
                        if (line.contains("Syntax error"))
                                continue;
-                       lines.add(line);
-                       if (pyro < npyro - 1) {
-                               if (pyros == null)
-                                       pyros = new AltosPyro[npyro];
-                               try {
-                                       pyros[pyro] = new AltosPyro(pyro, line);
-                               } catch (ParseException e) {
-                               }
-                               ++pyro;
-                               continue;
-                       }
-                       try { serial = get_int(line, "serial-number"); } catch (Exception e) {}
-                       try { log_format = get_int(line, "log-format"); } catch (Exception e) {}
-                       try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {}
-                       try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {}
-                       try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {}
-                       try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {}
-                       try {
-                               radio_frequency = get_int(line, "Frequency:");
-                               if (radio_frequency < 0)
-                                       radio_frequency = 434550;
-                       } catch (Exception e) {}
-                       try {
-                               if (line.startsWith("Accel cal")) {
-                                       String[] bits = line.split("\\s+");
-                                       if (bits.length >= 6) {
-                                               accel_cal_plus = Integer.parseInt(bits[3]);
-                                               accel_cal_minus = Integer.parseInt(bits[5]);
-                                       }
-                               }
-                       } catch (Exception e) {}
-                       try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {}
-                       try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {}
-                       try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {}
-                       try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {}
-                       try { version = get_string(line,"software-version"); } catch (Exception e) {}
-                       try { product = get_string(line,"product"); } catch (Exception e) {}
-                       try { manufacturer = get_string(line,"manufacturer"); } catch (Exception e) {}
-
-                       try { get_int(line, "flight"); stored_flight++; }  catch (Exception e) {}
-                       try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {}
-                       try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {}
-                       try { npyro = get_int(line, "Pyro-count:"); pyro = 0; } catch (Exception e) {}
+                       this.parse_line(line);
 
                        /* signals the end of the version info */
-                       if (line.startsWith("software-version"))
+                       if (line.startsWith(finished))
                                break;
                }
        }
 
-}
\ No newline at end of file
+       public boolean has_frequency() {
+               return radio_frequency >= 0 || radio_setting >= 0 || radio_channel >= 0;
+       }
+
+       public void set_frequency(double freq) {
+               int     frequency = radio_frequency;
+               int     setting = radio_setting;
+
+               if (frequency > 0) {
+                       radio_frequency = (int) Math.floor (freq * 1000 + 0.5);
+                       radio_channel = -1;
+               } else if (setting > 0) {
+                       radio_setting =AltosConvert.radio_frequency_to_setting(freq,
+                                                                                   radio_calibration);
+                       radio_channel = -1;
+               } else {
+                       radio_channel = AltosConvert.radio_frequency_to_channel(freq);
+               }
+       }
+
+       public double frequency() {
+               int     channel = radio_channel;
+               int     setting = radio_setting;
+               if (channel < 0)
+                       channel = 0;
+               if (setting < 0)
+                       setting = 0;
+
+               return AltosConvert.radio_to_frequency(radio_frequency,
+                                                      setting,
+                                                      radio_calibration,
+                                                      channel);
+       }
+
+       public int log_limit() {
+               if (storage_size > 0 && storage_erase_unit > 0) {
+                       int     log_limit = storage_size - storage_erase_unit;
+                       if (log_limit > 0)
+                               return log_limit / 1024;
+               }
+               return 1024;
+       }
+
+       public void get_values(AltosConfigValues source) {
+
+               /* HAS_FLIGHT */
+               if (main_deploy >= 0)
+                       main_deploy = source.main_deploy();
+               if (apogee_delay >= 0)
+                       apogee_delay = source.apogee_delay();
+               if (apogee_lockout >= 0)
+                       apogee_lockout = source.apogee_lockout();
+
+               /* HAS_RADIO */
+               if (has_frequency())
+                       set_frequency(source.radio_frequency());
+               if (radio_enable >= 0)
+                       radio_enable = source.radio_enable();
+               if (callsign != null)
+                       callsign = source.callsign();
+               if (radio_calibration >= 0)
+                       radio_calibration = source.radio_calibration();
+
+               /* HAS_ACCEL */
+               if (pad_orientation >= 0)
+                       pad_orientation = source.pad_orientation();
+
+               /* HAS_LOG */
+               if (flight_log_max >= 0)
+                       flight_log_max = source.flight_log_max();
+
+               /* HAS_IGNITE */
+               if (ignite_mode >= 0)
+                       ignite_mode = source.ignite_mode();
+
+               /* AO_PYRO_NUM */
+               if (npyro > 0)
+                       pyros = source.pyros();
+
+               if (aprs_interval >= 0)
+                       aprs_interval = source.aprs_interval();
+       }
+
+       public void set_values(AltosConfigValues dest) {
+               dest.set_serial(serial);
+               dest.set_product(product);
+               dest.set_version(version);
+               dest.set_main_deploy(main_deploy);
+               dest.set_apogee_delay(apogee_delay);
+               dest.set_apogee_lockout(apogee_lockout);
+               dest.set_radio_calibration(radio_calibration);
+               dest.set_radio_frequency(frequency());
+               boolean max_enabled = true;
+               switch (log_format) {
+               case AltosLib.AO_LOG_FORMAT_TINY:
+                       max_enabled = false;
+                       break;
+               default:
+                       if (stored_flight >= 0)
+                               max_enabled = false;
+                       break;
+               }
+               dest.set_flight_log_max_enabled(max_enabled);
+               dest.set_radio_enable(radio_enable);
+               dest.set_flight_log_max_limit(log_limit());
+               dest.set_flight_log_max(flight_log_max);
+               dest.set_ignite_mode(ignite_mode);
+               dest.set_pad_orientation(pad_orientation);
+               dest.set_callsign(callsign);
+               if (npyro > 0)
+                       dest.set_pyros(pyros);
+               else
+                       dest.set_pyros(null);
+               dest.set_aprs_interval(aprs_interval);
+       }
+
+       public void save(AltosLink link, boolean remote) throws InterruptedException, TimeoutException {
+
+               /* HAS_FLIGHT */
+               if (main_deploy >= 0)
+                       link.printf("c m %d\n", main_deploy);
+               if (apogee_delay >= 0)
+                       link.printf("c d %d\n", apogee_delay);
+               if (apogee_lockout >= 0)
+                       link.printf("c L %d\n", apogee_lockout);
+
+               /* Don't mess with radio calibration when remote */
+               if (radio_calibration > 0 && !remote)
+                       link.printf("c f %d\n", radio_calibration);
+
+               /* HAS_RADIO */
+               if (has_frequency()) {
+                       boolean has_frequency = radio_frequency >= 0;
+                       boolean has_setting = radio_setting > 0;
+                       double frequency = frequency();
+                       link.set_radio_frequency(frequency,
+                                                       has_frequency,
+                                                       has_setting,
+                                                       radio_calibration);
+                       /* When remote, reset the dongle frequency at the same time */
+                       if (remote) {
+                               link.stop_remote();
+                               link.set_radio_frequency(frequency);
+                               link.start_remote();
+                       }
+               }
+
+               if (callsign != null)
+                       link.printf("c c %s\n", callsign);
+               if (radio_enable >= 0)
+                       link.printf("c e %d\n", radio_enable);
+
+               /* HAS_ACCEL */
+               /* UI doesn't support accel cal */
+               if (pad_orientation >= 0)
+                       link.printf("c o %d\n", pad_orientation);
+
+               /* HAS_LOG */
+               if (flight_log_max != 0)
+                       link.printf("c l %d\n", flight_log_max);
+
+               /* HAS_IGNITE */
+               if (ignite_mode >= 0)
+                       link.printf("c i %d\n", ignite_mode);
+
+               /* HAS_AES */
+               /* UI doesn't support AES key config */
+
+               /* AO_PYRO_NUM */
+               if (pyros.length > 0) {
+                       for (int p = 0; p < pyros.length; p++) {
+                               link.printf("c P %s\n",
+                                                  pyros[p].toString());
+                       }
+               }
+
+               /* HAS_APRS */
+               if (aprs_interval >= 0)
+                       link.printf("c A %d\n", aprs_interval);
+
+               link.printf("c w\n");
+               link.flush_output();
+       }
+
+       public AltosConfigData(AltosLink link) throws InterruptedException, TimeoutException {
+               reset();
+               link.printf("c s\nf\nv\n");
+               read_link(link, "software-version");
+               System.out.printf("Log format %d\n", log_format);
+               switch (log_format) {
+               case AltosLib.AO_LOG_FORMAT_FULL:
+               case AltosLib.AO_LOG_FORMAT_TINY:
+               case AltosLib.AO_LOG_FORMAT_MEGAMETRUM:
+                       link.printf("l\n");
+                       read_link(link, "done");
+               default:
+                       break;
+               }
+       }
+
+}
diff --git a/altoslib/AltosConfigValues.java b/altoslib/AltosConfigValues.java
new file mode 100644 (file)
index 0000000..40d5217
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2012 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.
+ */
+
+package org.altusmetrum.AltosLib;
+
+public interface AltosConfigValues {
+       /* set and get all of the dialog values */
+       public abstract void set_product(String product);
+
+       public abstract void set_version(String version);
+
+       public abstract void set_serial(int serial);
+
+       public abstract void set_main_deploy(int new_main_deploy);
+
+       public abstract int main_deploy();
+
+       public abstract void set_apogee_delay(int new_apogee_delay);
+
+       public abstract int apogee_delay();
+
+       public abstract void set_apogee_lockout(int new_apogee_lockout);
+
+       public abstract int apogee_lockout();
+
+       public abstract void set_radio_frequency(double new_radio_frequency);
+
+       public abstract double radio_frequency();
+
+       public abstract void set_radio_calibration(int new_radio_calibration);
+
+       public abstract int radio_calibration();
+
+       public abstract void set_radio_enable(int new_radio_enable);
+
+       public abstract int radio_enable();
+
+       public abstract void set_callsign(String new_callsign);
+
+       public abstract String callsign();
+
+       public abstract void set_flight_log_max(int new_flight_log_max);
+
+       public abstract void set_flight_log_max_enabled(boolean enable);
+
+       public abstract int flight_log_max();
+
+       public abstract void set_flight_log_max_limit(int flight_log_max_limit);
+
+       public abstract void set_ignite_mode(int new_ignite_mode);
+
+       public abstract int ignite_mode();
+
+       public abstract void set_pad_orientation(int new_pad_orientation);
+
+       public abstract int pad_orientation();
+
+       public abstract void set_pyros(AltosPyro[] new_pyros);
+
+       public abstract AltosPyro[] pyros();
+
+       public abstract int aprs_interval();
+
+       public abstract void set_aprs_interval(int new_aprs_interval);
+}
index 6d510563c5d32622bfbc3cfb854da885c21b4f27..1b722026067b5bccfea4521bfdfb317cd3a5755a 100644 (file)
@@ -284,8 +284,8 @@ public abstract class AltosLink implements Runnable {
                frequency = in_frequency;
                config_data();
                set_radio_frequency(frequency,
-                                   config_data.radio_frequency != 0,
-                                   config_data.radio_setting != 0,
+                                   config_data.radio_frequency > 0,
+                                   config_data.radio_setting > 0,
                                    config_data.radio_calibration);
        }
 
@@ -339,10 +339,10 @@ public abstract class AltosLink implements Runnable {
        public String name;
 
        public void start_remote() throws TimeoutException, InterruptedException {
-               if (debug)
-                       System.out.printf("start remote %7.3f\n", frequency);
                if (frequency == 0.0)
                        frequency = AltosPreferences.frequency(serial);
+               if (debug)
+                       System.out.printf("start remote %7.3f\n", frequency);
                set_radio_frequency(frequency);
                set_callsign(AltosPreferences.callsign());
                printf("p\nE 0\n");
index 148a9f9252be841c8d4e7eb3479bd14d963586d7..318fea4d290ac1e88165f9722350cbf131e799bb 100644 (file)
@@ -82,6 +82,43 @@ public class AltosMs5607 {
                return pa;
        }
 
+       public boolean parse_line(String line) {
+               String[] items = line.split("\\s+");
+               if (line.startsWith("Pressure:")) {
+                       if (items.length >= 2)
+                               raw_pres = Integer.parseInt(items[1]);
+               } else if (line.startsWith("Temperature:")) {
+                       if (items.length >= 2)
+                               raw_temp = Integer.parseInt(items[1]);
+               } else if (line.startsWith("ms5607 reserved:")) {
+                       if (items.length >= 3)
+                               reserved = Integer.parseInt(items[2]);
+               } else if (line.startsWith("ms5607 sens:")) {
+                       if (items.length >= 3)
+                               sens = Integer.parseInt(items[2]);
+               } else if (line.startsWith("ms5607 off:")) {
+                       if (items.length >= 3)
+                               off = Integer.parseInt(items[2]);
+               } else if (line.startsWith("ms5607 tcs:")) {
+                       if (items.length >= 3)
+                               tcs = Integer.parseInt(items[2]);
+               } else if (line.startsWith("ms5607 tco:")) {
+                       if (items.length >= 3)
+                               tco = Integer.parseInt(items[2]);
+               } else if (line.startsWith("ms5607 tref:")) {
+                       if (items.length >= 3)
+                               tref = Integer.parseInt(items[2]);
+               } else if (line.startsWith("ms5607 tempsens:")) {
+                       if (items.length >= 3)
+                               tempsens = Integer.parseInt(items[2]);
+               } else if (line.startsWith("ms5607 crc:")) {
+                       if (items.length >= 3)
+                               crc = Integer.parseInt(items[2]);
+               } else if (line.startsWith("Altitude"))
+                       return false;
+               return true;
+       }
+
        public AltosMs5607() {
                raw_pres = AltosRecord.MISSING;
                raw_temp = AltosRecord.MISSING;
index 3c74679517fbf89c3f457225e6a50bdb471b0466..1aaec334bb5c05c1d3bd507dcac8d76e7802ae1c 100644 (file)
@@ -27,38 +27,7 @@ class AltosMs5607Query extends AltosMs5607 {
                        if (line == null) {
                                throw new TimeoutException();
                        }
-                       String[] items = line.split("\\s+");
-                       if (line.startsWith("Pressure:")) {
-                               if (items.length >= 2)
-                                       raw_pres = Integer.parseInt(items[1]);
-                       } else if (line.startsWith("Temperature:")) {
-                               if (items.length >= 2)
-                                       raw_temp = Integer.parseInt(items[1]);
-                       } else if (line.startsWith("ms5607 reserved:")) {
-                               if (items.length >= 3)
-                                       reserved = Integer.parseInt(items[2]);
-                       } else if (line.startsWith("ms5607 sens:")) {
-                               if (items.length >= 3)
-                                       sens = Integer.parseInt(items[2]);
-                       } else if (line.startsWith("ms5607 off:")) {
-                               if (items.length >= 3)
-                                       off = Integer.parseInt(items[2]);
-                       } else if (line.startsWith("ms5607 tcs:")) {
-                               if (items.length >= 3)
-                                       tcs = Integer.parseInt(items[2]);
-                       } else if (line.startsWith("ms5607 tco:")) {
-                               if (items.length >= 3)
-                                       tco = Integer.parseInt(items[2]);
-                       } else if (line.startsWith("ms5607 tref:")) {
-                               if (items.length >= 3)
-                                       tref = Integer.parseInt(items[2]);
-                       } else if (line.startsWith("ms5607 tempsens:")) {
-                               if (items.length >= 3)
-                                       tempsens = Integer.parseInt(items[2]);
-                       } else if (line.startsWith("ms5607 crc:")) {
-                               if (items.length >= 3)
-                                       crc = Integer.parseInt(items[2]);
-                       } else if (line.startsWith("Altitude"))
+                       if (!parse_line(line))
                                break;
                }
                convert();
index f28dd1c6609f24070b7ba0fa4ce4e5f8f60205ed..218c598ab5d80d6a4e264b86a1a9d25209b5f933 100644 (file)
@@ -92,6 +92,9 @@ public class AltosState {
        public void init (AltosRecord cur, AltosState prev_state) {
                data = cur;
 
+               /* Discard previous state if it was for a different board */
+               if (prev_state != null && prev_state.data.serial != data.serial)
+                       prev_state = null;
                ground_altitude = data.ground_altitude();
 
                altitude = data.altitude();
index 2579a65030a625a89784ab6876fbd97908e02886..0086bc6555fc617414ddc63b51756012e1efc555 100644 (file)
@@ -12,6 +12,7 @@ AltosLibdir = $(datadir)/java
 AltosLib_JAVA = \
        $(SRC)/AltosLib.java \
        $(SRC)/AltosConfigData.java \
+       $(SRC)/AltosConfigValues.java \
        $(SRC)/AltosConvert.java \
        $(SRC)/AltosCRCException.java \
        $(SRC)/AltosEepromChunk.java \
index 4b0edec0fbf5492aa48501c5e9ab2540f121d65c..e1ffebb4b95f1129144e1a86c70dadf2915ae78d 100644 (file)
@@ -58,64 +58,12 @@ public class AltosConfig implements ActionListener {
        AltosDevice     device;
        AltosSerial     serial_line;
        boolean         remote;
-       AltosConfigData remote_config_data;
-       double          remote_frequency;
-       int_ref         serial;
-       int_ref         log_format;
-       int_ref         main_deploy;
-       int_ref         apogee_delay;
-       int_ref         apogee_lockout;
-       int_ref         radio_channel;
-       int_ref         radio_calibration;
-       int_ref         flight_log_max;
-       int_ref         ignite_mode;
-       int_ref         pad_orientation;
-       int_ref         radio_setting;
-       int_ref         radio_frequency;
-       int_ref         storage_size;
-       int_ref         storage_erase_unit;
-       int_ref         stored_flight;
-       int_ref         radio_enable;
-       string_ref      version;
-       string_ref      product;
-       string_ref      callsign;
-       int_ref         npyro;
-       AltosPyro[]     pyros;
+
+       AltosConfigData data;
        AltosConfigUI   config_ui;
        boolean         serial_started;
        boolean         made_visible;
 
-       boolean get_int(String line, String label, int_ref x) {
-               if (line.startsWith(label)) {
-                       try {
-                               String tail = line.substring(label.length()).trim();
-                               String[] tokens = tail.split("\\s+");
-                               if (tokens.length > 0) {
-                                       int     i = Integer.parseInt(tokens[0]);
-                                       x.set(i);
-                                       return true;
-                               }
-                       } catch (NumberFormatException ne) {
-                       }
-               }
-               return false;
-       }
-
-       boolean get_string(String line, String label, string_ref s) {
-               if (line.startsWith(label)) {
-                       String  quoted = line.substring(label.length()).trim();
-
-                       if (quoted.startsWith("\""))
-                               quoted = quoted.substring(1);
-                       if (quoted.endsWith("\""))
-                               quoted = quoted.substring(0,quoted.length()-1);
-                       s.set(quoted);
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
        void start_serial() throws InterruptedException, TimeoutException {
                serial_started = true;
                if (remote)
@@ -130,43 +78,8 @@ public class AltosConfig implements ActionListener {
                        serial_line.stop_remote();
        }
 
-       int log_limit() {
-               if (storage_size.get() > 0 && storage_erase_unit.get() > 0) {
-                       int     log_limit = storage_size.get() - storage_erase_unit.get();
-                       if (log_limit > 0)
-                               return log_limit / 1024;
-               }
-               return 1024;
-       }
-
        void update_ui() {
-               config_ui.set_serial(serial.get());
-               config_ui.set_product(product.get());
-               config_ui.set_version(version.get());
-               config_ui.set_main_deploy(main_deploy.get());
-               config_ui.set_apogee_delay(apogee_delay.get());
-               config_ui.set_apogee_lockout(apogee_lockout.get());
-               config_ui.set_radio_calibration(radio_calibration.get());
-               config_ui.set_radio_frequency(frequency());
-               boolean max_enabled = true;
-               switch (log_format.get()) {
-               case Altos.AO_LOG_FORMAT_TINY:
-                       max_enabled = false;
-                       break;
-               default:
-                       if (stored_flight.get() >= 0)
-                               max_enabled = false;
-                       break;
-               }
-               config_ui.set_flight_log_max_enabled(max_enabled);
-               config_ui.set_radio_enable(radio_enable.get());
-               config_ui.set_flight_log_max_limit(log_limit());
-               config_ui.set_flight_log_max(flight_log_max.get());
-               config_ui.set_ignite_mode(ignite_mode.get());
-               config_ui.set_pad_orientation(pad_orientation.get());
-               config_ui.set_callsign(callsign.get());
-               config_ui.set_pyros(pyros);
-               config_ui.set_has_pyro(npyro.get() > 0);
+               data.set_values(config_ui);
                config_ui.set_clean();
                if (!made_visible) {
                        made_visible = true;
@@ -176,52 +89,6 @@ public class AltosConfig implements ActionListener {
 
        int     pyro;
 
-       void process_line(String line) {
-               if (line == null) {
-                       abort();
-                       return;
-               }
-               if (line.equals("all finished")) {
-                       if (serial_line != null)
-                               update_ui();
-                       return;
-               }
-               if (pyro < npyro.get()) {
-                       if (pyros == null)
-                               pyros = new AltosPyro[npyro.get()];
-
-                       try {
-                               pyros[pyro] = new AltosPyro(pyro, line);
-                       } catch (ParseException e) {
-                               System.out.printf ("pyro parse failed %s\n", line);
-                       }
-                       ++pyro;
-                       return;
-               }
-               get_int(line, "serial-number", serial);
-               get_int(line, "log-format", log_format);
-               get_int(line, "Main deploy:", main_deploy);
-               get_int(line, "Apogee delay:", apogee_delay);
-               get_int(line, "Apogee lockout:", apogee_lockout);
-               get_int(line, "Radio channel:", radio_channel);
-               get_int(line, "Radio cal:", radio_calibration);
-               get_int(line, "Max flight log:", flight_log_max);
-               get_int(line, "Ignite mode:", ignite_mode);
-               get_int(line, "Pad orientation:", pad_orientation);
-               get_int(line, "Radio setting:", radio_setting);
-               if (get_int(line, "Frequency:", radio_frequency))
-                       if (radio_frequency.get() < 0)
-                               radio_frequency.set(434550);
-               get_int(line, "Radio enable:", radio_enable);
-               get_int(line, "Storage size:", storage_size);
-               get_int(line, "Storage erase unit:", storage_erase_unit);
-               get_int(line, "flight", stored_flight);
-               get_string(line, "Callsign:", callsign);
-               get_string(line,"software-version", version);
-               get_string(line,"product", product);
-               get_int(line, "Pyro-count:", npyro);
-       }
-
        final static int        serial_mode_read = 0;
        final static int        serial_mode_save = 1;
        final static int        serial_mode_reboot = 2;
@@ -230,63 +97,33 @@ public class AltosConfig implements ActionListener {
                AltosConfig     config;
                int             serial_mode;
 
-               void process_line(String line) {
-                       config.process_line(line);
-               }
-               void callback(String in_line) {
-                       final String line = in_line;
+               void callback(String in_cmd) {
+                       final String cmd = in_cmd;
                        Runnable r = new Runnable() {
                                        public void run() {
-                                               process_line(line);
+                                               if (cmd.equals("abort")) {
+                                                       abort();
+                                               } else if (cmd.equals("all finished")) {
+                                                       if (serial_line != null)
+                                                               update_ui();
+                                               }
                                        }
                                };
                        SwingUtilities.invokeLater(r);
                }
 
-               void reset_data() {
-                       serial.set(0);
-                       log_format.set(Altos.AO_LOG_FORMAT_UNKNOWN);
-                       main_deploy.set(250);
-                       apogee_delay.set(0);
-                       apogee_lockout.set(0);
-                       radio_channel.set(0);
-                       radio_setting.set(0);
-                       radio_frequency.set(0);
-                       radio_calibration.set(1186611);
-                       radio_enable.set(-1);
-                       flight_log_max.set(0);
-                       ignite_mode.set(-1);
-                       pad_orientation.set(-1);
-                       storage_size.set(-1);
-                       storage_erase_unit.set(-1);
-                       stored_flight.set(-1);
-                       callsign.set("N0CALL");
-                       version.set("unknown");
-                       product.set("unknown");
-                       pyro = 0;
-                       npyro.set(0);
-               }
-
                void get_data() {
+                       data = null;
                        try {
-                               config.start_serial();
-                               reset_data();
-
-                               config.serial_line.printf("c s\nf\nl\nv\n");
-                               for (;;) {
-                                       try {
-                                               String line = config.serial_line.get_reply(5000);
-                                               if (line == null)
-                                                       stop_serial();
-                                               callback(line);
-                                               if (line.startsWith("software-version"))
-                                                       break;
-                                       } catch (Exception e) {
-                                               break;
-                                       }
-                               }
+                               start_serial();
+                               data = new AltosConfigData(config.serial_line);
                        } catch (InterruptedException ie) {
                        } catch (TimeoutException te) {
+                               try {
+                                       stop_serial();
+                                       callback("abort");
+                               } catch (InterruptedException ie) {
+                               }
                        } finally {
                                try {
                                        stop_serial();
@@ -298,41 +135,11 @@ public class AltosConfig implements ActionListener {
 
                void save_data() {
                        try {
-                               double frequency = frequency();
-                               boolean has_frequency = radio_frequency.get() > 0;
-                               boolean has_setting = radio_setting.get() > 0;
                                start_serial();
-                               serial_line.printf("c m %d\n", main_deploy.get());
-                               serial_line.printf("c d %d\n", apogee_delay.get());
-                               serial_line.printf("c L %d\n", apogee_lockout.get());
-                               if (!remote)
-                                       serial_line.printf("c f %d\n", radio_calibration.get());
-                               serial_line.set_radio_frequency(frequency,
-                                                               has_frequency,
-                                                               has_setting,
-                                                               radio_calibration.get());
-                               if (remote) {
-                                       serial_line.stop_remote();
-                                       serial_line.set_radio_frequency(frequency);
-                                       AltosUIPreferences.set_frequency(device.getSerial(), frequency);
-                                       serial_line.start_remote();
-                               }
-                               serial_line.printf("c c %s\n", callsign.get());
-                               if (flight_log_max.get() != 0)
-                                       serial_line.printf("c l %d\n", flight_log_max.get());
-                               if (radio_enable.get() >= 0)
-                                       serial_line.printf("c e %d\n", radio_enable.get());
-                               if (ignite_mode.get() >= 0)
-                                       serial_line.printf("c i %d\n", ignite_mode.get());
-                               if (pad_orientation.get() >= 0)
-                                       serial_line.printf("c o %d\n", pad_orientation.get());
-                               if (pyros.length > 0) {
-                                       for (int p = 0; p < pyros.length; p++) {
-                                               serial_line.printf("c P %s\n",
-                                                                  pyros[p].toString());
-                                       }
-                               }
-                               serial_line.printf("c w\n");
+                               data.save(serial_line, remote);
+                               if (remote)
+                                       AltosUIPreferences.set_frequency(device.getSerial(),
+                                                                        data.frequency());
                        } catch (InterruptedException ie) {
                        } catch (TimeoutException te) {
                        } finally {
@@ -413,57 +220,29 @@ public class AltosConfig implements ActionListener {
        }
 
        double frequency() {
-               return AltosConvert.radio_to_frequency(radio_frequency.get(),
-                                                      radio_setting.get(),
-                                                      radio_calibration.get(),
-                                                      radio_channel.get());
-       }
-
-       void set_frequency(double freq) {
-               int     frequency = radio_frequency.get();
-               int     setting = radio_setting.get();
-
-               if (frequency > 0) {
-                       radio_frequency.set((int) Math.floor (freq * 1000 + 0.5));
-                       radio_channel.set(0);
-               } else if (setting > 0) {
-                       radio_setting.set(AltosConvert.radio_frequency_to_setting(freq,
-                                                                                 radio_calibration.get()));
-                       radio_channel.set(0);
-               } else {
-                       radio_channel.set(AltosConvert.radio_frequency_to_channel(freq));
-               }
+               return AltosConvert.radio_to_frequency(data.radio_frequency,
+                                                      data.radio_setting,
+                                                      data.radio_calibration,
+                                                      data.radio_channel);
        }
 
        void save_data() {
 
                /* bounds check stuff */
-               if (config_ui.flight_log_max() > log_limit()) {
+               if (config_ui.flight_log_max() > data.log_limit()) {
                        JOptionPane.showMessageDialog(owner,
                                                      String.format("Requested flight log, %dk, is larger than the available space, %dk.\n",
                                                                    config_ui.flight_log_max(),
-                                                                   log_limit()),
+                                                                   data.log_limit()),
                                                      "Maximum Flight Log Too Large",
                                                      JOptionPane.ERROR_MESSAGE);
                        return;
                }
 
-               main_deploy.set(config_ui.main_deploy());
-               apogee_delay.set(config_ui.apogee_delay());
-               apogee_lockout.set(config_ui.apogee_lockout());
-               radio_calibration.set(config_ui.radio_calibration());
-               set_frequency(config_ui.radio_frequency());
-               flight_log_max.set(config_ui.flight_log_max());
-               if (radio_enable.get() >= 0)
-                       radio_enable.set(config_ui.radio_enable());
-               if (ignite_mode.get() >= 0)
-                       ignite_mode.set(config_ui.ignite_mode());
-               if (pad_orientation.get() >= 0)
-                       pad_orientation.set(config_ui.pad_orientation());
-               callsign.set(config_ui.callsign());
-               if (npyro.get() > 0) {
-                       pyros = config_ui.pyros();
-               }
+               /* Pull data out of the UI and stuff back into our local data record */
+
+               data.get_values(config_ui);
+
                run_serial_thread(serial_mode_save);
        }
 
@@ -491,27 +270,6 @@ public class AltosConfig implements ActionListener {
        public AltosConfig(JFrame given_owner) {
                owner = given_owner;
 
-               serial = new int_ref(0);
-               log_format = new int_ref(Altos.AO_LOG_FORMAT_UNKNOWN);
-               main_deploy = new int_ref(250);
-               apogee_delay = new int_ref(0);
-               apogee_lockout = new int_ref(0);
-               radio_channel = new int_ref(0);
-               radio_setting = new int_ref(0);
-               radio_frequency = new int_ref(0);
-               radio_calibration = new int_ref(1186611);
-               radio_enable = new int_ref(-1);
-               flight_log_max = new int_ref(0);
-               ignite_mode = new int_ref(-1);
-               pad_orientation = new int_ref(-1);
-               storage_size = new int_ref(-1);
-               storage_erase_unit = new int_ref(-1);
-               stored_flight = new int_ref(-1);
-               callsign = new string_ref("N0CALL");
-               version = new string_ref("unknown");
-               product = new string_ref("unknown");
-               npyro = new int_ref(0);
-
                device = AltosDeviceDialog.show(owner, Altos.product_any);
                if (device != null) {
                        try {
index feac053be9ad0fc1ec358de8926c1ae5d1425231..95780e2b26a0484272728a0875a39da0aea1e3a8 100644 (file)
@@ -25,7 +25,7 @@ import org.altusmetrum.AltosLib.*;
 
 public class AltosConfigUI
        extends AltosDialog
-       implements ActionListener, ItemListener, DocumentListener
+       implements ActionListener, ItemListener, DocumentListener, AltosConfigValues
 {
 
        Container       pane;
@@ -39,6 +39,7 @@ public class AltosConfigUI
        JLabel          radio_calibration_label;
        JLabel          radio_frequency_label;
        JLabel          radio_enable_label;
+       JLabel          aprs_interval_label;
        JLabel          flight_log_max_label;
        JLabel          ignite_mode_label;
        JLabel          pad_orientation_label;
@@ -56,6 +57,7 @@ public class AltosConfigUI
        AltosFreqList   radio_frequency_value;
        JTextField      radio_calibration_value;
        JRadioButton    radio_enable_value;
+       JComboBox       aprs_interval_value;
        JComboBox       flight_log_max_value;
        JComboBox       ignite_mode_value;
        JComboBox       pad_orientation_value;
@@ -97,6 +99,13 @@ public class AltosConfigUI
                "Redundant Main",
        };
 
+       static String[] aprs_interval_values = {
+               "Disabled",
+               "2",
+               "5",
+               "10"
+       };
+
        static String[] pad_orientation_values = {
                "Antenna Up",
                "Antenna Down",
@@ -141,6 +150,13 @@ public class AltosConfigUI
                        radio_enable_value.setToolTipText("Firmware version does not support disabling radio");
        }
 
+       void set_aprs_interval_tool_tip() {
+               if (aprs_interval_value.isEnabled())
+                       aprs_interval_value.setToolTipText("Enable APRS and set the interval between APRS reports");
+               else
+                       aprs_interval_value.setToolTipText("Hardware doesn't support APRS");
+       }
+
        void set_flight_log_max_tool_tip() {
                if (flight_log_max_value.isEnabled())
                        flight_log_max_value.setToolTipText("Size reserved for each flight log (in kB)");
@@ -393,7 +409,7 @@ public class AltosConfigUI
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = il;
                c.ipady = 5;
-               radio_enable_label = new JLabel("Telemetry/RDF Enable:");
+               radio_enable_label = new JLabel("Telemetry/RDF/APRS Enable:");
                pane.add(radio_enable_label, c);
 
                c = new GridBagConstraints();
@@ -410,6 +426,32 @@ public class AltosConfigUI
                set_radio_enable_tool_tip();
                row++;
 
+               /* APRS interval */
+               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;
+               aprs_interval_label = new JLabel("APRS Interval(s):");
+               pane.add(aprs_interval_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;
+               aprs_interval_value = new JComboBox(aprs_interval_values);
+               aprs_interval_value.setEditable(true);
+               aprs_interval_value.addItemListener(this);
+               pane.add(aprs_interval_value, c);
+               set_aprs_interval_tool_tip();
+               row++;
+
                /* Callsign */
                c = new GridBagConstraints();
                c.gridx = 0; c.gridy = row;
@@ -684,6 +726,7 @@ public class AltosConfigUI
 
        public void set_apogee_delay(int new_apogee_delay) {
                apogee_delay_value.setSelectedItem(Integer.toString(new_apogee_delay));
+               apogee_delay_value.setEnabled(new_apogee_delay >= 0);
        }
 
        public int apogee_delay() {
@@ -692,6 +735,7 @@ public class AltosConfigUI
 
        public void set_apogee_lockout(int new_apogee_lockout) {
                apogee_lockout_value.setSelectedItem(Integer.toString(new_apogee_lockout));
+               apogee_lockout_value.setEnabled(new_apogee_lockout >= 0);
        }
 
        public int apogee_lockout() {
@@ -829,13 +873,10 @@ public class AltosConfigUI
                        return -1;
        }
 
-       public void set_has_pyro(boolean has_pyro) {
-               pyro.setEnabled(has_pyro);
-       }
-
        public void set_pyros(AltosPyro[] new_pyros) {
                pyros = new_pyros;
-               if (pyro_ui != null)
+               pyro.setEnabled(pyros != null);
+               if (pyros != null && pyro_ui != null)
                        pyro_ui.set_pyros(pyros);
        }
 
@@ -844,4 +885,24 @@ public class AltosConfigUI
                        pyros = pyro_ui.get_pyros();
                return pyros;
        }
+
+       public void set_aprs_interval(int new_aprs_interval) {
+               String  s;
+
+               if (new_aprs_interval <= 0)
+                       s = "Disabled";
+               else
+                       s = Integer.toString(new_aprs_interval);
+               aprs_interval_value.setSelectedItem(s);
+               aprs_interval_value.setEnabled(new_aprs_interval >= 0);
+               set_aprs_interval_tool_tip();
+       }
+
+       public int aprs_interval() {
+               String  s = aprs_interval_value.getSelectedItem().toString();
+
+               if (s.equals("Disabled"))
+                       return 0;
+               return Integer.parseInt(s);
+       }
 }
index 75e536c583776e363693b5d3ff993aaf9b16893f..62d516b24f7782e1a1343409ed9b8c1d602e5012 100644 (file)
@@ -68,11 +68,13 @@ class AltosGraphTime extends AltosGraph {
     abstract static class TimeSeries implements Element {
         protected XYSeries series;
         private String axisName;
+       private String axisUnits;
         private Color color;
 
-        public TimeSeries(String axisName, String label, Color color) {
+        public TimeSeries(String axisName, String axisUnits, String label, Color color) {
             this.series = new XYSeries(label);
-            this.axisName = axisName;
+            this.axisName = String.format("%s (%s)", axisName, axisUnits);
+           this.axisUnits = axisUnits;
             this.color = color;
         }
 
@@ -85,8 +87,14 @@ class AltosGraphTime extends AltosGraph {
             XYSeriesCollection dataset = new XYSeriesCollection();
             dataset.addSeries(this.series);
 
-            XYItemRenderer renderer = new StandardXYItemRenderer();
+            XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
             renderer.setSeriesPaint(0, color);
+           StandardXYToolTipGenerator  tool_tip;
+
+           tool_tip = new StandardXYToolTipGenerator(String.format("{1}s: {2}%s ({0})", axisUnits),
+                                                     new java.text.DecimalFormat("0.00"),
+                                                     new java.text.DecimalFormat("0.00"));
+           renderer.setBaseToolTipGenerator(tool_tip);
 
             int dataNum = g.getDataNum(this);
             int axisNum = g.getAxisNum(this);
@@ -192,10 +200,8 @@ class AltosGraphTime extends AltosGraph {
     public JFreeChart createChart() {
         NumberAxis xAxis = new NumberAxis("Time (s)");
         xAxis.setAutoRangeIncludesZero(false);
-        XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
         XYPlot plot = new XYPlot();
         plot.setDomainAxis(xAxis);
-        plot.setRenderer(renderer);
         plot.setOrientation(PlotOrientation.VERTICAL);
 
         if (serial != null && flight != null) {
@@ -205,7 +211,6 @@ class AltosGraphTime extends AltosGraph {
             title = callsign + " - " + title;
         }
 
-        renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
         JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT,
                                 plot, true);
         ChartUtilities.applyCurrentTheme(chart);
index f59f70bab47781daf0783e747875e2ec45542152..b7c2e92e74c07ea3cad46cba633e71f88fe5bc71 100644 (file)
@@ -29,7 +29,7 @@ public class AltosGraphUI extends AltosFrame
 
     static private class OverallGraphs {
         AltosGraphTime.Element height = 
-               new AltosGraphTime.TimeSeries(String.format("Height (%s)", AltosConvert.height.show_units()), "Height (AGL)", red) {
+               new AltosGraphTime.TimeSeries("Height", AltosConvert.height.show_units(), "Height (AGL)", red) {
                 public void gotTimeData(double time, AltosDataPoint d) {
                        double  height = d.height();
                        if (height != AltosRecord.MISSING)
@@ -38,7 +38,7 @@ public class AltosGraphUI extends AltosFrame
             };
     
         AltosGraphTime.Element speed =
-               new AltosGraphTime.TimeSeries(String.format("Speed (%s)", AltosConvert.speed.show_units()), "Vertical Speed", green) { 
+               new AltosGraphTime.TimeSeries("Speed", AltosConvert.speed.show_units(), "Vertical Speed", green) { 
                 public void gotTimeData(double time, AltosDataPoint d) {
                    double      speed = d.speed();
                    if (speed != AltosRecord.MISSING)
@@ -47,8 +47,8 @@ public class AltosGraphUI extends AltosFrame
             };
     
         AltosGraphTime.Element acceleration =
-               new AltosGraphTime.TimeSeries(String.format("Acceleration (%s)",
-                                                           AltosConvert.accel.show_units()),
+               new AltosGraphTime.TimeSeries("Acceleration",
+                                             AltosConvert.accel.show_units(),
                                              "Axial Acceleration", blue)
             {
                 public void gotTimeData(double time, AltosDataPoint d) {
@@ -59,8 +59,8 @@ public class AltosGraphUI extends AltosFrame
             };
     
         AltosGraphTime.Element temperature =
-            new AltosGraphTime.TimeSeries("Temperature (\u00B0C)", 
-                    "Board temperature", red) 
+           new AltosGraphTime.TimeSeries("Temperature", "\u00B0C", 
+                                         "Board temperature", red) 
             {
                 public void gotTimeData(double time, AltosDataPoint d) {
                    double temp = d.temperature();
@@ -70,7 +70,7 @@ public class AltosGraphUI extends AltosFrame
             };
     
         AltosGraphTime.Element drogue_voltage =
-            new AltosGraphTime.TimeSeries("Voltage (V)", "Drogue Continuity", yellow) 
+            new AltosGraphTime.TimeSeries("Voltage", "(V)", "Drogue Continuity", yellow) 
             {
                 public void gotTimeData(double time, AltosDataPoint d) {
                    double v = d.drogue_voltage();
@@ -80,7 +80,7 @@ public class AltosGraphUI extends AltosFrame
             };
     
         AltosGraphTime.Element main_voltage =
-            new AltosGraphTime.TimeSeries("Voltage (V)", "Main Continuity", magenta) 
+            new AltosGraphTime.TimeSeries("Voltage", "(V)", "Main Continuity", magenta) 
             {
                 public void gotTimeData(double time, AltosDataPoint d) {
                    double v = d.main_voltage();
index 257fdaece07f7d4a060c1125cdd305700a8faaba..871b8205705757aa1b86f1045474316435bfc993 100644 (file)
@@ -1 +1 @@
-SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list ao-load ao-telem ao-stmload ao-send-telem
+SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list ao-load ao-telem ao-stmload ao-send-telem ao-sky-flash
diff --git a/ao-tools/ao-sky-flash/Makefile.am b/ao-tools/ao-sky-flash/Makefile.am
new file mode 100644 (file)
index 0000000..f6c5089
--- /dev/null
@@ -0,0 +1,18 @@
+bin_PROGRAMS=ao-sky-flash
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AO_SKY_FLASH_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_sky_flash_DEPENDENCIES = $(AO_SKY_FLASH_LIBS)
+
+ao_sky_flash_LDADD=$(AO_SKY_FLASH_LIBS) $(LIBUSB_LIBS)
+
+ao_sky_flash_SOURCES = \
+       sky_bin.c \
+       sky_debug.c \
+       sky_flash.c \
+       sky_flash.h \
+       sky_serial.c \
+       sky_srec.c
+
+man_MANS = ao-sky-flash.1
diff --git a/ao-tools/ao-sky-flash/STI_01.04.42-01.10.23_4x_9600_Bin_20100901.bin b/ao-tools/ao-sky-flash/STI_01.04.42-01.10.23_4x_9600_Bin_20100901.bin
new file mode 100644 (file)
index 0000000..c698add
Binary files /dev/null and b/ao-tools/ao-sky-flash/STI_01.04.42-01.10.23_4x_9600_Bin_20100901.bin differ
diff --git a/ao-tools/ao-sky-flash/STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.bin b/ao-tools/ao-sky-flash/STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.bin
new file mode 100644 (file)
index 0000000..9e25689
Binary files /dev/null and b/ao-tools/ao-sky-flash/STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.bin differ
diff --git a/ao-tools/ao-sky-flash/ao-sky-flash.1 b/ao-tools/ao-sky-flash/ao-sky-flash.1
new file mode 100644 (file)
index 0000000..d61c9c9
--- /dev/null
@@ -0,0 +1,85 @@
+.\"
+.\" Copyright © 2009 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.
+.\"
+.\" 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.
+.\"
+.\"
+.TH AO-SKY-FLASH 1 "ao-sky-flash" ""
+.SH NAME
+ao-sky-flash \- flash GPS firmware program to a SkyTraq GPS chip
+.SH SYNOPSIS
+.B "ao-sky-flash"
+[\-T \fItty-device\fP]
+[\--tty \fItty-device\fP]
+[\-D \fIaltos-device\fP]
+[\--device \fIaltos-device\fP]
+[\--loader \fIboot-loader\fP]
+[\--firmware \fIgps-firmware\fP]
+[\--query]
+[\--quiet]
+[\--raw]
+.SH DESCRIPTION
+.I ao-sky-flash
+loads the specified GPS firmware file into the target GPS chip flash
+memory using the specified boot loader.
+.SH OPTIONS
+.TP
+\-T tty-device | --tty tty-device
+This selects which tty device the debugger uses to communicate with
+the target device.
+.TP
+\-D AltOS-device | --device AltOS-device
+Search for a connected device. This requires an argument of one of the
+following forms:
+.IP
+TeleMetrum:2
+.br
+TeleMetrum
+.br
+2
+.IP
+Leaving out the product name will cause the tool to select a suitable
+product, leaving out the serial number will cause the tool to match
+one of the available devices.
+.TP
+\--loader boot-loader
+This specifies the desired boot loader to use for reflashing the
+device. You should use srec_115200.bin unless you have a good reason
+not to. This should be in S record format.
+.TP
+\--firmware gps-firmware
+This specifies the new GPS firmware image to load onto the target GPS
+chip. No checking is done on this device at all; flash garbage and the
+GPS chip will probably fail to boot.
+.TP
+\--query
+Instead of loading new firmware, query the current version of firmware
+running on the target device.
+.TP
+\--quiet
+Normally, ao-spy-flash is quite chatty. This shuts it up, except for
+error messages.
+.TP
+\--raw
+The expected target for reflashing is an Altus Metrum product with the
+GPS chip connected to the CPU on that board and not directly to the
+USB serial port. This option says that the target GPS chip is directly
+connected, which changes how things are initialized a bit.
+.SH USAGE
+.I ao-sky-flash
+loads the specified bootloader into device RAM and then uses that to
+load new firmware to flash.
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-sky-flash/sky_bin.c b/ao-tools/ao-sky-flash/sky_bin.c
new file mode 100644 (file)
index 0000000..04cfec3
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright © 2012 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 "sky_flash.h"
+#include <stdio.h>
+#include <string.h>
+
+#define FLASHBYTES     8192
+
+int
+skytraq_send_bin(int fd, const char *filename)
+{
+       FILE            *file;
+       char            buf[FLASHBYTES];
+       int             count;
+       unsigned char   cksum;
+       int             c;
+       long            size;
+       long            pos;
+       char            message[1024];
+       int             ret;
+       
+       file = fopen(filename, "r");
+       if (!file) {
+               perror(filename);
+               return -1;
+       }
+
+       /* Compute checksum, figure out how long the file */
+       cksum = 0;
+       while ((c = getc(file)) != EOF)
+               cksum += (unsigned char) c;
+       size = ftell(file);
+       rewind(file);
+
+       sprintf(message, "BINSIZE = %d Checksum = %d Loopnumber = %d ", size, cksum, 1);
+
+       ret = skytraq_cmd_wait(fd, message, strlen(message) + 1, "OK", 20000);
+       if (ret < 0)
+               printf ("waitstatus failed %d\n", ret);
+
+       pos = 0;
+       for (;;) {
+               count = fread(buf, 1, sizeof (buf), file);
+               if (count < 0) {
+                       perror("fread");
+                       fclose(file);
+                       return -1;
+               }
+               if (count == 0)
+                       break;
+               skytraq_dbg_printf (0, "%7d of %7d ", pos + count, size);
+               pos += count;
+               ret = skytraq_cmd_wait(fd, buf, count, "OK", 20000);
+               if (ret < 0)
+                       return ret;
+       }
+       return skytraq_waitstatus(fd, "END", 30000);
+}
diff --git a/ao-tools/ao-sky-flash/sky_debug.c b/ao-tools/ao-sky-flash/sky_debug.c
new file mode 100644 (file)
index 0000000..32571f0
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2012 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 <stdint.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include "sky_flash.h"
+
+static int     dbg_input;
+static int     dbg_newline = 1;
+
+int
+skytraq_millis(void)
+{
+       struct timeval  tv;
+       gettimeofday(&tv, NULL);
+       return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
+static void
+skytraq_dbg_time(void)
+{
+       int     delta = skytraq_millis() - skytraq_open_time;
+
+       if (!skytraq_verbose)
+               return;
+       printf ("%4d.%03d ", delta / 1000, delta % 1000);
+}
+
+void
+skytraq_dbg_newline(void)
+{
+       if (!skytraq_verbose)
+               return;
+       if (!dbg_newline) {
+               putchar('\n');
+               dbg_newline = 1;
+       }
+}
+
+static void
+skytraq_dbg_set(int input)
+{
+       if (!skytraq_verbose)
+               return;
+       if (input != dbg_input) {
+               skytraq_dbg_newline();
+               if (input)
+                       putchar('\t');
+               dbg_input = input;
+       }
+}
+
+void
+skytraq_dbg_char(int input, char c)
+{
+       if (!skytraq_verbose)
+               return;
+       skytraq_dbg_set(input);
+       if (dbg_newline)
+               skytraq_dbg_time();
+       if (c < ' '  || c > '~')
+               printf ("\\%02x", (unsigned char) c);
+       else
+               putchar(c);
+       dbg_newline = 0;
+       if (c == '\n')
+               dbg_input = 2;
+       fflush(stdout);
+}
+
+void
+skytraq_dbg_buf(int input, const char *buf, int len)
+{
+       if (!skytraq_verbose)
+               return;
+       while (len--)
+               skytraq_dbg_char(input, *buf++);
+}
+
+void
+skytraq_dbg_printf(int input, const char *fmt, ...)
+{
+       va_list ap;
+
+       if (!skytraq_verbose)
+               return;
+       skytraq_dbg_set(input);
+       if (dbg_newline)
+               skytraq_dbg_time();
+       va_start (ap, fmt);
+       vprintf(fmt, ap);
+       va_end(ap);
+       dbg_newline = 0;
+}
diff --git a/ao-tools/ao-sky-flash/sky_flash.c b/ao-tools/ao-sky-flash/sky_flash.c
new file mode 100644 (file)
index 0000000..55cb2cb
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright © 2012 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 "sky_flash.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include "cc.h"
+
+static const struct option options[] = {
+       { .name = "tty", .has_arg = 1, .val = 'T' },
+       { .name = "device", .has_arg = 1, .val = 'D' },
+       { .name = "loader", .has_arg = 1, .val = 'l' },
+       { .name = "firmware", .has_arg = 1, .val = 'f' },
+       { .name = "query", .has_arg = 0, .val = 'q' },
+       { .name = "raw", .has_arg = 0, .val = 'r' },
+       { .name = "quiet", .has_arg = 0, .val = 'Q' },
+       { 0, 0, 0, 0},
+};
+
+static uint8_t query_version[] = {
+       0xa0, 0xa1, 0x00, 0x02, 0x02, 0x01, 0x03, 0x0d, 0x0a
+};
+
+static void
+usage(char *program)
+{
+       fprintf(stderr,
+               "usage: %s [--tty <tty-name>]\n"
+               "          [--device <device-name>]\n"
+               "          [--loader <srec bootloader file>]\n"
+               "          [--firmware <binary firmware file>]\n"
+               "          [--query]\n"
+               "          [--quiet]\n"
+               "          [--raw]\n", program);
+       exit(1);
+}
+
+int
+skytraq_expect(int fd, uint8_t want, int timeout) {
+       int     c;
+
+       c = skytraq_waitchar(fd, timeout);
+       if (c < 0)
+               return -1;
+       if (c == want)
+               return 1;
+       return 0;
+}
+
+int
+skytraq_wait_reply(int fd, uint8_t reply, uint8_t *buf, uint8_t reply_len) {
+
+       for(;;) {
+               uint8_t a, b;
+               uint8_t cksum_computed, cksum_read;
+               int     len;
+               switch (skytraq_expect(fd, 0xa0, 10000)) {
+               case -1:
+                       return -1;
+               case 0:
+                       continue;
+               case 1:
+                       break;
+               }
+               switch (skytraq_expect(fd, 0xa1, 1000)) {
+               case -1:
+                       return -1;
+               case 0:
+                       continue;
+               }
+               a = skytraq_waitchar(fd, 1000);
+               b = skytraq_waitchar(fd, 1000);
+               switch (skytraq_expect(fd, reply, 1000)) {
+               case -1:
+                       return -1;
+               case 0:
+                       continue;
+               }
+               len = (a << 16) | b;
+               if (len != reply_len)
+                       continue;
+               *buf++ = reply;
+               len--;
+               cksum_computed = reply;
+               while (len--) {
+                       a = skytraq_waitchar(fd, 1000);
+                       if (a < 0)
+                               return a;
+                       cksum_computed ^= a;
+                       *buf++ = a;
+               }
+               switch (skytraq_expect(fd, cksum_computed, 1000)) {
+               case -1:
+                       return -1;
+               case 0:
+                       continue;
+               }
+               switch (skytraq_expect(fd, 0x0d, 1000)) {
+               case -1:
+                       return -1;
+               case 0:
+                       continue;
+               }
+               switch (skytraq_expect(fd, 0x0a, 1000)) {
+               case -1:
+                       return -1;
+               case 0:
+                       continue;
+               }
+               break;
+       }
+       return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+       int     fd;
+       char    buf[512];
+       int     ret;
+       FILE    *input;
+       long    size;
+       unsigned char   cksum;
+       int     c;
+       char    message[1024];
+       char    *tty = NULL;
+       char    *device = NULL;
+       char    *loader = "srec_115200.bin";
+       char    *file = NULL;
+       int     query = 0;
+       int     raw = 0;
+
+       while ((c = getopt_long(argc, argv, "T:D:l:f:qQr", options, NULL)) != -1) {
+               switch (c) {
+               case 'T':
+                       tty = optarg;
+                       break;
+               case 'D':
+                       device = optarg;
+                       break;
+               case 'l':
+                       loader = optarg;
+                       break;
+               case 'f':
+                       file = optarg;
+                       break;
+               case 'q':
+                       query = 1;
+                       break;
+               case 'Q':
+                       skytraq_verbose = 0;
+                       break;
+               case 'r':
+                       raw = 1;
+                       break;
+               default:
+                       usage(argv[0]);
+                       break;
+               }
+       }
+
+       if (!tty)
+               tty = cc_usbdevs_find_by_arg(device, "TeleMetrum");
+       if (!tty)
+               tty = getenv("ALTOS_TTY");
+       if (!tty)
+               tty="/dev/ttyACM0";
+       fd = skytraq_open(tty);
+       if (fd < 0)
+               exit(1);
+
+       if (raw) {
+               /* Set the baud rate to 115200 */
+               skytraq_setcomm(fd, 115200);
+               sleep(1);
+               skytraq_setspeed(fd, 115200);
+       } else {
+               /* Connect TM to the device */
+               skytraq_write(fd, "U\n", 2);
+       }
+
+       /* Wait for the device to stabilize after baud rate changes */
+       for (c = 0; c < 6; c++) {
+               skytraq_flush(fd);
+               sleep(1);
+       }
+
+       if (query) {
+               uint8_t query_reply[14];
+
+               uint8_t         software_type;
+               uint32_t        kernel_version;
+               uint32_t        odm_version;
+               uint32_t        revision;
+
+               skytraq_write(fd, query_version, 9);
+               if (skytraq_wait_reply(fd, 0x80, query_reply, sizeof (query_reply)) != 0) {
+                       fprintf(stderr, "query reply failed\n");
+                       exit(1);
+               }
+
+#define i8(o)  query_reply[(o)-1]
+#define i32(o) ((i8(o) << 24) | (i8(o+1) << 16) | (i8(o+2) << 8) | (i8(o+3)))
+               software_type = i8(2);
+               kernel_version = i32(3);
+               odm_version = i32(7);
+               revision = i32(11);
+               skytraq_dbg_printf(0, "\n");
+               printf ("Software Type %d. Kernel Version %d.%d.%d. ODM Version %d.%d.%d. Revision %d.%d.%d.\n",
+                       software_type,
+                       kernel_version >> 16 & 0xff,
+                       kernel_version >> 8 & 0xff,
+                       kernel_version >> 0 & 0xff,
+                       odm_version >> 16 & 0xff,
+                       odm_version >> 8 & 0xff,
+                       odm_version >> 0 & 0xff,
+                       revision >> 16 & 0xff,
+                       revision >> 8 & 0xff,
+                       revision >> 0 & 0xff);
+               exit(0);
+       }
+
+       if (!file)
+               usage(argv[0]);
+
+       ret = skytraq_send_srec(fd, "srec_115200.bin");
+       skytraq_dbg_printf (0, "srec ret %d\n", ret);
+       if (ret < 0)
+               exit(1);
+
+       sleep(2);
+
+//     ret = skytraq_send_bin(fd, "STI_01.04.42-01.10.23_4x_9600_Bin_20100901.bin");
+       ret = skytraq_send_bin(fd, "STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.bin");
+
+       printf ("bin ret %d\n", ret);
+       if (ret < 0)
+               exit(1);
+
+       return 0;
+}
diff --git a/ao-tools/ao-sky-flash/sky_flash.h b/ao-tools/ao-sky-flash/sky_flash.h
new file mode 100644 (file)
index 0000000..77f4c74
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2012 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.
+ */
+
+/* sky_serial.c */
+
+extern int     skytraq_open_time;
+extern int     skytraq_verbose;
+
+int
+skytraq_open(const char *path);
+
+int
+skytraq_setspeed(int fd, int baud);
+
+int
+skytraq_setcomm(int fd, int baudrate);
+
+int
+skytraq_write(int fd, const char *data, int len);
+
+int
+skytraq_waitchar(int fd, int timeout);
+
+int
+skytraq_waitstatus(int fd, const char *status, int timeout);
+
+void
+skytraq_flush(int fd);
+
+int
+skytraq_cmd_wait(int fd, const char *message, int len, const char *status, int timeout);
+
+int
+skytraq_cmd_nowait(int fd, const char *message, int len);
+
+/* sky_debug.c */
+
+void
+skytraq_dbg_printf(int input, const char *fmt, ...);
+
+void
+skytraq_dbg_buf(int input, const char *buf, int len);
+
+void
+skytraq_dbg_char(int input, char c);
+
+/* sky_srec.c */
+int
+skytraq_send_srec(int fd, const char *file);
+
+/* sky_bin.c */
+int
+skytraq_send_bin(int fd, const char *filename);
diff --git a/ao-tools/ao-sky-flash/sky_serial.c b/ao-tools/ao-sky-flash/sky_serial.c
new file mode 100644 (file)
index 0000000..7230bf8
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright © 2012 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.
+ */
+
+#define _BSD_SOURCE
+#include <termios.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <poll.h>
+#include "sky_flash.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+int    skytraq_verbose = 1;
+
+int
+skytraq_setspeed(int fd, int baud)
+{
+       int     b;
+       int     ret;
+       struct termios  term;
+
+       switch (baud) {
+       case 9600:
+               b = B9600;
+               break;
+       case 38400:
+               b = B38400;
+               break;
+       case 115200:
+               b = B115200;
+               break;
+       default:
+               fprintf (stderr, "Invalid baudrate %d\n", baud);
+               return -1;
+       }
+       ret = tcgetattr(fd, &term);
+       cfmakeraw(&term);
+#ifdef USE_POLL
+       term.c_cc[VMIN] = 1;
+       term.c_cc[VTIME] = 0;
+#else
+       term.c_cc[VMIN] = 0;
+       term.c_cc[VTIME] = 1;
+#endif
+
+       cfsetspeed(&term, b);
+
+       ret = tcsetattr(fd, TCSAFLUSH, &term);
+       return ret;
+}
+
+int    skytraq_open_time;
+
+int
+skytraq_open(const char *path)
+{
+       int             fd;
+       int             ret;
+
+       fd = open(path, O_RDWR | O_NOCTTY);
+       if (fd < 0) {
+               perror (path);
+               return -1;
+       }
+
+       ret = skytraq_setspeed(fd, 9600);
+       if (ret < 0) {
+               close (fd);
+               return -1;
+       }
+       skytraq_open_time = skytraq_millis();
+       return fd;
+}
+
+
+#define BAUD           57600
+#define BPS            (BAUD/10 * 9/10)
+#define US_PER_CHAR    (1000000 / BPS)
+
+int
+skytraq_write(int fd, const char *data, int len)
+{
+       const char *d = data;
+       int             r;
+       int             us;
+
+       skytraq_dbg_printf (0, "%4d: ", len);
+       if (len < 70)
+               skytraq_dbg_buf(0, data, len);
+       while (len) {
+               int     this_time = len;
+               if (this_time > 128)
+                       this_time = 128;
+               skytraq_dbg_printf(0, ".");
+               fflush(stdout);
+               r = write(fd, data, this_time);
+               if (r <= 0)
+                       return r;
+               us = r * US_PER_CHAR;
+               usleep(r * US_PER_CHAR);
+               data += r;
+               len -= r;
+       }
+       skytraq_dbg_newline();
+       return 1;
+}
+
+int
+skytraq_setcomm(int fd, int baudrate)
+{
+       uint8_t msg[11];
+       int     i;
+       uint8_t cksum;
+
+       int target_baudrate;
+       switch(baudrate)
+       {
+       case 4800:
+               target_baudrate=0;
+               break;
+       case 9600:
+               target_baudrate=1;
+               break;
+       case 19200:
+               target_baudrate=2;
+               break;
+       case 38400:
+               target_baudrate=3;
+               break;
+       case 57600:
+               target_baudrate=4;
+               break;
+       case 115200:
+               target_baudrate=5;
+               break;
+       case 230400:
+               target_baudrate=6;
+               break;
+       }
+       msg[0] = 0xa0;  /* header */
+       msg[1] = 0xa1;
+       msg[2] = 0x00;  /* length */
+       msg[3] = 0x04;
+       msg[4] = 0x05;  /* configure serial port */
+       msg[5] = 0x00;  /* COM 1 */
+       msg[6] = target_baudrate;
+       msg[7] = 0x00;  /* update to SRAM only */
+
+       cksum = 0;
+       for (i = 4; i < 8; i++)
+               cksum ^= msg[i];
+       msg[8] = cksum;
+       msg[9] = 0x0d;
+       msg[10] = 0x0a;
+       return skytraq_write(fd, msg, 11);
+}
+
+int
+skytraq_waitchar(int fd, int timeout)
+{
+       struct pollfd   fds[1];
+       int             ret;
+       unsigned char   c;
+
+       for (;;) {
+               fds[0].fd = fd;
+               fds[0].events = POLLIN;
+               ret = poll(fds, 1, timeout);
+               if (ret >= 1) {
+                       if (fds[0].revents & POLLIN) {
+                               ret = read(fd, &c, 1);
+                               if (ret == 1) {
+                                       skytraq_dbg_char(1, c);
+                                       return c;
+                               }
+                       }
+               } else if (ret == 0)
+                       return -2;
+               else {
+                       perror("poll");
+                       return -1;
+               }
+       }
+}
+
+int
+skytraq_waitstatus(int fd, const char *status, int timeout)
+{
+       const char      *s;
+       int             c;
+
+       for (;;) {
+               c = skytraq_waitchar(fd, timeout);
+               if (c < 0) {
+                       skytraq_dbg_newline();
+                       return c;
+               }
+               if ((char) c == *status) {
+                       s = status + 1;
+                       for (;;) {
+                               c = skytraq_waitchar(fd, timeout);
+                               if (c < 0) {
+                                       skytraq_dbg_newline();
+                                       return c;
+                               }
+                               if ((char) c != *s)
+                                       break;
+                               if (!*s) {
+                                       skytraq_dbg_newline();
+                                       return 0;
+                               }
+                               s++;
+                       }
+               }
+       }
+}
+
+void
+skytraq_flush(int fd)
+{
+       while (skytraq_waitchar(fd, 1) >= 0)
+               ;
+}
+
+int
+skytraq_cmd_wait(int fd, const char *message, int len, const char *status, int timeout)
+{
+       skytraq_flush(fd);
+       skytraq_write(fd, message, len);
+       return skytraq_waitstatus(fd, status, timeout);
+}
+
+int
+skytraq_cmd_nowait(int fd, const char *message, int len)
+{
+       skytraq_flush(fd);
+       return skytraq_write(fd, message, len);
+}
diff --git a/ao-tools/ao-sky-flash/sky_srec.c b/ao-tools/ao-sky-flash/sky_srec.c
new file mode 100644 (file)
index 0000000..6d00f58
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2012 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 "sky_flash.h"
+#include <stdio.h>
+#include <string.h>
+
+static const char loader_start[] = "$LOADER DOWNLOAD";
+
+int
+skytraq_send_srec(int fd, const char *filename)
+{
+       FILE    *file;
+       int     ret;
+       char    line[1024];
+
+       file = fopen(filename, "r");
+       if (!file) {
+               perror(filename);
+               return -1;
+       }
+
+       ret = skytraq_cmd_wait(fd, loader_start, strlen(loader_start) + 1, "OK", 1000);
+       if (ret)
+               return ret;
+
+       for (;;) {
+               char    *s;
+               int     len;
+
+               s = fgets(line, sizeof(line), file);
+               if (!s)
+                       break;
+               len = strlen(s);
+               if (len < 3)            /* Terminated with \r\n */
+                       break;
+               s[len-2] = '\n';        /* Smash \r */
+               s[len-1] = '\0';        /* Smash \n */
+               skytraq_cmd_nowait(fd, s, len);
+       }
+       fclose(file);
+
+       ret = skytraq_waitstatus(fd, "END", 10000);
+       skytraq_dbg_newline();
+       return ret;
+}
diff --git a/ao-tools/ao-sky-flash/srec_115200.bin b/ao-tools/ao-sky-flash/srec_115200.bin
new file mode 100644 (file)
index 0000000..8ea8e7c
--- /dev/null
@@ -0,0 +1,346 @@
+S0130000666C6173683131353230302E73726563DA\r
+S31550000000033FFFF7821063209DE380011920000013\r
+S31550000010D2030000173FFFF79612E3E4AC07BFF890\r
+S31550000020D225800BD005800B133FFFC0900A0009E4\r
+S3155000003090122977D0230000E00320901B0800136C\r
+S31550000040C0232090D20320149E136018D225800B13\r
+S31550000050D005800B1300180090120009900A3FF04B\r
+S31550000060D0232014D20300001100003FD225800B6C\r
+S31550000070D405800B901223FF940A800813043E0087\r
+S3155000008094128009D4230000D003C0009A13601C38\r
+S31550000090D025800BD205800B11004000902A4008D5\r
+S315500000A0D023C000D403400011000040D425800B5B\r
+S315500000B0D205800BA00C204092124008A13C20068D\r
+S315500000C011140005E02A2180D2234000B8102000E8\r
+S315500000D0400004C890102005130004004000017031\r
+S315500000E090102001213FFFF84000036F90058010CB\r
+S315500000F0A014200A92058010B6102000B4102000DB\r
+S31550000100A6102000AE10200096102000D00A400005\r
+S3155000011080A2202002800006920260019602E00131\r
+S3155000012080A2E06324BFFFFBD00A40009810200055\r
+S3155000013080A3000B1680000F113FFFF89012200A83\r
+S31550000140940580089810000B912CE0029002001341\r
+S31550000150D20A8000912A200190020009A6023FD0BF\r
+S3155000016098833FFF12BFFFF99402A0019810000B2D\r
+S315500001709205800C113FFFF894024008961020001B\r
+S315500001809002800BD20A201680A2602002800007BF\r
+S3155000019080A2E0009602E00180A2E06304BFFFFA6D\r
+S315500001A09002800B80A2E0000480000F113FFFF800\r
+S315500001B09205800C9012201698024008900DE0FF90\r
+S315500001C0932A2002D40B000092024008932A600121\r
+S315500001D094028009AE02BFD09682FFFF12BFFFF88D\r
+S315500001E098032001133FFFF794126384921263869B\r
+S315500001F090078009400001A89207800A80A220003B\r
+S3155000020002800122153FFFF79012A386D21780086D\r
+S3155000021080A2601C0280010E9012A384113FFFF74A\r
+S31550000220961223849012238692102037D237800854\r
+S31550000230941020B5D437800B900F2001213FFFF743\r
+S31550000240AB2A201392142386110001E1D41780099A\r
+S3155000025090122154A2142384A4054008D617801165\r
+S3155000026090100012400002289210202080A22000F8\r
+S31550000270028000CA11140005B0100010B21000110F\r
+S31550000280A0102000113FFFEA80A420000280000445\r
+S315500002909212225511000015921221AA912A60102D\r
+S315500002A0A8162386A3322010D617801990048010E2\r
+S315500002B0D417801492102002400001DA98100011D1\r
+S315500002C080A22000028000B511140005D0148010C1\r
+S315500002D080A44008128000B0A004200280A420030D\r
+S315500002E004BFFFEA113FFFEA213FFFF79214238430\r
+S315500002F0D617800990100012D417801440000202BD\r
+S3155000030092102020170001DF9012E3F8D20200006D\r
+S31550000310941423E4D225800AA01423E0C02580102B\r
+S31550000320D005800A80A23FFF228000BB9012E3FCDA\r
+S31550000330113FFFF7A2122384A0122386110001C198\r
+S31550000340D417801090122154D61780119210202065\r
+S31550000350400001ED90054008110001E9D4178010C6\r
+S3155000036090122154D617801192102020400001E699\r
+S3155000037090054008110001F1D417801090122154B5\r
+S31550000380D617801192102020400001DF90054008BA\r
+S31550000390133FFFF8D00D800980A220421280000B37\r
+S315500003A0A410001392058009D00A600180A220494A\r
+S315500003B03280000721140005D00A600280A2204E28\r
+S315500003C022800008D417801021140005400002F640\r
+S315500003D09014202890142028400002F39E03FCF02D\r
+S315500003E090102000D6178011400001C792100013BC\r
+S315500003F080A2200022800069111400051114000506\r
+S31550000400400002E990122030400000BE010000007A\r
+S3155000041011000007A81223FFB010001480A4801406\r
+S31550000420148000031300000892100012113FFFF8C9\r
+S315500004304000036F90058008A2922000028000734E\r
+S31550000440A010200080A40011B40680111A8000214B\r
+S31550000450A4248011333FFFF71100003FAA1223FF57\r
+S31550000460BA1663849810001092102000A00420023F\r
+S31550000470173FFFF89005800CD40A000B932A6008AA\r
+S315500004809803200180A3001006BFFFFB9212400A7A\r
+S31550000490912A60109932201080A300150280000A1C\r
+S315500004A090166386D417800892102002D617801DA6\r
+S315500004B04000015C9010001B80A220000280003793\r
+S315500004C01114000580A400110ABFFFE7B606E0022A\r
+S315500004D0900E801880A0000892603FFF80A0001206\r
+S315500004E090603FFF809240080280000680A68013ED\r
+S315500004F011140005400002AC9012203080A68013E3\r
+S3155000050012BFFFC880A480149410200080A28013CC\r
+S315500005101680000996102000D21280009132600891\r
+S315500005209002C0089402A00280A2801306BFFFFB6F\r
+S3155000053096020009920AE0FF900DE0FF80A2400863\r
+S31550000540028000041114000510BFFFA49012203839\r
+S31550000550153FFFF79012A3E0D205800880A26001F4\r
+S31550000560128000109212A3849012A386D41780088A\r
+S3155000057098102A01D6178009110001DF901223FC2A\r
+S31550000580400001289210200280A22000128000060E\r
+S31550000590211400051114000510BFFF909012202061\r
+S315500005A02114000540000280901420404000027E35\r
+S315500005B090142040901020F013080013D0302000E3\r
+S315500005C092126020D012400015200000900A3FFE83\r
+S315500005D0D03240009612A04C90102010D022C0006D\r
+S315500005E0D802C0009412A0B813080004D822800084\r
+S315500005F092126014D0024000900A3FFED022400072\r
+S3155000060010800000010000001114000510BFFF7398\r
+S3155000061090122048D20200001102807FD225800A13\r
+S31550000620901223FFD0258010D205800AD005801065\r
+S3155000063080A2400832BFFF40113FFFF790102001C3\r
+S31550000640D025801010BFFF3C113FFFF7D61780080A\r
+S31550000650921AE0B980A0000994603FFF901AE0DA40\r
+S3155000066080A0000892603FFF8092800902BFFEED95\r
+S31550000670113FFFF780A2E0DA22BFFEF0B81020014A\r
+S3155000068010BFFEEF900F20012114000540000246D6\r
+S315500006909014205030BFFFFE01000000941020F04F\r
+S315500006A019080013D430200098132020170800048E\r
+S315500006B0D41300008212E01417200000940ABFFEE3\r
+S315500006C09A12E0B8D4330000900A20FF9612E04CFC\r
+S315500006D0D222C00080A22001128000070100000033\r
+S315500006E0D202C000D2234000D0004000900A3FFE04\r
+S315500006F0D02040000100000081C3E0080100000046\r
+S315500007001308000492126014D00240009012200187\r
+S31550000710D02240000100000081C3E0080100000023\r
+S315500007209C03BF90D233A066D213A06696100008E1\r
+S31550000730920A6080D012000080A0000994402000E8\r
+S31550000740900A208080A000089240200080A2400A93\r
+S315500007500280000D01000000D012C000808A2020C7\r
+S315500007601280000901000000D012C000900A2080BB\r
+S3155000077080A000089240200080A2400A12BFFFF7D6\r
+S3155000078001000000D012C000900A208080A000080E\r
+S3155000079090402000901A000A901A20010100000093\r
+S315500007A081C3E0089C23BF909DE3BF90B20E60FFCB\r
+S315500007B0A0100018C027BFF480A660BA14800006A7\r
+S315500007C080A660DA80A660B916800006153FFFEA5B\r
+S315500007D080A660B512800027B0102000153FFFEAB2\r
+S315500007E096102AAA9412A2AA13000015D432C00059\r
+S315500007F09212615598102554113FFFE0D2330000F4\r
+S3155000080090122080D032C000D432C000D2330000C3\r
+S315500008101100000C2300003F90122030130000C33B\r
+S31550000820D0340000A412613FB21463FF921463FFE8\r
+S315500008307FFFFFBC90100010B0100008D007BFF427\r
+S3155000084090022001D027BFF4D214000080A64009A0\r
+S315500008500280000880A620011280000601000000D8\r
+S31550000860D007BFF480A2001208BFFFF2921463FFB4\r
+S31550000870D007BFF4130000C39212613F80A2400814\r
+S3155000088094403FFFB00E000A0100000081C7E00807\r
+S3155000089081E80000153FFFEA98102AAA9412A2AAEE\r
+S315500008A0D4330000170000159612E155153FFFE4AA\r
+S315500008B0D63025549412A090D4330000D61022007E\r
+S315500008C09A100008960AE0FFD6320000901030F0D9\r
+S315500008D0D0330000D613400098100009901AE03724\r
+S315500008E080A0000894603FFF901AE01C80A000088A\r
+S315500008F092603FFF8092800912800007821020008C\r
+S3155000090080A2E0C20280000480A2E0201280004251\r
+S3155000091090102000113FFFEA94102AAA901222AAA2\r
+S31550000920D03280001300001592126155113FFFE43A\r
+S31550000930D230255490122090D0328000D21022020C\r
+S31550000940901030F0920A60FFD2330000D03280000F\r
+S31550000950D013400080A220370280002A80A2202097\r
+S31550000960D41300000280001D912AA0109002BF47A8\r
+S31550000970912A201091322010952AA01080A2200290\r
+S315500009809532A01092602000901AA0B580A0000861\r
+S31550000990920A600190603FFF809240083280000BBF\r
+S315500009A08210200180A2A0B90280000A80A2A0BABB\r
+S315500009B00280000880A2A0EF0280000680A2A0DA82\r
+S315500009C02280000282102001108000139010000136\r
+S315500009D010BFFFFE821020019132201080A220EE1F\r
+S315500009E012BFFFE49002BF479010201CD033400046\r
+S315500009F0921020B9D233000010BFFFDD941020B9F9\r
+S31550000A00D413000080A2A03402BFFFF880A2202099\r
+S31550000A1030BFFFD50100000081C3E008010000008F\r
+S31550000A209DE3BF88B72EE010C037BFF4B736E0104D\r
+S31550000A30A0100018C027BFEC80A6E0BA14800006AC\r
+S31550000A4080A6E0DA80A6E0B916800006113FFFEADC\r
+S31550000A5080A6E0B512800023B0102000113FFFEAB7\r
+S31550000A6094102AAA901222AAD032800013000015A0\r
+S31550000A7092126155113FFFE8D2302554901220A0B2\r
+S31550000A80D0328000F837BFF2D017BFF2130000C340\r
+S31550000A90D0340000B612613FD217BFF27FFFFF215C\r
+S31550000AA090100010B0100008D007BFEC9002200143\r
+S31550000AB0D027BFECD2140000D017BFF280A2000995\r
+S31550000AC00280000880A62001128000060100000066\r
+S31550000AD0D007BFEC80A2001B08BFFFF0010000004A\r
+S31550000AE0D007BFEC130000C39212613F80A24008AA\r
+S31550000AF094403FFFB00E000A0100000081C7E00895\r
+S31550000B0081E800009DE3BF9811140005D4022150DE\r
+S31550000B10A210200080A4400AA410001B9A102000A6\r
+S31550000B20A0102000A610200116800012961020005A\r
+S31550000B30912EA010B5322010932EE0109810000A76\r
+S31550000B40111400059332601094122060D002A00C4C\r
+S31550000B5080A2001A22800048D002A0109602E0011E\r
+S31550000B6080A2C00C06BFFFFA9402A05011140005D3\r
+S31550000B70D202215080A2C009028000449010200168\r
+S31550000B8080A6200008800016912AE0029002000BF1\r
+S31550000B9013140005B4126060992A20049E10200197\r
+S31550000BA0912C200290020010912A200290030008F6\r
+S31550000BB09002001AD4022004A2046001D202200836\r
+S31550000BC080A4400A932BC0099A034009A0643FFFB2\r
+S31550000BD080A6000D18BFFFF4912C200280A660005D\r
+S31550000BE00480001F932AE0029202400BB60CA0FF2D\r
+S31550000BF011140005A4122060B52A60049210001B3F\r
+S31550000C007FFFFEEA90100018932C200292024010AB\r
+S31550000C10932A6002920680099402401280A2200014\r
+S31550000C2002800013A2046001D202A0089010200195\r
+S31550000C30912A000980A64008B00600080680000ADE\r
+S31550000C40B2264008D002A00480A44008A0643FFF0A\r
+S31550000C5080A6600014BFFFEB9210001B1080000BA3\r
+S31550000C6090100013108000099010200110BFFFFC57\r
+S31550000C70A610200080A2000932BFFFBA9602E001FA\r
+S31550000C8010BFFFBC1114000581C7E00891E80008A9\r
+S31550000C9013140005D40A61801708000013000013CE\r
+S31550000CA09212630C952AA00294028009D202C00ABD\r
+S31550000CB0941000089132601F80A22001028000002B\r
+S31550000CC09132601D808A20012280000490102001FC\r
+S31550000CD0C022800030800002D022800081C3E0080C\r
+S31550000CE09010000911140005D20A21801508000041\r
+S31550000CF0110000139012230C932A600292024008AE\r
+S31550000D00D20280099132601F80A220010280000029\r
+S31550000D100100000081C3E008901000099DE3BF90D8\r
+S31550000D2011140005E00A2180B00E20FF11140005B1\r
+S31550000D3090122154B12E2002E2020018A12C20025A\r
+S31550000D40110000139012230CA00400087FFFFFD15E\r
+S31550000D509007BFF4D207BFF411060000932A601E15\r
+S31550000D60921240112308000092124008D2244010DB\r
+S31550000D707FFFFFC89007BFF4D207BFF411070000EA\r
+S31550000D80932A601E92124008D22440107FFFFFC162\r
+S31550000D909007BFF4D207BFF411030000932A601ED8\r
+S31550000DA092124008D22440107FFFFFBA9007BFF43A\r
+S31550000DB0D207BFF41104000090122003932A601E3C\r
+S31550000DC092124008D22440107FFFFFB29007BFF422\r
+S31550000DD0D207BFF411050000932A601E92124008F4\r
+S31550000DE0D22440107FFFFFC0010000000100000028\r
+S31550000DF081C7E00881E800009DE3BF90111400050B\r
+S31550000E00E00A218025080000110000139012230CDF\r
+S31550000E10A12C2002A00400087FFFFF9E9007BFF47C\r
+S31550000E20D207BFF411050000932A601E92124008A3\r
+S31550000E30D22480107FFFFF979007BFF4A2100008BE\r
+S31550000E40D007BFF427040000912A201E90120013E9\r
+S31550000E50D02480107FFFFF8F9007BFF4D207BFF4D6\r
+S31550000E6011040004932A601E92124008D224801066\r
+S31550000E707FFFFF889007BFF4D007BFF4A20C60FF36\r
+S31550000E80912A201E9012001190120013D024801027\r
+S31550000E907FFFFF95010000000100000081C7E008B8\r
+S31550000EA081E800009DE3BF9011140005D20A21800D\r
+S31550000EB02708000011000013932A60029012230C99\r
+S31550000EC09202400893326002AC100009AB2A6002CD\r
+S31550000ED0AE1000097FFFFF6F9007BFF4D007BFF435\r
+S31550000EE023030000912A201E90120011D024C01511\r
+S31550000EF07FFFFF7D0100000091322016A08A200F4F\r
+S31550000F0032800011A2102000A4100011A32DA002BF\r
+S31550000F107FFFFF609007BFF4D207BFF4932A601E8D\r
+S31550000F2092124012D224C0117FFFFF6F01000000C1\r
+S31550000F3091322016A08A200F02BFFFF60100000052\r
+S31550000F40A210200080A440101ABFFFE3A52DE00296\r
+S31550000F50290100007FFFFF4F9007BFF4D007BFF471\r
+S31550000F60A2046001912A201E90120014D024C012AF\r
+S31550000F707FFFFF5D01000000D02E0000808A20FF19\r
+S31550000F8002800006B006200180A440100ABFFFF27E\r
+S31550000F900100000030BFFFD00100000081C7E0080B\r
+S31550000FA081E800009DE3BF9011140005D20A21800C\r
+S31550000FB025080000D40E000011000013932A600289\r
+S31550000FC09012230C80A2A000028000849202400856\r
+S31550000FD0AD2A60109135A012A72A2002AA10000847\r
+S31550000FE0A81000137FFFFF2B9007BFF4D007BFF464\r
+S31550000FF021030000912A201E90120010D024801345\r
+S315500010007FFFFF3901000000900A200680A22006CB\r
+S315500010100280001001000000A2100010A12D6002F5\r
+S315500010207FFFFF1C9007BFF4D207BFF4932A601EC0\r
+S3155000103092124011D22480107FFFFF2B0100000036\r
+S31550001040900A200680A2200612BFFFF6010000007B\r
+S315500010507FFFFF109007BFF4D007BFF4D20E0000F9\r
+S31550001060912A201E90120009D02480147FFFFF1E63\r
+S31550001070B0062001D00E000080A2200012BFFFDA79\r
+S31550001080010000009135A010D404800880A2A00071\r
+S315500010900680004C010000009132A01D808A20017C\r
+S315500010A00280004690102001C027BFF4D007BFF43D\r
+S315500010B013030000912A201E901200099335A010A8\r
+S315500010C0D0248009D404800980A2A0000680003470\r
+S315500010D0900AA00680A22006028000169135A01222\r
+S315500010E09A1000089E102001972A2002190300002A\r
+S315500010F09132A01D808A2001128000039210200098\r
+S315500011009210000F912A601E9012000CD024800B72\r
+S31550001110D404800B80A2A0000680001A900AA00674\r
+S3155000112080A2200612BFFFF49132A01DD227BFF431\r
+S315500011309132A01D808A200102800010901020015B\r
+S31550001140C027BFF4D007BFF49335A010912A201EB4\r
+S31550001150D0248009D404800980A2A00016800021E2\r
+S3155000116090100009D404800880A2A00006BFFFFE9C\r
+S31550001170010000003080001B10BFFFF3D027BFF4E2\r
+S31550001180912B6002D404800880A2A00006BFFFFE07\r
+S315500011900100000010BFFFE3900AA006901000095E\r
+S315500011A0D404800880A2A00006BFFFFE0100000004\r
+S315500011B010BFFFC9900AA00610BFFFBDD027BFF4CD\r
+S315500011C0D404800880A2A00006BFFFFE01000000E4\r
+S315500011D010BFFFB39132A01D10BFFFABAD2A6010F8\r
+S315500011E00100000081C7E00881E800009DE3BF9838\r
+S315500011F035140005F60EA180921000183500001324\r
+S31550001200B416A30CB72EE002B606C01A992EE010FB\r
+S31550001210B53320129B2EA002A210001AA610001958\r
+S315500012203B080000961020009410000DA410001AE0\r
+S31550001230F807400D80A7200006800064B137201DB6\r
+S31550001240B00E200180A00018B0603FFFB12E201EC6\r
+S3155000125033030000B0160019F027400AF807400A79\r
+S3155000126080A7200006800052B1372016B48E200F7A\r
+S315500012701280001A82102000B3332012310003D09E\r
+S31550001280901000199E162240B32E600237030000BC\r
+S3155000129080A0400F8200600118800053B0102000DB\r
+S315500012A0B137201DB00E200180A00018B0603FFF5E\r
+S315500012B0B12E201EB016001BF0274019F807401912\r
+S315500012C080A7200006800033B1372016B48E200F39\r
+S315500012D002BFFFF180A0400F8210200080A0401A6C\r
+S315500012E01ABFFFD4B1332012B72E20029010001827\r
+S315500012F09E10001BA0100018F807401B80A7200066\r
+S315500013000680001DB137201DB00E200180A00018A8\r
+S31550001310B0603FFFB12E201E33010000B0160019F9\r
+S31550001320F027400FF807400F80A720000680000CDA\r
+S31550001330B12C20029602E001F82A400080A2C01388\r
+S3155000134002800029B010000B8200600180A0401A74\r
+S315500013500ABFFFEA9202600130BFFFB6F807401895\r
+S3155000136080A7200006BFFFFE0100000010BFFFF35C\r
+S315500013709602E001B12A2002F807401880A7200003\r
+S3155000138006BFFFFE0100000010BFFFE0B137201D71\r
+S31550001390B12A2002F807401880A7200006BFFFFE9A\r
+S315500013A00100000010BFFFCAB1372016B12CA002B1\r
+S315500013B0F807401880A7200006BFFFFE0100000076\r
+S315500013C010BFFFABB1372016B12C6002F80740189A\r
+S315500013D080A7200006BFFFFE0100000010BFFF9946\r
+S315500013E0B137201D0100000081C7E00881E80000E8\r
+S315500013F09DE3BF987FFFFE81B00E20FF7FFFFE4822\r
+S3155000140081E800000100000000000000000000001C\r
+S315500014100000000000000000000000000000000076\r
+S315500014204572726F723400004572726F72330000EB\r
+S315500014304F4B0000000000004572726F7232000080\r
+S31550001440454E4400000000004572726F7235000030\r
+S315500014504572726F723100000000000000000000FB\r
+S3155000146000000000000000010000000E00000037E0\r
+S31550001470000000B500004000000000030000000D11\r
+S3155000148000000037000000B5000080000000000496\r
+S315500014900000000F00000037000000B500010000FA\r
+S315500014A00000000B0000001000000037000000B5DF\r
+S315500014B00000000000000007000000100000001CA3\r
+S315500014C0000000B900007000000000080000000F86\r
+S315500014D00000001C000000B9000078000000000A5F\r
+S315500014E00000000D0000001C000000B900007C0048\r
+S315500014F00000000B0000000E0000001C000000B9A8\r
+S31550001500000000000000000F000000100000001C4A\r
+S31550001510000000DA00007000000000100000000F0C\r
+S315500015200000001C000000DA0000700000000012ED\r
+S315500015300000000D0000001C000000DA00007000E2\r
+S31550001540000000130000000E0000001C000000DA2E\r
+S3155000155000000003000001AA000000D50000006A48\r
+S3155000156000000035000000230000001100000008B4\r
+S3115000157000000000000000000000000019\r
+S70550000000AA\r
diff --git a/ao-tools/ao-sky-flash/srec_9600.bin b/ao-tools/ao-sky-flash/srec_9600.bin
new file mode 100644 (file)
index 0000000..9a29ab1
--- /dev/null
@@ -0,0 +1,346 @@
+S0190000666C6173685F3139646F74355F393630302E737265638A\r
+S31550000000033FFFF7821063209DE380011920000013\r
+S31550000010D2030000173FFFF79612E3E4AC07BFF890\r
+S31550000020D225800BD005800B133FFFC0900A0009E4\r
+S3155000003090122977D0230000E00320901B0800136C\r
+S31550000040C0232090D20320149E136018D225800B13\r
+S31550000050D005800B1300180090120009900A3FF04B\r
+S31550000060D0232014D20300001100003FD225800B6C\r
+S31550000070D405800B901223FF940A800813043E0087\r
+S3155000008094128009D4230000D003C0009A13601C38\r
+S31550000090D025800BD205800B11004000902A4008D5\r
+S315500000A0D023C000D403400011000040D425800B5B\r
+S315500000B0D205800BA00C204092124008A13C20068D\r
+S315500000C011140005E02A2180D2234000B8102000E8\r
+S315500000D0400004C890102001130004004000017035\r
+S315500000E090102001213FFFF84000036F90058010CB\r
+S315500000F0A014200A92058010B6102000B4102000DB\r
+S31550000100A6102000AE10200096102000D00A400005\r
+S3155000011080A2202002800006920260019602E00131\r
+S3155000012080A2E06324BFFFFBD00A40009810200055\r
+S3155000013080A3000B1680000F113FFFF89012200A83\r
+S31550000140940580089810000B912CE0029002001341\r
+S31550000150D20A8000912A200190020009A6023FD0BF\r
+S3155000016098833FFF12BFFFF99402A0019810000B2D\r
+S315500001709205800C113FFFF894024008961020001B\r
+S315500001809002800BD20A201680A2602002800007BF\r
+S3155000019080A2E0009602E00180A2E06304BFFFFA6D\r
+S315500001A09002800B80A2E0000480000F113FFFF800\r
+S315500001B09205800C9012201698024008900DE0FF90\r
+S315500001C0932A2002D40B000092024008932A600121\r
+S315500001D094028009AE02BFD09682FFFF12BFFFF88D\r
+S315500001E098032001133FFFF794126384921263869B\r
+S315500001F090078009400001A89207800A80A220003B\r
+S3155000020002800122153FFFF79012A386D21780086D\r
+S3155000021080A2601C0280010E9012A384113FFFF74A\r
+S31550000220961223849012238692102037D237800854\r
+S31550000230941020B5D437800B900F2001213FFFF743\r
+S31550000240AB2A201392142386110001E1D41780099A\r
+S3155000025090122154A2142384A4054008D617801165\r
+S3155000026090100012400002289210202080A22000F8\r
+S31550000270028000CA11140005B0100010B21000110F\r
+S31550000280A0102000113FFFEA80A420000280000445\r
+S315500002909212225511000015921221AA912A60102D\r
+S315500002A0A8162386A3322010D617801990048010E2\r
+S315500002B0D417801492102002400001DA98100011D1\r
+S315500002C080A22000028000B511140005D0148010C1\r
+S315500002D080A44008128000B0A004200280A420030D\r
+S315500002E004BFFFEA113FFFEA213FFFF79214238430\r
+S315500002F0D617800990100012D417801440000202BD\r
+S3155000030092102020170001DF9012E3F8D20200006D\r
+S31550000310941423E4D225800AA01423E0C02580102B\r
+S31550000320D005800A80A23FFF228000BB9012E3FCDA\r
+S31550000330113FFFF7A2122384A0122386110001C198\r
+S31550000340D417801090122154D61780119210202065\r
+S31550000350400001ED90054008110001E9D4178010C6\r
+S3155000036090122154D617801192102020400001E699\r
+S3155000037090054008110001F1D417801090122154B5\r
+S31550000380D617801192102020400001DF90054008BA\r
+S31550000390133FFFF8D00D800980A220421280000B37\r
+S315500003A0A410001392058009D00A600180A220494A\r
+S315500003B03280000721140005D00A600280A2204E28\r
+S315500003C022800008D417801021140005400002F640\r
+S315500003D09014202890142028400002F39E03FCF02D\r
+S315500003E090102000D6178011400001C792100013BC\r
+S315500003F080A2200022800069111400051114000506\r
+S31550000400400002E990122030400000BE010000007A\r
+S3155000041011000007A81223FFB010001480A4801406\r
+S31550000420148000031300000892100012113FFFF8C9\r
+S315500004304000036F90058008A2922000028000734E\r
+S31550000440A010200080A40011B40680111A8000214B\r
+S31550000450A4248011333FFFF71100003FAA1223FF57\r
+S31550000460BA1663849810001092102000A00420023F\r
+S31550000470173FFFF89005800CD40A000B932A6008AA\r
+S315500004809803200180A3001006BFFFFB9212400A7A\r
+S31550000490912A60109932201080A300150280000A1C\r
+S315500004A090166386D417800892102002D617801DA6\r
+S315500004B04000015C9010001B80A220000280003793\r
+S315500004C01114000580A400110ABFFFE7B606E0022A\r
+S315500004D0900E801880A0000892603FFF80A0001206\r
+S315500004E090603FFF809240080280000680A68013ED\r
+S315500004F011140005400002AC9012203080A68013E3\r
+S3155000050012BFFFC880A480149410200080A28013CC\r
+S315500005101680000996102000D21280009132600891\r
+S315500005209002C0089402A00280A2801306BFFFFB6F\r
+S3155000053096020009920AE0FF900DE0FF80A2400863\r
+S31550000540028000041114000510BFFFA49012203839\r
+S31550000550153FFFF79012A3E0D205800880A26001F4\r
+S31550000560128000109212A3849012A386D41780088A\r
+S3155000057098102A01D6178009110001DF901223FC2A\r
+S31550000580400001289210200280A22000128000060E\r
+S31550000590211400051114000510BFFF909012202061\r
+S315500005A02114000540000280901420404000027E35\r
+S315500005B090142040901020F013080013D0302000E3\r
+S315500005C092126020D012400015200000900A3FFE83\r
+S315500005D0D03240009612A04C90102010D022C0006D\r
+S315500005E0D802C0009412A0B813080004D822800084\r
+S315500005F092126014D0024000900A3FFED022400072\r
+S3155000060010800000010000001114000510BFFF7398\r
+S3155000061090122048D20200001102807FD225800A13\r
+S31550000620901223FFD0258010D205800AD005801065\r
+S3155000063080A2400832BFFF40113FFFF790102001C3\r
+S31550000640D025801010BFFF3C113FFFF7D61780080A\r
+S31550000650921AE0B980A0000994603FFF901AE0DA40\r
+S3155000066080A0000892603FFF8092800902BFFEED95\r
+S31550000670113FFFF780A2E0DA22BFFEF0B81020014A\r
+S3155000068010BFFEEF900F20012114000540000246D6\r
+S315500006909014205030BFFFFE01000000941020F04F\r
+S315500006A019080013D430200098132020170800048E\r
+S315500006B0D41300008212E01417200000940ABFFEE3\r
+S315500006C09A12E0B8D4330000900A20FF9612E04CFC\r
+S315500006D0D222C00080A22001128000070100000033\r
+S315500006E0D202C000D2234000D0004000900A3FFE04\r
+S315500006F0D02040000100000081C3E0080100000046\r
+S315500007001308000492126014D00240009012200187\r
+S31550000710D02240000100000081C3E0080100000023\r
+S315500007209C03BF90D233A066D213A06696100008E1\r
+S31550000730920A6080D012000080A0000994402000E8\r
+S31550000740900A208080A000089240200080A2400A93\r
+S315500007500280000D01000000D012C000808A2020C7\r
+S315500007601280000901000000D012C000900A2080BB\r
+S3155000077080A000089240200080A2400A12BFFFF7D6\r
+S3155000078001000000D012C000900A208080A000080E\r
+S3155000079090402000901A000A901A20010100000093\r
+S315500007A081C3E0089C23BF909DE3BF90B20E60FFCB\r
+S315500007B0A0100018C027BFF480A660BA14800006A7\r
+S315500007C080A660DA80A660B916800006153FFFEA5B\r
+S315500007D080A660B512800027B0102000153FFFEAB2\r
+S315500007E096102AAA9412A2AA13000015D432C00059\r
+S315500007F09212615598102554113FFFE0D2330000F4\r
+S3155000080090122080D032C000D432C000D2330000C3\r
+S315500008101100000C2300003F90122030130000C33B\r
+S31550000820D0340000A412613FB21463FF921463FFE8\r
+S315500008307FFFFFBC90100010B0100008D007BFF427\r
+S3155000084090022001D027BFF4D214000080A64009A0\r
+S315500008500280000880A620011280000601000000D8\r
+S31550000860D007BFF480A2001208BFFFF2921463FFB4\r
+S31550000870D007BFF4130000C39212613F80A2400814\r
+S3155000088094403FFFB00E000A0100000081C7E00807\r
+S3155000089081E80000153FFFEA98102AAA9412A2AAEE\r
+S315500008A0D4330000170000159612E155153FFFE4AA\r
+S315500008B0D63025549412A090D4330000D61022007E\r
+S315500008C09A100008960AE0FFD6320000901030F0D9\r
+S315500008D0D0330000D613400098100009901AE03724\r
+S315500008E080A0000894603FFF901AE01C80A000088A\r
+S315500008F092603FFF8092800912800007821020008C\r
+S3155000090080A2E0C20280000480A2E0201280004251\r
+S3155000091090102000113FFFEA94102AAA901222AAA2\r
+S31550000920D03280001300001592126155113FFFE43A\r
+S31550000930D230255490122090D0328000D21022020C\r
+S31550000940901030F0920A60FFD2330000D03280000F\r
+S31550000950D013400080A220370280002A80A2202097\r
+S31550000960D41300000280001D912AA0109002BF47A8\r
+S31550000970912A201091322010952AA01080A2200290\r
+S315500009809532A01092602000901AA0B580A0000861\r
+S31550000990920A600190603FFF809240083280000BBF\r
+S315500009A08210200180A2A0B90280000A80A2A0BABB\r
+S315500009B00280000880A2A0EF0280000680A2A0DA82\r
+S315500009C02280000282102001108000139010000136\r
+S315500009D010BFFFFE821020019132201080A220EE1F\r
+S315500009E012BFFFE49002BF479010201CD033400046\r
+S315500009F0921020B9D233000010BFFFDD941020B9F9\r
+S31550000A00D413000080A2A03402BFFFF880A2202099\r
+S31550000A1030BFFFD50100000081C3E008010000008F\r
+S31550000A209DE3BF88B72EE010C037BFF4B736E0104D\r
+S31550000A30A0100018C027BFEC80A6E0BA14800006AC\r
+S31550000A4080A6E0DA80A6E0B916800006113FFFEADC\r
+S31550000A5080A6E0B512800023B0102000113FFFEAB7\r
+S31550000A6094102AAA901222AAD032800013000015A0\r
+S31550000A7092126155113FFFE8D2302554901220A0B2\r
+S31550000A80D0328000F837BFF2D017BFF2130000C340\r
+S31550000A90D0340000B612613FD217BFF27FFFFF215C\r
+S31550000AA090100010B0100008D007BFEC9002200143\r
+S31550000AB0D027BFECD2140000D017BFF280A2000995\r
+S31550000AC00280000880A62001128000060100000066\r
+S31550000AD0D007BFEC80A2001B08BFFFF0010000004A\r
+S31550000AE0D007BFEC130000C39212613F80A24008AA\r
+S31550000AF094403FFFB00E000A0100000081C7E00895\r
+S31550000B0081E800009DE3BF9811140005D4022150DE\r
+S31550000B10A210200080A4400AA410001B9A102000A6\r
+S31550000B20A0102000A610200116800012961020005A\r
+S31550000B30912EA010B5322010932EE0109810000A76\r
+S31550000B40111400059332601094122060D002A00C4C\r
+S31550000B5080A2001A22800048D002A0109602E0011E\r
+S31550000B6080A2C00C06BFFFFA9402A05011140005D3\r
+S31550000B70D202215080A2C009028000449010200168\r
+S31550000B8080A6200008800016912AE0029002000BF1\r
+S31550000B9013140005B4126060992A20049E10200197\r
+S31550000BA0912C200290020010912A200290030008F6\r
+S31550000BB09002001AD4022004A2046001D202200836\r
+S31550000BC080A4400A932BC0099A034009A0643FFFB2\r
+S31550000BD080A6000D18BFFFF4912C200280A660005D\r
+S31550000BE00480001F932AE0029202400BB60CA0FF2D\r
+S31550000BF011140005A4122060B52A60049210001B3F\r
+S31550000C007FFFFEEA90100018932C200292024010AB\r
+S31550000C10932A6002920680099402401280A2200014\r
+S31550000C2002800013A2046001D202A0089010200195\r
+S31550000C30912A000980A64008B00600080680000ADE\r
+S31550000C40B2264008D002A00480A44008A0643FFF0A\r
+S31550000C5080A6600014BFFFEB9210001B1080000BA3\r
+S31550000C6090100013108000099010200110BFFFFC57\r
+S31550000C70A610200080A2000932BFFFBA9602E001FA\r
+S31550000C8010BFFFBC1114000581C7E00891E80008A9\r
+S31550000C9013140005D40A61801708000013000013CE\r
+S31550000CA09212630C952AA00294028009D202C00ABD\r
+S31550000CB0941000089132601F80A22001028000002B\r
+S31550000CC09132601D808A20012280000490102001FC\r
+S31550000CD0C022800030800002D022800081C3E0080C\r
+S31550000CE09010000911140005D20A21801508000041\r
+S31550000CF0110000139012230C932A600292024008AE\r
+S31550000D00D20280099132601F80A220010280000029\r
+S31550000D100100000081C3E008901000099DE3BF90D8\r
+S31550000D2011140005E00A2180B00E20FF11140005B1\r
+S31550000D3090122154B12E2002E2020018A12C20025A\r
+S31550000D40110000139012230CA00400087FFFFFD15E\r
+S31550000D509007BFF4D207BFF411060000932A601E15\r
+S31550000D60921240112308000092124008D2244010DB\r
+S31550000D707FFFFFC89007BFF4D207BFF411070000EA\r
+S31550000D80932A601E92124008D22440107FFFFFC162\r
+S31550000D909007BFF4D207BFF411030000932A601ED8\r
+S31550000DA092124008D22440107FFFFFBA9007BFF43A\r
+S31550000DB0D207BFF41104000090122003932A601E3C\r
+S31550000DC092124008D22440107FFFFFB29007BFF422\r
+S31550000DD0D207BFF411050000932A601E92124008F4\r
+S31550000DE0D22440107FFFFFC0010000000100000028\r
+S31550000DF081C7E00881E800009DE3BF90111400050B\r
+S31550000E00E00A218025080000110000139012230CDF\r
+S31550000E10A12C2002A00400087FFFFF9E9007BFF47C\r
+S31550000E20D207BFF411050000932A601E92124008A3\r
+S31550000E30D22480107FFFFF979007BFF4A2100008BE\r
+S31550000E40D007BFF427040000912A201E90120013E9\r
+S31550000E50D02480107FFFFF8F9007BFF4D207BFF4D6\r
+S31550000E6011040004932A601E92124008D224801066\r
+S31550000E707FFFFF889007BFF4D007BFF4A20C60FF36\r
+S31550000E80912A201E9012001190120013D024801027\r
+S31550000E907FFFFF95010000000100000081C7E008B8\r
+S31550000EA081E800009DE3BF9011140005D20A21800D\r
+S31550000EB02708000011000013932A60029012230C99\r
+S31550000EC09202400893326002AC100009AB2A6002CD\r
+S31550000ED0AE1000097FFFFF6F9007BFF4D007BFF435\r
+S31550000EE023030000912A201E90120011D024C01511\r
+S31550000EF07FFFFF7D0100000091322016A08A200F4F\r
+S31550000F0032800011A2102000A4100011A32DA002BF\r
+S31550000F107FFFFF609007BFF4D207BFF4932A601E8D\r
+S31550000F2092124012D224C0117FFFFF6F01000000C1\r
+S31550000F3091322016A08A200F02BFFFF60100000052\r
+S31550000F40A210200080A440101ABFFFE3A52DE00296\r
+S31550000F50290100007FFFFF4F9007BFF4D007BFF471\r
+S31550000F60A2046001912A201E90120014D024C012AF\r
+S31550000F707FFFFF5D01000000D02E0000808A20FF19\r
+S31550000F8002800006B006200180A440100ABFFFF27E\r
+S31550000F900100000030BFFFD00100000081C7E0080B\r
+S31550000FA081E800009DE3BF9011140005D20A21800C\r
+S31550000FB025080000D40E000011000013932A600289\r
+S31550000FC09012230C80A2A000028000849202400856\r
+S31550000FD0AD2A60109135A012A72A2002AA10000847\r
+S31550000FE0A81000137FFFFF2B9007BFF4D007BFF464\r
+S31550000FF021030000912A201E90120010D024801345\r
+S315500010007FFFFF3901000000900A200680A22006CB\r
+S315500010100280001001000000A2100010A12D6002F5\r
+S315500010207FFFFF1C9007BFF4D207BFF4932A601EC0\r
+S3155000103092124011D22480107FFFFF2B0100000036\r
+S31550001040900A200680A2200612BFFFF6010000007B\r
+S315500010507FFFFF109007BFF4D007BFF4D20E0000F9\r
+S31550001060912A201E90120009D02480147FFFFF1E63\r
+S31550001070B0062001D00E000080A2200012BFFFDA79\r
+S31550001080010000009135A010D404800880A2A00071\r
+S315500010900680004C010000009132A01D808A20017C\r
+S315500010A00280004690102001C027BFF4D007BFF43D\r
+S315500010B013030000912A201E901200099335A010A8\r
+S315500010C0D0248009D404800980A2A0000680003470\r
+S315500010D0900AA00680A22006028000169135A01222\r
+S315500010E09A1000089E102001972A2002190300002A\r
+S315500010F09132A01D808A2001128000039210200098\r
+S315500011009210000F912A601E9012000CD024800B72\r
+S31550001110D404800B80A2A0000680001A900AA00674\r
+S3155000112080A2200612BFFFF49132A01DD227BFF431\r
+S315500011309132A01D808A200102800010901020015B\r
+S31550001140C027BFF4D007BFF49335A010912A201EB4\r
+S31550001150D0248009D404800980A2A00016800021E2\r
+S3155000116090100009D404800880A2A00006BFFFFE9C\r
+S31550001170010000003080001B10BFFFF3D027BFF4E2\r
+S31550001180912B6002D404800880A2A00006BFFFFE07\r
+S315500011900100000010BFFFE3900AA006901000095E\r
+S315500011A0D404800880A2A00006BFFFFE0100000004\r
+S315500011B010BFFFC9900AA00610BFFFBDD027BFF4CD\r
+S315500011C0D404800880A2A00006BFFFFE01000000E4\r
+S315500011D010BFFFB39132A01D10BFFFABAD2A6010F8\r
+S315500011E00100000081C7E00881E800009DE3BF9838\r
+S315500011F035140005F60EA180921000183500001324\r
+S31550001200B416A30CB72EE002B606C01A992EE010FB\r
+S31550001210B53320129B2EA002A210001AA610001958\r
+S315500012203B080000961020009410000DA410001AE0\r
+S31550001230F807400D80A7200006800064B137201DB6\r
+S31550001240B00E200180A00018B0603FFFB12E201EC6\r
+S3155000125033030000B0160019F027400AF807400A79\r
+S3155000126080A7200006800052B1372016B48E200F7A\r
+S315500012701280001A82102000B3332012310003D09E\r
+S31550001280901000199E162240B32E600237030000BC\r
+S3155000129080A0400F8200600118800053B0102000DB\r
+S315500012A0B137201DB00E200180A00018B0603FFF5E\r
+S315500012B0B12E201EB016001BF0274019F807401912\r
+S315500012C080A7200006800033B1372016B48E200F39\r
+S315500012D002BFFFF180A0400F8210200080A0401A6C\r
+S315500012E01ABFFFD4B1332012B72E20029010001827\r
+S315500012F09E10001BA0100018F807401B80A7200066\r
+S315500013000680001DB137201DB00E200180A00018A8\r
+S31550001310B0603FFFB12E201E33010000B0160019F9\r
+S31550001320F027400FF807400F80A720000680000CDA\r
+S31550001330B12C20029602E001F82A400080A2C01388\r
+S3155000134002800029B010000B8200600180A0401A74\r
+S315500013500ABFFFEA9202600130BFFFB6F807401895\r
+S3155000136080A7200006BFFFFE0100000010BFFFF35C\r
+S315500013709602E001B12A2002F807401880A7200003\r
+S3155000138006BFFFFE0100000010BFFFE0B137201D71\r
+S31550001390B12A2002F807401880A7200006BFFFFE9A\r
+S315500013A00100000010BFFFCAB1372016B12CA002B1\r
+S315500013B0F807401880A7200006BFFFFE0100000076\r
+S315500013C010BFFFABB1372016B12C6002F80740189A\r
+S315500013D080A7200006BFFFFE0100000010BFFF9946\r
+S315500013E0B137201D0100000081C7E00881E80000E8\r
+S315500013F09DE3BF987FFFFE81B00E20FF7FFFFE4822\r
+S3155000140081E800000100000000000000000000001C\r
+S315500014100000000000000000000000000000000076\r
+S315500014204572726F723400004572726F72330000EB\r
+S315500014304F4B0000000000004572726F7232000080\r
+S31550001440454E4400000000004572726F7235000030\r
+S315500014504572726F723100000000000000000000FB\r
+S3155000146000000000000000010000000E00000037E0\r
+S31550001470000000B500004000000000030000000D11\r
+S3155000148000000037000000B5000080000000000496\r
+S315500014900000000F00000037000000B500010000FA\r
+S315500014A00000000B0000001000000037000000B5DF\r
+S315500014B00000000000000007000000100000001CA3\r
+S315500014C0000000B900007000000000080000000F86\r
+S315500014D00000001C000000B9000078000000000A5F\r
+S315500014E00000000D0000001C000000B900007C0048\r
+S315500014F00000000B0000000E0000001C000000B9A8\r
+S31550001500000000000000000F000000100000001C4A\r
+S31550001510000000DA00007000000000100000000F0C\r
+S315500015200000001C000000DA0000700000000012ED\r
+S315500015300000000D0000001C000000DA00007000E2\r
+S31550001540000000130000000E0000001C000000DA2E\r
+S3155000155000000003000001FB000000FD0000007EBB\r
+S315500015600000003F0000002A000000150000000A9D\r
+S3115000157000000000000000000000000019\r
+S70550000000AA\r
index 6257ee44ec458d7ddd0261c957d9064c6f6059fa..625540bbe07e5cb5923a73075c82de48bc1f2cbe 100644 (file)
@@ -269,6 +269,122 @@ struct cc_telem {
 int
 cc_telem_parse(const char *input_line, struct cc_telem *telem);
 
+struct ao_log_mega {
+       char                    type;                   /* 0 */
+       uint8_t                 is_config;              /* 1 */
+       uint16_t                tick;                   /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;         /* 4 */
+                       int16_t         ground_accel;   /* 6 */
+                       uint32_t        ground_pres;    /* 8 */
+               } flight;                               /* 12 */
+               /* AO_LOG_STATE */
+               struct {
+                       uint16_t        state;
+                       uint16_t        reason;
+               } state;
+               /* AO_LOG_SENSOR */
+               struct {
+                       uint32_t        pres;           /* 4 */
+                       uint32_t        temp;           /* 8 */
+                       int16_t         accel_x;        /* 12 */
+                       int16_t         accel_y;        /* 14 */
+                       int16_t         accel_z;        /* 16 */
+                       int16_t         gyro_x;         /* 18 */
+                       int16_t         gyro_y;         /* 20 */
+                       int16_t         gyro_z;         /* 22 */
+                       int16_t         mag_x;          /* 24 */
+                       int16_t         mag_y;          /* 26 */
+                       int16_t         mag_z;          /* 28 */
+                       int16_t         accel;          /* 30 */
+               } sensor;       /* 32 */
+               /* AO_LOG_TEMP_VOLT */
+               struct {
+                       int16_t         v_batt;         /* 4 */
+                       int16_t         v_pbatt;        /* 6 */
+                       int16_t         n_sense;        /* 8 */
+                       int16_t         sense[10];      /* 10 */
+               } volt;                                 /* 30 */
+               /* AO_LOG_GPS_TIME */
+               struct {
+                       int32_t         latitude;       /* 4 */
+                       int32_t         longitude;      /* 8 */
+                       int16_t         altitude;       /* 12 */
+                       uint8_t         hour;           /* 14 */
+                       uint8_t         minute;         /* 15 */
+                       uint8_t         second;         /* 16 */
+                       uint8_t         flags;          /* 17 */
+                       uint8_t         year;           /* 18 */
+                       uint8_t         month;          /* 19 */
+                       uint8_t         day;            /* 20 */
+                       uint8_t         pad;            /* 21 */
+               } gps;  /* 22 */
+               /* AO_LOG_GPS_SAT */
+               struct {
+                       uint16_t        channels;       /* 4 */
+                       struct {
+                               uint8_t svid;
+                               uint8_t c_n;
+                       } sats[12];                     /* 6 */
+               } gps_sat;                              /* 30 */
+
+               struct {
+                       uint32_t                kind;
+                       int32_t                 data[6];
+               } config_int;
+
+               struct {
+                       uint32_t                kind;
+                       char                    string[24];
+               } config_str;
+
+               /* Raw bytes */
+               uint8_t bytes[28];
+       } u;
+};
+
+#define AO_CONFIG_CONFIG               1
+#define AO_CONFIG_MAIN                 2
+#define AO_CONFIG_APOGEE               3
+#define AO_CONFIG_LOCKOUT              4
+#define AO_CONFIG_FREQUENCY            5
+#define AO_CONFIG_RADIO_ENABLE         6
+#define AO_CONFIG_ACCEL_CAL            7
+#define AO_CONFIG_RADIO_CAL            8
+#define AO_CONFIG_MAX_LOG              9
+#define AO_CONFIG_IGNITE_MODE          10
+#define AO_CONFIG_PAD_ORIENTATION      11
+#define AO_CONFIG_SERIAL_NUMBER                12
+#define AO_CONFIG_LOG_FORMAT           13
+#define AO_CONFIG_MS5607_RESERVED      14
+#define AO_CONFIG_MS5607_SENS          15
+#define AO_CONFIG_MS5607_OFF           16
+#define AO_CONFIG_MS5607_TCS           17
+#define AO_CONFIG_MS5607_TCO           18
+#define AO_CONFIG_MS5607_TREF          19
+#define AO_CONFIG_MS5607_TEMPSENS      20
+#define AO_CONFIG_MS5607_CRC           21
+
+
+#define AO_LOG_FLIGHT          'F'
+#define AO_LOG_SENSOR          'A'
+#define AO_LOG_TEMP_VOLT       'T'
+#define AO_LOG_DEPLOY          'D'
+#define AO_LOG_STATE           'S'
+#define AO_LOG_GPS_TIME                'G'
+#define AO_LOG_GPS_LAT         'N'
+#define AO_LOG_GPS_LON         'W'
+#define AO_LOG_GPS_ALT         'H'
+#define AO_LOG_GPS_SAT         'V'
+#define AO_LOG_GPS_DATE                'Y'
+
+#define AO_LOG_CONFIG          'c'
+
+int
+cc_mega_parse(const char *input_line, struct ao_log_mega *l);
+
 #ifndef TRUE
 #define TRUE 1
 #define FALSE 0
index e3b1185fece9022c5b1b29f1a46922d02adcf691..55dd20ec5cbd9ceb2c6b9925d809b4820336faf5 100644 (file)
@@ -164,6 +164,7 @@ ao-tools/ao-load/Makefile
 ao-tools/ao-telem/Makefile
 ao-tools/ao-stmload/Makefile
 ao-tools/ao-send-telem/Makefile
+ao-tools/ao-sky-flash/Makefile
 ao-utils/Makefile
 src/Version
 ])
index 9f24321b6d1398f2b0e38bdfb213588795ec3cec..122a0fed2349bfcc7cbe9895e8fe9b095c730888 100755 (executable)
@@ -27,7 +27,7 @@ build-indep: build-stamp
 
 build-stamp: configure-stamp  
        dh_testdir
-       $(MAKE) VERSION=$(PKG_VERSION)
+       $(MAKE)
        (cd doc ; $(MAKE))
        touch $@
 
index b2677a029ed9c66f3c33b3861fddb0382ece3ee0..e7ab353bbd2ef171107f6f937048cc476845a657 100644 (file)
@@ -277,6 +277,19 @@ NAR #88757, TRA #12200
       apogee and main ejection charges.  All Altus Metrum products are 
       designed for use with single-cell batteries with 3.7 volts nominal.
     </para>
+    <para>
+      The battery connectors are a standard 2-pin JST connector and
+      match batteries sold by Spark Fun. These batteries are
+      single-cell Lithium Polymer batteries that nominally provide 3.7
+      volts.  Other vendors sell similar batteries for RC aircraft
+      using mating connectors, however the polarity for those is
+      generally reversed from the batteries used by Altus Metrum
+      products. In particular, the Tenergy batteries supplied for use
+      in Featherweight flight computers are not compatible with Altus
+      Metrum flight computers or battery chargers. <emphasis>Check
+      polarity and voltage before connecting any battery not purchased
+      from Altus Metrum or Spark Fun.</emphasis>
+    </para>
     <para>
       By default, we use the unregulated output of the Li-Po battery directly
       to fire ejection charges.  This works marvelously with standard
@@ -481,7 +494,7 @@ NAR #88757, TRA #12200
       <para>
         You can monitor the operation of the radio link by watching the 
         lights on the devices. The red LED will flash each time a packet
-        is tramsitted, while the green LED will light up on TeleDongle when 
+        is transmitted, while the green LED will light up on TeleDongle when 
         it is waiting to receive a packet from the altimeter.
       </para>
     </section>
@@ -2199,7 +2212,7 @@ NAR #88757, TRA #12200
        </listitem>
        <listitem>
          <para>
-           RF interface for battery charging, configuration, and data recovery.
+           RF interface for configuration, and data recovery.
          </para>
        </listitem>
        <listitem>
index 9ba407af6f6a3e0f1027f4e5c5e5fa2378bfee6b..2ef546c98dc2d4d1f462bb2c042c9c9885a8df85 100644 (file)
@@ -480,10 +480,10 @@ ao_usb_putchar(char c) __critical __reentrant
        ao_usb_in_flushed = 0;
 }
 
-static char
+static int
 _ao_usb_pollchar(void)
 {
-       char c;
+       uint8_t c;
        uint8_t intx;
 
        if (!ao_usb_running)
@@ -517,10 +517,10 @@ _ao_usb_pollchar(void)
        return c;
 }
 
-char
+int
 ao_usb_pollchar(void)
 {
-       char    c;
+       int     c;
        cli();
        c = _ao_usb_pollchar();
        sei();
@@ -530,7 +530,7 @@ ao_usb_pollchar(void)
 char
 ao_usb_getchar(void) __critical
 {
-       char    c;
+       int     c;
 
        cli();
        while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
index f80004104130c324c19cd4e68884edc4b5a208a4..bfdc418a6ca2ae204c4f80aaa14726c67c0cf65c 100644 (file)
@@ -56,7 +56,7 @@ ao_adc_isr(void) __interrupt 1
        uint8_t __xdata *a;
 
        sequence = (ADCCON2 & ADCCON2_SCH_MASK) >> ADCCON2_SCH_SHIFT;
-#if TELEMETRUM_V_0_1 || TELEMETRUM_V_0_2 || TELEMETRUM_V_1_0 || TELEMETRUM_V_1_1 || TELEMETRUM_V_1_2 || TELELAUNCH_V_0_1
+#if TELEMETRUM_V_0_1 || TELEMETRUM_V_0_2 || TELEMETRUM_V_1_0 || TELEMETRUM_V_1_1 || TELEMETRUM_V_1_2 || TELELAUNCH_V_0_1 || TELEBALLOON_V_1_1
        /* TeleMetrum readings */
 #if HAS_ACCEL_REF
        if (sequence == 2) {
index 847b5aaf857da6b602aeb28ee13e862e614daf35..4e534697021d71eab0266c0e977ac5c207ea4cf1 100644 (file)
@@ -193,54 +193,39 @@ ao_dbg_long_delay(void)
 #define AO_RESET_LOW_DELAY     AO_MS_TO_TICKS(100)
 #define AO_RESET_HIGH_DELAY    AO_MS_TO_TICKS(100)
 
-void
-ao_dbg_debug_mode(void)
+static void
+ao_dbg_send_bits_delay(uint8_t msk, uint8_t val)
 {
-       ao_dbg_set_pins();
        ao_dbg_long_delay();
-       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
-       ao_dbg_long_delay();
-       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|    0    );
-       ao_delay(AO_RESET_LOW_DELAY);
-       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
-       ao_dbg_long_delay();
-       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|    0    );
-       ao_dbg_long_delay();
-       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
-       ao_dbg_long_delay();
-       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|DBG_RESET_N);
-       ao_delay(AO_RESET_HIGH_DELAY);
+       ao_dbg_send_bits(msk, val);
 }
 
 void
-ao_dbg_reset(void)
+ao_dbg_do_reset(uint8_t clock_up)
 {
        ao_dbg_set_pins();
-       ao_dbg_long_delay();
-       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
-       ao_dbg_long_delay();
-       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
+       ao_dbg_send_bits_delay(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
+       ao_dbg_send_bits_delay(DBG_CLOCK|DBG_DATA|DBG_RESET_N, clock_up |DBG_DATA|    0    );
        ao_delay(AO_RESET_LOW_DELAY);
-       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
-       ao_dbg_long_delay();
-       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
-       ao_dbg_long_delay();
-       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
-       ao_dbg_long_delay();
-       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
+       ao_dbg_send_bits      (DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
+       ao_dbg_send_bits_delay(DBG_CLOCK|DBG_DATA|DBG_RESET_N, clock_up |DBG_DATA|    0    );
+       ao_dbg_send_bits_delay(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
+       ao_dbg_send_bits_delay(DBG_CLOCK|DBG_DATA|DBG_RESET_N, clock_up |DBG_DATA|DBG_RESET_N);
        ao_delay(AO_RESET_HIGH_DELAY);
 }
 
 static void
 debug_enable(void)
 {
-       ao_dbg_debug_mode();
+       /* toggle clock line while holding reset low */
+       ao_dbg_do_reset(0);
 }
 
 static void
 debug_reset(void)
 {
-       ao_dbg_reset();
+       /* hold clock high while holding reset low */
+       ao_dbg_do_reset(DBG_CLOCK);
 }
 
 static void
@@ -281,22 +266,6 @@ debug_get(void)
        putchar('\n');
 }
 
-static uint8_t
-getnibble(void)
-{
-       __pdata char    c;
-
-       c = getchar();
-       if ('0' <= c && c <= '9')
-               return c - '0';
-       if ('a' <= c && c <= 'f')
-               return c - ('a' - 10);
-       if ('A' <= c && c <= 'F')
-               return c - ('A' - 10);
-       ao_cmd_status = ao_cmd_lex_error;
-       return 0;
-}
-
 static void
 debug_input(void)
 {
@@ -338,8 +307,8 @@ debug_output(void)
                return;
        ao_dbg_start_transfer(addr);
        while (count--) {
-               b = getnibble() << 4;
-               b |= getnibble();
+               b = ao_getnibble() << 4;
+               b |= ao_getnibble();
                if (ao_cmd_status != ao_cmd_success)
                        return;
                ao_dbg_write_byte(b);
index 4838380228214dcf7fe0e475bf493a89237bcc21..8913a9b075333d1532064d5357aebd90051d7369 100644 (file)
@@ -34,8 +34,14 @@ const __code struct ao_serial_speed ao_serial_speeds[] = {
                /* .baud = */ 59,
                /* .gcr =  */ (11 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
        },
+       /* [AO_SERIAL_SPEED_115200] = */ {
+               /* .baud = */ 59,
+               /* .gcr =  */ (12 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
+       },
 };
 
+#define AO_SERIAL_SPEED_MAX    AO_SERIAL_SPEED_115200
+
 #if HAS_SERIAL_0
 
 volatile __xdata struct ao_fifo        ao_serial0_rx_fifo;
@@ -85,10 +91,10 @@ ao_serial0_getchar(void) __critical
 }
 
 #if USE_SERIAL_0_STDIN
-char
+int
 ao_serial0_pollchar(void) __critical
 {
-       char    c;
+       uint8_t c;
        if (ao_fifo_empty(ao_serial0_rx_fifo))
                return AO_READ_AGAIN;
        ao_fifo_remove(ao_serial0_rx_fifo,c);
@@ -116,7 +122,7 @@ void
 ao_serial0_set_speed(uint8_t speed)
 {
        ao_serial0_drain();
-       if (speed > AO_SERIAL_SPEED_57600)
+       if (speed > AO_SERIAL_SPEED_MAX)
                return;
        U0UCR |= UxUCR_FLUSH;
        U0BAUD = ao_serial_speeds[speed].baud;
@@ -173,10 +179,10 @@ ao_serial1_getchar(void) __critical
 }
 
 #if USE_SERIAL_1_STDIN
-char
+int
 ao_serial1_pollchar(void) __critical
 {
-       char    c;
+       uint8_t c;
        if (ao_fifo_empty(ao_serial1_rx_fifo))
                return AO_READ_AGAIN;
        ao_fifo_remove(ao_serial1_rx_fifo,c);
@@ -204,7 +210,7 @@ void
 ao_serial1_set_speed(uint8_t speed)
 {
        ao_serial1_drain();
-       if (speed > AO_SERIAL_SPEED_57600)
+       if (speed > AO_SERIAL_SPEED_MAX)
                return;
        U1UCR |= UxUCR_FLUSH;
        U1BAUD = ao_serial_speeds[speed].baud;
index ce26e8088a4cfee539b78bb82ea54538dab1af9d..f66e807cf7bf13e2d9c774a56645cde6fca4923a 100644 (file)
@@ -382,19 +382,19 @@ ao_usb_putchar(char c) __critical __reentrant
                ao_usb_in_send();
 }
 
-char
+int
 ao_usb_pollchar(void) __critical
 {
-       char c;
+       uint8_t c;
        if (ao_usb_out_bytes == 0) {
                USBINDEX = AO_USB_OUT_EP;
                if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0)
-                       return AO_READ_AGAIN;
+                       return -1;
                ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL;
                if (ao_usb_out_bytes == 0) {
                        USBINDEX = AO_USB_OUT_EP;
                        USBCSOL &= ~USBCSOL_OUTPKT_RDY;
-                       return AO_READ_AGAIN;
+                       return -1;
                }
        }
        --ao_usb_out_bytes;
@@ -409,7 +409,7 @@ ao_usb_pollchar(void) __critical
 char
 ao_usb_getchar(void) __critical
 {
-       char    c;
+       int     c;
 
        while ((c = ao_usb_pollchar()) == AO_READ_AGAIN)
                ao_sleep(&ao_stdin_ready);
index 81d92e72b2d512483b4640a08cf9c1651a2abab3..df5bbf487e2469702421b27a25d7ac9378351d03 100644 (file)
@@ -170,6 +170,10 @@ ao_cmd_hex(void);
 void
 ao_cmd_decimal(void);
 
+/* Read a single hex nibble off stdin. */
+uint8_t
+ao_getnibble(void);
+
 uint8_t
 ao_match_word(__code char *word);
 
@@ -525,6 +529,11 @@ ao_radio_recv_abort(void);
 void
 ao_radio_test(uint8_t on);
 
+typedef int16_t (*ao_radio_fill_func)(uint8_t *buffer, int16_t len);
+
+void
+ao_radio_send_lots(ao_radio_fill_func fill);
+
 /*
  * Compute the packet length as follows:
  *
@@ -595,10 +604,10 @@ ao_monitor_init(void) __reentrant;
  * ao_stdio.c
  */
 
-#define AO_READ_AGAIN  ((char) -1)
+#define AO_READ_AGAIN  (-1)
 
 struct ao_stdio {
-       char    (*pollchar)(void);
+       int     (*pollchar)(void);
        void    (*putchar)(char c) __reentrant;
        void    (*flush)(void);
        uint8_t echo;
@@ -617,7 +626,7 @@ uint8_t
 ao_echo(void);
 
 int8_t
-ao_add_stdio(char (*pollchar)(void),
+ao_add_stdio(int (*pollchar)(void),
             void (*putchar)(char) __reentrant,
             void (*flush)(void)) __reentrant;
 
@@ -675,7 +684,7 @@ extern __xdata uint8_t ao_force_freq;
 #endif
 
 #define AO_CONFIG_MAJOR        1
-#define AO_CONFIG_MINOR        12
+#define AO_CONFIG_MINOR        13
 
 #define AO_AES_LEN 16
 
@@ -702,12 +711,17 @@ struct ao_config {
 #if AO_PYRO_NUM
        struct ao_pyro  pyro[AO_PYRO_NUM];      /* minor version 12 */
 #endif
+       uint16_t        aprs_interval;          /* minor version 13 */
 };
 
 #define AO_IGNITE_MODE_DUAL            0
 #define AO_IGNITE_MODE_APOGEE          1
 #define AO_IGNITE_MODE_MAIN            2
 
+#define AO_RADIO_ENABLE_CORE           1
+#define AO_RADIO_DISABLE_TELEMETRY     2
+#define AO_RADIO_DISABLE_RDF           4
+
 #define AO_PAD_ORIENTATION_ANTENNA_UP  0
 #define AO_PAD_ORIENTATION_ANTENNA_DOWN        1
 
index 1814cecf5021848e4fe88b8fc3841dd10e6a491f..3d086a57e106d8f0110e0da6ad8a309fe985552d 100644 (file)
@@ -110,6 +110,22 @@ putnibble(uint8_t v)
                putchar(v + ('a' - 10));
 }
 
+uint8_t
+ao_getnibble(void)
+{
+       char    c;
+
+       c = getchar();
+       if ('0' <= c && c <= '9')
+               return c - '0';
+       if ('a' <= c && c <= 'f')
+               return c - ('a' - 10);
+       if ('A' <= c && c <= 'F')
+               return c - ('A' - 10);
+       ao_cmd_status = ao_cmd_lex_error;
+       return 0;
+}
+
 void
 ao_cmd_put16(uint16_t v)
 {
@@ -249,12 +265,25 @@ ao_reboot(void)
 static void
 version(void)
 {
-       printf("manufacturer     %s\n", ao_manufacturer);
-       printf("product          %s\n", ao_product);
-       printf("serial-number    %u\n", ao_serial_number);
+       printf("manufacturer     %s\n"
+              "product          %s\n"
+              "serial-number    %u\n"
+#if HAS_FLIGHT
+              "current-flight   %u\n"
+#endif
+#if HAS_LOG
+              "log-format       %u\n"
+#endif
+              , ao_manufacturer
+              , ao_product
+              , ao_serial_number
+#if HAS_FLIGHT
+              , ao_flight_number
+#endif
 #if HAS_LOG
-       printf("log-format       %u\n", ao_log_format);
+              , ao_log_format
 #endif
+               );
 #if HAS_MS5607
        ao_ms5607_info();
 #endif
index e85ddcb4d74d9a53dbb0b2ed9630d4be0f667cfe..0aac16a678ad1a6296bb1c4278bf5985bfbc0576 100644 (file)
@@ -128,7 +128,7 @@ _ao_config_get(void)
                if (minor < 6)
                        ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION;
                if (minor < 8)
-                       ao_config.radio_enable = TRUE;
+                       ao_config.radio_enable = AO_RADIO_ENABLE_CORE;
                if (minor < 9)
                        ao_xmemset(&ao_config.aes_key, '\0', AO_AES_LEN);
                if (minor < 10)
@@ -139,6 +139,8 @@ _ao_config_get(void)
                if (minor < 12)
                        memset(&ao_config.pyro, '\0', sizeof (ao_config.pyro));
 #endif
+               if (minor < 13)
+                       ao_config.aprs_interval = 0;
                ao_config.minor = AO_CONFIG_MINOR;
                ao_config_dirty = 1;
        }
@@ -498,6 +500,27 @@ ao_config_key_set(void) __reentrant
 }
 #endif
 
+#if HAS_APRS
+
+void
+ao_config_aprs_show(void)
+{
+       printf ("APRS interval: %d\n", ao_config.aprs_interval);
+}
+
+void
+ao_config_aprs_set(void)
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.aprs_interval = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
+
+#endif /* HAS_APRS */
+
 struct ao_config_var {
        __code char     *str;
        void            (*set)(void) __reentrant;
@@ -529,15 +552,15 @@ __code struct ao_config_var ao_config_vars[] = {
          ao_config_callsign_set,       ao_config_callsign_show },
        { "e <0 disable, 1 enable>\0Enable telemetry and RDF",
          ao_config_radio_enable_set, ao_config_radio_enable_show },
+       { "f <cal>\0Radio calib (cal = rf/(xtal/2^16))",
+         ao_config_radio_cal_set,      ao_config_radio_cal_show },
 #endif /* HAS_RADIO */
 #if HAS_ACCEL
        { "a <+g> <-g>\0Accel calib (0 for auto)",
          ao_config_accel_calibrate_set,ao_config_accel_calibrate_show },
+       { "o <0 antenna up, 1 antenna down>\0Set pad orientation",
+         ao_config_pad_orientation_set,ao_config_pad_orientation_show },
 #endif /* HAS_ACCEL */
-#if HAS_RADIO
-       { "f <cal>\0Radio calib (cal = rf/(xtal/2^16))",
-         ao_config_radio_cal_set,      ao_config_radio_cal_show },
-#endif /* HAS_RADIO */
 #if HAS_LOG
        { "l <size>\0Flight log size (kB)",
          ao_config_log_set,            ao_config_log_show },
@@ -546,10 +569,6 @@ __code struct ao_config_var ao_config_vars[] = {
        { "i <0 dual, 1 apogee, 2 main>\0Set igniter mode",
          ao_config_ignite_mode_set,    ao_config_ignite_mode_show },
 #endif
-#if HAS_ACCEL
-       { "o <0 antenna up, 1 antenna down>\0Set pad orientation",
-         ao_config_pad_orientation_set,ao_config_pad_orientation_show },
-#endif
 #if HAS_AES
        { "k <32 hex digits>\0Set AES encryption key",
          ao_config_key_set, ao_config_key_show },
@@ -557,6 +576,10 @@ __code struct ao_config_var ao_config_vars[] = {
 #if AO_PYRO_NUM
        { "P <n,?>\0Configure pyro channels",
          ao_pyro_set, ao_pyro_show },
+#endif
+#if HAS_APRS
+       { "A <secs>\0APRS packet interval (0 disable)",
+         ao_config_aprs_set, ao_config_aprs_show },
 #endif
        { "s\0Show",
          ao_config_show,               0 },
index 6fdd19cb9b7ca88cc72d1b6fd52073cd3ac032a2..7e2f85d8fb569894c09a75672f57f046df048007 100644 (file)
@@ -288,4 +288,25 @@ typedef int16_t accel_t;
 
 #endif
 
+#if !HAS_GYRO && HAS_MPU6000
+
+#define HAS_GYRO       1
+
+typedef int16_t        gyro_t;
+typedef int32_t angle_t;
+
+/* Y axis is aligned with the direction of motion (along) */
+/* X axis is aligned in the other board axis (across) */
+/* Z axis is aligned perpendicular to the board (through) */
+
+#define ao_data_along(packet)  ((packet)->mpu6000.accel_y)
+#define ao_data_across(packet) ((packet)->mpu6000.accel_x)
+#define ao_data_through(packet)        ((packet)->mpu6000.accel_z)
+
+#define ao_data_roll(packet)   ((packet)->mpu6000.gyro_y)
+#define ao_data_pitch(packet)  ((packet)->mpu6000.gyro_x)
+#define ao_data_yaw(packet)    ((packet)->mpu6000.gyro_z)
+
+#endif
+
 #endif /* _AO_DATA_H_ */
index 4eaed4207a16a56a94260bf6519162db8b3841c1..036d6f2de56c134ab445c85b5b709c7e019a5076 100644 (file)
@@ -199,10 +199,16 @@ struct ao_log_mega {
        union {                                         /* 4 */
                /* AO_LOG_FLIGHT */
                struct {
-                       uint16_t        flight;         /* 4 */
-                       int16_t         ground_accel;   /* 6 */
-                       uint32_t        ground_pres;    /* 8 */
-               } flight;                               /* 12 */
+                       uint16_t        flight;                 /* 4 */
+                       int16_t         ground_accel;           /* 6 */
+                       uint32_t        ground_pres;            /* 8 */
+                       int16_t         ground_accel_along;     /* 16 */
+                       int16_t         ground_accel_across;    /* 12 */
+                       int16_t         ground_accel_through;   /* 14 */
+                       int16_t         ground_roll;            /* 18 */
+                       int16_t         ground_pitch;           /* 20 */
+                       int16_t         ground_yaw;             /* 22 */
+               } flight;                                       /* 24 */
                /* AO_LOG_STATE */
                struct {
                        uint16_t        state;
index ac1590db760f67ee82506a07ced3b87ce711480d..e03687ada912d8352527179caa9117e8645bd630 100644 (file)
@@ -94,6 +94,14 @@ ao_log(void)
        log.tick = ao_sample_tick;
 #if HAS_ACCEL
        log.u.flight.ground_accel = ao_ground_accel;
+#endif
+#if HAS_GYRO
+       log.u.flight.ground_accel_along = ao_ground_accel_along;
+       log.u.flight.ground_accel_across = ao_ground_accel_across;
+       log.u.flight.ground_accel_through = ao_ground_accel_through;
+       log.u.flight.ground_pitch = ao_ground_pitch;
+       log.u.flight.ground_yaw = ao_ground_yaw;
+       log.u.flight.ground_roll = ao_ground_roll;
 #endif
        log.u.flight.ground_pres = ao_ground_pres;
        log.u.flight.flight = ao_flight_number;
index 18ab85dd4fd5b9ab1aee3409784b8db165b43eb9..23ebf7ddc62dc8e2efaf4e39531a3c2817c8ff19 100644 (file)
@@ -102,9 +102,9 @@ ao_log_single(void)
                while (ao_log_running) {
                        /* Write samples to EEPROM */
                        while (ao_log_monitor_pos != ao_monitor_head) {
-                               memcpy(&ao_log_single_write_data.telemetry,
-                                      &ao_monitor_ring[ao_log_monitor_pos],
-                                      AO_LOG_SINGLE_SIZE);
+                               ao_xmemcpy(&ao_log_single_write_data.telemetry,
+                                          &ao_monitor_ring[ao_log_monitor_pos],
+                                          AO_LOG_SINGLE_SIZE);
                                ao_log_single_write();
                                ao_log_monitor_pos = ao_monitor_ring_next(ao_log_monitor_pos);
                                ao_log_telem_track();
index 0eafd3b2d5294122847eb7891b85226e2f8b17ef..08b184d60fc340596208c2660b842fc07cff7a69 100644 (file)
@@ -62,7 +62,7 @@ ao_packet_flush(void);
 void
 ao_packet_putchar(char c) __reentrant;
 
-char
+int
 ao_packet_pollchar(void);
 
 #if PACKET_HAS_MASTER
index 985c094046de9ad9923f0aa7803c6a9f899e3c46..dec44f9fa0910aa422ce8e7771c75001aba3fb94 100644 (file)
@@ -37,6 +37,16 @@ __pdata alt_t                ao_sample_height;
 #if HAS_ACCEL
 __pdata accel_t                ao_sample_accel;
 #endif
+#if HAS_GYRO
+__pdata accel_t                ao_sample_accel_along;
+__pdata accel_t                ao_sample_accel_across;
+__pdata accel_t                ao_sample_accel_through;
+__pdata gyro_t         ao_sample_roll;
+__pdata gyro_t         ao_sample_pitch;
+__pdata gyro_t         ao_sample_yaw;
+__pdata angle_t                ao_sample_angle;
+__pdata angle_t                ao_sample_roll_angle;
+#endif
 
 __data uint8_t         ao_sample_data;
 
@@ -53,6 +63,15 @@ __pdata accel_t              ao_accel_2g;            /* factory accel calibration */
 __pdata int32_t                ao_accel_scale;         /* sensor to m/s² conversion */
 #endif
 
+#if HAS_GYRO
+__pdata accel_t                ao_ground_accel_along;
+__pdata accel_t                ao_ground_accel_across;
+__pdata accel_t                ao_ground_accel_through;
+__pdata gyro_t         ao_ground_pitch;
+__pdata gyro_t         ao_ground_yaw;
+__pdata gyro_t         ao_ground_roll;
+#endif
+
 static __pdata uint8_t ao_preflight;           /* in preflight mode */
 
 static __pdata uint16_t        nsamples;
@@ -60,6 +79,14 @@ __pdata int32_t ao_sample_pres_sum;
 #if HAS_ACCEL
 __pdata int32_t ao_sample_accel_sum;
 #endif
+#if HAS_GYRO
+__pdata int32_t ao_sample_accel_along_sum;
+__pdata int32_t ao_sample_accel_across_sum;
+__pdata int32_t        ao_sample_accel_through_sum;
+__pdata int32_t ao_sample_pitch_sum;
+__pdata int32_t ao_sample_yaw_sum;
+__pdata int32_t        ao_sample_roll_sum;
+#endif
 
 static void
 ao_sample_preflight_add(void)
@@ -68,6 +95,14 @@ ao_sample_preflight_add(void)
        ao_sample_accel_sum += ao_sample_accel;
 #endif
        ao_sample_pres_sum += ao_sample_pres;
+#if HAS_GYRO
+       ao_sample_accel_along_sum += ao_sample_accel_along;
+       ao_sample_accel_across_sum += ao_sample_accel_across;
+       ao_sample_accel_through_sum += ao_sample_accel_through;
+       ao_sample_pitch_sum += ao_sample_pitch;
+       ao_sample_yaw_sum += ao_sample_yaw;
+       ao_sample_roll_sum += ao_sample_roll;
+#endif
        ++nsamples;
 }
 
@@ -80,8 +115,23 @@ ao_sample_preflight_set(void)
 #endif
        ao_ground_pres = ao_sample_pres_sum >> 9;
        ao_ground_height = pres_to_altitude(ao_ground_pres);
-       nsamples = 0;
        ao_sample_pres_sum = 0;
+#if HAS_GYRO
+       ao_ground_accel_along = ao_sample_accel_along_sum >> 9;
+       ao_ground_accel_across = ao_sample_accel_across_sum >> 9;
+       ao_ground_accel_through = ao_sample_accel_through_sum >> 9;
+       ao_ground_pitch = ao_sample_pitch_sum >> 9;
+       ao_ground_yaw = ao_sample_yaw_sum >> 9;
+       ao_ground_roll = ao_sample_roll_sum >> 9;
+       ao_sample_accel_along_sum = 0;
+       ao_sample_accel_across_sum = 0;
+       ao_sample_accel_through_sum = 0;
+       ao_sample_pitch_sum = 0;
+       ao_sample_yaw_sum = 0;
+       ao_sample_roll_sum = 0;
+       ao_sample_angle = 0;
+#endif 
+       nsamples = 0;
 }
 
 static void
@@ -122,6 +172,25 @@ ao_sample_preflight_update(void)
                ao_sample_preflight_set();
 }
 
+#if 0
+#if HAS_GYRO
+static int32_t p_filt;
+static int32_t y_filt;
+
+static gyro_t inline ao_gyro(void) {
+       gyro_t  p = ao_sample_pitch - ao_ground_pitch;
+       gyro_t  y = ao_sample_yaw - ao_ground_yaw;
+
+       p_filt = p_filt - (p_filt >> 6) + p;
+       y_filt = y_filt - (y_filt >> 6) + y;
+
+       p = p_filt >> 6;
+       y = y_filt >> 6;
+       return ao_sqrt(p*p + y*y);
+}
+#endif
+#endif
+
 uint8_t
 ao_sample(void)
 {
@@ -147,6 +216,14 @@ ao_sample(void)
                        ao_sample_accel = ao_data_accel_invert(ao_sample_accel);
                ao_data_set_accel(ao_data, ao_sample_accel);
 #endif
+#if HAS_GYRO
+               ao_sample_accel_along = ao_data_along(ao_data);
+               ao_sample_accel_across = ao_data_across(ao_data);
+               ao_sample_accel_through = ao_data_through(ao_data);
+               ao_sample_pitch = ao_data_pitch(ao_data);
+               ao_sample_yaw = ao_data_yaw(ao_data);
+               ao_sample_roll = ao_data_roll(ao_data);
+#endif
 
                if (ao_preflight)
                        ao_sample_preflight();
@@ -154,6 +231,9 @@ ao_sample(void)
                        if (ao_flight_state < ao_flight_boost)
                                ao_sample_preflight_update();
                        ao_kalman();
+#if HAS_GYRO
+                       /* do quaternion stuff here... */
+#endif
                }
                ao_sample_data = ao_data_ring_next(ao_sample_data);
        }
@@ -170,6 +250,21 @@ ao_sample_init(void)
 #if HAS_ACCEL
        ao_sample_accel_sum = 0;
        ao_sample_accel = 0;
+#endif
+#if HAS_GYRO
+       ao_sample_accel_along_sum = 0;
+       ao_sample_accel_across_sum = 0;
+       ao_sample_accel_through_sum = 0;
+       ao_sample_accel_along = 0;
+       ao_sample_accel_across = 0;
+       ao_sample_accel_through = 0;
+       ao_sample_pitch_sum = 0;
+       ao_sample_yaw_sum = 0;
+       ao_sample_roll_sum = 0;
+       ao_sample_pitch = 0;
+       ao_sample_yaw = 0;
+       ao_sample_roll = 0;
+       ao_sample_angle = 0;
 #endif
        ao_sample_data = ao_data_head;
        ao_preflight = TRUE;
index 9336bdf9c8bfda847a2e0cfbe9166ed96baccedf..a2dac9792a8bc2c13a5de441daa3fd50adb731b6 100644 (file)
@@ -111,6 +111,14 @@ extern __pdata accel_t     ao_ground_accel;        /* startup acceleration */
 extern __pdata accel_t         ao_accel_2g;            /* factory accel calibration */
 extern __pdata int32_t ao_accel_scale;         /* sensor to m/s² conversion */
 #endif
+#if HAS_GYRO
+extern __pdata accel_t ao_ground_accel_along;
+extern __pdata accel_t ao_ground_accel_across;
+extern __pdata accel_t ao_ground_accel_through;
+extern __pdata gyro_t  ao_ground_pitch;
+extern __pdata gyro_t  ao_ground_yaw;
+extern __pdata gyro_t  ao_ground_roll;
+#endif
 
 void ao_sample_init(void);
 
index 1a8e74de9e586adbd87805c141e8a1df4d5da87d..66315d227e8e05ac8a620e6727e11d44586f00ca 100644 (file)
 
 static __xdata uint8_t ao_send[AO_MAX_SEND];
 
-static uint8_t
-getnibble(void)
-{
-       char    c;
-
-       c = getchar();
-       if ('0' <= c && c <= '9')
-               return c - '0';
-       if ('a' <= c && c <= 'f')
-               return c - ('a' - 10);
-       if ('A' <= c && c <= 'F')
-               return c - ('A' - 10);
-       ao_cmd_status = ao_cmd_lex_error;
-       return 0;
-}
-
 static void
 ao_send_packet(void)
 {
@@ -53,8 +37,8 @@ ao_send_packet(void)
                return;
        }
        for (i = 0; i < count; i++) {
-               b = getnibble() << 4;
-               b |= getnibble();
+               b = ao_getnibble() << 4;
+               b |= ao_getnibble();
                if (ao_cmd_status != ao_cmd_success)
                        return;
                ao_send[i] = b;
index 53aa8a89e2c7d7903270257f2118c1700b6a28a3..a799bf2c9bc4afd6322d507d7b27626d866a29e9 100644 (file)
@@ -22,6 +22,7 @@
 #define AO_SERIAL_SPEED_9600   1
 #define AO_SERIAL_SPEED_19200  2
 #define AO_SERIAL_SPEED_57600  3
+#define AO_SERIAL_SPEED_115200 4
 
 #if HAS_SERIAL_0
 extern volatile __xdata struct ao_fifo ao_serial0_rx_fifo;
@@ -30,6 +31,9 @@ extern volatile __xdata struct ao_fifo        ao_serial0_tx_fifo;
 char
 ao_serial0_getchar(void);
 
+int
+ao_serial0_pollchar(void);
+
 void
 ao_serial0_putchar(char c);
 
@@ -47,7 +51,7 @@ extern volatile __xdata struct ao_fifo        ao_serial1_tx_fifo;
 char
 ao_serial1_getchar(void);
 
-char
+int
 ao_serial1_pollchar(void);
 
 void
@@ -67,7 +71,7 @@ extern volatile __xdata struct ao_fifo        ao_serial2_tx_fifo;
 char
 ao_serial2_getchar(void);
 
-char
+int
 ao_serial2_pollchar(void);
 
 void
@@ -80,6 +84,26 @@ void
 ao_serial2_set_speed(uint8_t speed);
 #endif
 
+#if HAS_SERIAL_3
+extern volatile __xdata struct ao_fifo ao_serial3_rx_fifo;
+extern volatile __xdata struct ao_fifo ao_serial3_tx_fifo;
+
+char
+ao_serial3_getchar(void);
+
+int
+ao_serial3_pollchar(void);
+
+void
+ao_serial3_putchar(char c);
+
+void
+ao_serial3_drain(void);
+
+void
+ao_serial3_set_speed(uint8_t speed);
+#endif
+
 void
 ao_serial_init(void);
 
index 09c2e319be51aea52261c336cffde83789ced07a..3a550eaa74e48a4fab3abbe40f1a02cbc18d33f2 100644 (file)
@@ -15,7 +15,9 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
+#ifndef AO_FLIGHT_TEST
 #include "ao.h"
+#endif
 
 /* Adapted from int_sqrt.c in the linux kernel, which is licensed GPLv2 */
 /**
index 8cf66a239ac1db03d8d1d72c5c2bd7d44ab26a0c..1748dfe8d940ecc550ff41911db01b0259291ec9 100644 (file)
@@ -98,7 +98,7 @@ __xdata uint8_t ao_stdin_ready;
 char
 getchar(void) __reentrant
 {
-       char c;
+       int c;
        ao_arch_critical(
                int8_t stdio = ao_cur_stdio;
 
@@ -123,7 +123,7 @@ ao_echo(void)
 }
 
 int8_t
-ao_add_stdio(char (*pollchar)(void),
+ao_add_stdio(int (*pollchar)(void),
             void (*putchar)(char),
             void (*flush)(void)) __reentrant
 {
index 0411fbdd425921c42f26b68d5116f932bfc18d96..9cb074b5220a2c6279353d1b4ab5371be2dd5385 100644 (file)
@@ -305,6 +305,8 @@ ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *nam
                );
 }
 
+__data uint8_t ao_task_minimize_latency;
+
 /* Task switching function. This must not use any stack variables */
 void
 ao_yield(void) ao_arch_naked_define
@@ -331,7 +333,12 @@ ao_yield(void) ao_arch_naked_define
        }
 
        ao_arch_isr_stack();
-       ao_arch_block_interrupts();
+#if !HAS_TASK_QUEUE
+       if (ao_task_minimize_latency)
+               ao_arch_release_interrupts();
+       else
+#endif
+               ao_arch_block_interrupts();
 
 #if AO_CHECK_STACK
        in_yield = 1;
@@ -374,7 +381,7 @@ ao_yield(void) ao_arch_naked_define
                                break;
 
                        /* Wait for interrupts when there's nothing ready */
-                       if (ao_cur_task_index == ao_last_task_index)
+                       if (ao_cur_task_index == ao_last_task_index && !ao_task_minimize_latency)
                                ao_arch_wait_interrupt();
                }
        }
index 049f69a7c2fb121d2dbdffd2564d7bb8f989fe4e..50bfb220f081571572bbaab82395c1d0e29b1813 100644 (file)
@@ -47,6 +47,7 @@ struct ao_task {
 extern __xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS];
 extern __data uint8_t ao_num_tasks;
 extern __xdata struct ao_task *__data ao_cur_task;
+extern __data uint8_t ao_task_minimize_latency;        /* Reduce IRQ latency */
 
 /*
  ao_task.c
index 52ac94891adebd99f915cf97a20e95ddf171a18c..8d440e15410ff4bd7833bcd5da6e1380d8ba46f9 100644 (file)
@@ -22,6 +22,12 @@ static __pdata uint16_t ao_telemetry_interval;
 static __pdata uint8_t ao_rdf = 0;
 static __pdata uint16_t ao_rdf_time;
 
+#if HAS_APRS
+static __pdata uint16_t ao_aprs_time;
+
+#include <ao_aprs.h>
+#endif
+
 #if defined(MEGAMETRUM)
 #define AO_SEND_MEGA   1
 #endif
@@ -288,30 +294,40 @@ ao_telemetry(void)
                while (ao_telemetry_interval == 0)
                        ao_sleep(&telemetry);
                time = ao_rdf_time = ao_time();
+#if HAS_APRS
+               ao_aprs_time = time;
+#endif
                while (ao_telemetry_interval) {
 
-
+#if HAS_APRS
+                       if (!(ao_config.radio_enable & AO_RADIO_DISABLE_TELEMETRY))
+#endif
+                       {
 #ifdef AO_SEND_ALL_BARO
-                       ao_send_baro();
+                               ao_send_baro();
 #endif
 #ifdef AO_SEND_MEGA
-                       ao_send_mega_sensor();
-                       ao_send_mega_data();
+                               ao_send_mega_sensor();
+                               ao_send_mega_data();
 #else
-                       ao_send_sensor();
+                               ao_send_sensor();
 #endif
 
 #if HAS_COMPANION
-                       if (ao_companion_running)
-                               ao_send_companion();
+                               if (ao_companion_running)
+                                       ao_send_companion();
 #endif
-                       ao_send_configuration();
+                               ao_send_configuration();
 #if HAS_GPS
-                       ao_send_location();
-                       ao_send_satellite();
+                               ao_send_location();
+                               ao_send_satellite();
 #endif
+                       }
 #ifndef AO_SEND_ALL_BARO
                        if (ao_rdf &&
+#if HAS_APRS
+                           !(ao_config.radio_enable & AO_RADIO_DISABLE_RDF) &&
+#endif
                            (int16_t) (ao_time() - ao_rdf_time) >= 0)
                        {
 #if HAS_IGNITE_REPORT
@@ -325,6 +341,14 @@ ao_telemetry(void)
 #endif
                                        ao_radio_rdf();
                        }
+#if HAS_APRS
+                       if (ao_config.aprs_interval != 0 &&
+                           (int16_t) (ao_time() - ao_aprs_time) >= 0)
+                       {
+                               ao_aprs_time = ao_time() + AO_SEC_TO_TICKS(ao_config.aprs_interval);
+                               ao_aprs_send();
+                       }
+#endif
 #endif
                        time += ao_telemetry_interval;
                        delay = time - ao_time();
@@ -389,8 +413,9 @@ ao_rdf_set(uint8_t rdf)
        ao_rdf = rdf;
        if (rdf == 0)
                ao_radio_rdf_abort();
-       else
+       else {
                ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS;
+       }
 }
 
 __xdata struct ao_task ao_telemetry_task;
index e051db9323d5639e91e1931ba5607c6b238ab806..4476ee6be99f4ffd76db8f6d651ff2171616d989 100644 (file)
@@ -33,7 +33,7 @@ ao_usb_getchar(void);
 /* Poll for a charcter on the USB input queue.
  * returns AO_READ_AGAIN if none are available
  */
-char
+int
 ao_usb_pollchar(void);
 
 /* Flush the USB output queue */
diff --git a/src/drivers/ao_aprs.c b/src/drivers/ao_aprs.c
new file mode 100644 (file)
index 0000000..03bcab0
--- /dev/null
@@ -0,0 +1,599 @@
+/** 
+ * http://ad7zj.net/kd7lmo/aprsbeacon_code.html
+ *
+ * @mainpage Pico Beacon
+ *
+ * @section overview_sec Overview
+ *
+ * The Pico Beacon is an APRS based tracking beacon that operates in the UHF 420-450MHz band.  The device utilizes a 
+ * Microchip PIC 18F2525 embedded controller, Motorola M12+ GPS engine, and Analog Devices AD9954 DDS.  The device is capable
+ * of generating a 1200bps A-FSK and 9600 bps FSK AX.25 compliant APRS (Automatic Position Reporting System) message.
+
+
+ *
+ * @section history_sec Revision History
+ *
+ * @subsection v305 V3.05
+ * 23 Dec 2006, Change include; (1) change printf format width to conform to ANSI standard when new CCS 4.xx compiler released.
+ *
+ *
+ * @subsection v304 V3.04
+ * 10 Jan 2006, Change include; (1) added amplitude control to engineering mode,
+ *                                     (2) corrected number of bytes reported in log,
+ *                                     (3) add engineering command to set high rate position reports (5 seconds), and
+ *                                     (4) corrected size of LOG_COORD block when searching for end of log.
+ *
+ * @subsection v303 V3.03
+ * 15 Sep 2005, Change include; (1) removed AD9954 setting SDIO as input pin, 
+ *                                     (2) additional comments and Doxygen tags,
+ *                                     (3) integration and test code calculates DDS FTW,
+ *                                     (4) swapped bus and reference analog input ports (hardware change),
+ *                                     (5) added message that indicates we are reading flash log and reports length,
+ *                                     (6) report bus voltage in 10mV steps, and
+ *                                     (7) change log type enumerated values to XORed nibbles for error detection.
+ *
+ *
+ * @subsection v302 V3.02
+ * 6 Apr 2005, Change include; (1) corrected tracked satellite count in NMEA-0183 $GPGGA message,
+ *                                    (2) Doxygen documentation clean up and additions, and
+ *                                    (3) added integration and test code to baseline.
+ *
+ * 
+ * @subsection v301 V3.01
+ * 13 Jan 2005, Renamed project and files to Pico Beacon.
+ *
+ *
+ * @subsection v300 V3.00
+ * 15 Nov 2004, Change include; (1) Micro Beacon extreme hardware changes including integral transmitter,
+ *                                     (2) PIC18F2525 processor,
+ *                                     (3) AD9954 DDS support functions,
+ *                                     (4) added comments and formatting for doxygen,
+ *                                     (5) process GPS data with native Motorola protocol,
+ *                                     (6) generate plain text $GPGGA and $GPRMC messages,
+ *                                     (7) power down GPS 5 hours after lock,
+ *                                     (8) added flight data recorder, and
+ *                                     (9) added diagnostics terminal mode.
+ *
+ * 
+ * @subsection v201 V2.01
+ * 30 Jan 2004, Change include; (1) General clean up of in-line documentation, and 
+ *                                     (2) changed temperature resolution to 0.1 degrees F.
+ *
+ * 
+ * @subsection v200 V2.00
+ * 26 Oct 2002, Change include; (1) Micro Beacon II hardware changes including PIC18F252 processor,
+ *                                     (2) serial EEPROM, 
+ *                                     (3) GPS power control, 
+ *                                     (4) additional ADC input, and 
+ *                                     (5) LM60 temperature sensor.                            
+ *
+ *
+ * @subsection v101 V1.01
+ * 5 Dec 2001, Change include; (1) Changed startup message, and 
+ *                                    (2) applied SEPARATE pragma to several methods for memory usage.
+ *
+ *
+ * @subsection v100 V1.00
+ * 25 Sep 2001, Initial release.  Flew ANSR-3 and ANSR-4.
+ * 
+
+
+ *
+ *
+ * @section copyright_sec Copyright
+ *
+ * Copyright (c) 2001-2009 Michael Gray, KD7LMO
+
+
+ *
+ *
+ * @section gpl_sec GNU General Public License
+ *
+ *  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.
+ *
+ *  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
+ *  
+
+
+ * 
+ * 
+ * @section design Design Details
+ *
+ * Provides design details on a variety of the components that make up the Pico Beacon.
+ *
+ *  @subpage power
+ */
+
+/**
+ *  @page power Power Consumption
+ *
+ *  Measured DC power consumption.
+ * 
+ *  3VDC prime power current 
+
+ *
+ *    7mA Held in reset 
+
+ *   18mA Processor running, all I/O off 
+
+ *  110mA GPS running 
+
+ *  120mA GPS running w/antenna 
+
+ *  250mA DDS running and GPS w/antenna 
+
+ *  420mA DDS running, GPS w/antenna, and PA chain on with no RF 
+
+ *  900mA Transmit 
+
+ *
+ */
+
+#ifndef AO_APRS_TEST
+#include <ao.h>
+#endif
+
+#include <ao_aprs.h>
+
+// Public methods, constants, and data structures for each class.
+
+static void timeInit(void);
+
+static void tncInit(void);
+static void tnc1200TimerTick(void);
+
+/** @} */
+
+/**
+ *  @defgroup sys System Library Functions
+ *
+ *  Generic system functions similiar to the run-time C library.
+ *
+ *  @{
+ */
+
+/**
+ *    Calculate the CRC-16 CCITT of buffer that is length bytes long.
+ *    The crc parameter allow the calculation on the CRC on multiple buffers.
+ *
+ *    @param buffer Pointer to data buffer.
+ *    @param length number of bytes in data buffer
+ *    @param crc starting value
+ *
+ *    @return CRC-16 of buffer[0 .. length]
+ */
+static uint16_t sysCRC16(const uint8_t *buffer, uint8_t length, uint16_t crc)
+{
+    uint8_t i, bit, value;
+
+    for (i = 0; i < length; ++i) 
+    {
+        value = buffer[i];
+
+        for (bit = 0; bit < 8; ++bit) 
+        {
+            crc ^= (value & 0x01);
+            crc = ( crc & 0x01 ) ? ( crc >> 1 ) ^ 0x8408 : ( crc >> 1 );
+            value = value >> 1;
+        } // END for
+    } // END for
+
+    return crc ^ 0xffff;
+}
+
+/** @} */
+
+/**
+ *  @defgroup rtc Real Time Interrupt tick
+ *
+ *  Manage the built-in real time interrupt.  The interrupt clock PRI is 104uS (9600 bps).
+ *
+ *  @{
+ */
+
+/// 16-bit NCO where the upper 8-bits are used to index into the frequency generation table.
+static uint16_t timeNCO;
+
+/// Audio tone NCO update step (phase).
+static uint16_t timeNCOFreq;
+
+/**
+ *   Initialize the real-time clock.
+ */
+static void timeInit()
+{
+    timeNCO = 0x00;
+    timeNCOFreq = 0x2000;
+}
+
+/** @} */
+
+/**
+ *  @defgroup tnc TNC (Terminal Node Controller)
+ *
+ *  Functions that provide a subset of the TNC functions.
+ *
+ *  @{
+ */
+
+/// The number of start flag bytes to send before the packet message.  (360bits * 1200bps = 300mS)
+#define TNC_TX_DELAY 45
+
+/// The size of the TNC output buffer.
+#define TNC_BUFFER_SIZE 40
+
+/// States that define the current mode of the 1200 bps (A-FSK) state machine.
+typedef enum
+{
+    /// Stand by state ready to accept new message.
+    TNC_TX_READY,
+
+    /// 0x7E bit stream pattern used to define start of APRS message.
+    TNC_TX_SYNC,
+
+    /// Transmit the AX.25 header that contains the source/destination call signs, APRS path, and flags.
+    TNC_TX_HEADER,
+
+    /// Transmit the message data.
+    TNC_TX_DATA,
+
+    /// Transmit the end flag sequence.
+    TNC_TX_END
+} TNC_TX_1200BPS_STATE;
+
+/// AX.25 compliant packet header that contains destination, station call sign, and path.
+/// 0x76 for SSID-11, 0x78 for SSID-12
+static uint8_t TNC_AX25_HEADER[] = { 
+    'A' << 1, 'P' << 1, 'A' << 1, 'M' << 1, ' ' << 1, ' ' << 1, 0x60, \
+    'N' << 1, '0' << 1, 'C' << 1, 'A' << 1, 'L' << 1, 'L' << 1, 0x78, \
+    'W' << 1, 'I' << 1, 'D' << 1, 'E' << 1, '2' << 1, ' ' << 1, 0x65, \
+    0x03, 0xf0 };
+
+#define TNC_CALLSIGN_OFF       7
+#define TNC_CALLSIGN_LEN       6
+
+static void
+tncSetCallsign(void)
+{
+#ifndef AO_APRS_TEST
+       uint8_t i;
+
+       for (i = 0; i < TNC_CALLSIGN_LEN; i++) {
+               if (!ao_config.callsign[i])
+                       break;
+               TNC_AX25_HEADER[TNC_CALLSIGN_OFF + i] = ao_config.callsign[i] << 1;
+       }
+       for (; i < TNC_CALLSIGN_LEN; i++)
+               TNC_AX25_HEADER[TNC_CALLSIGN_OFF + i] = ' ' << 1;
+#endif
+}
+
+/// The next bit to transmit.
+static uint8_t tncTxBit;
+
+/// Current mode of the 1200 bps state machine.
+static TNC_TX_1200BPS_STATE tncMode;
+
+/// Counter for each bit (0 - 7) that we are going to transmit.
+static uint8_t tncBitCount;
+
+/// A shift register that holds the data byte as we bit shift it for transmit.
+static uint8_t tncShift;
+
+/// Index into the APRS header and data array for each byte as we transmit it.
+static uint8_t tncIndex;
+
+/// The number of bytes in the message portion of the AX.25 message.
+static uint8_t tncLength;
+
+/// A copy of the last 5 bits we've transmitted to determine if we need to bit stuff on the next bit.
+static uint8_t tncBitStuff;
+
+/// Buffer to hold the message portion of the AX.25 packet as we prepare it.
+static uint8_t tncBuffer[TNC_BUFFER_SIZE];
+
+/** 
+ *   Initialize the TNC internal variables.
+ */
+static void tncInit()
+{
+    tncTxBit = 0;
+    tncMode = TNC_TX_READY;
+}
+
+/**
+ *   Method that is called every 833uS to transmit the 1200bps A-FSK data stream.
+ *   The provides the pre and postamble as well as the bit stuffed data stream.
+ */
+static void tnc1200TimerTick()
+{
+    // Set the A-FSK frequency.
+    if (tncTxBit == 0x00)
+        timeNCOFreq = 0x2000;
+    else
+        timeNCOFreq = 0x3aab;
+
+    switch (tncMode) 
+    {
+        case TNC_TX_READY:
+            // Generate a test signal alteranting between high and low tones.
+            tncTxBit = (tncTxBit == 0 ? 1 : 0);
+            break;
+
+        case TNC_TX_SYNC:
+            // The variable tncShift contains the lastest data byte.
+            // NRZI enocde the data stream.
+            if ((tncShift & 0x01) == 0x00) {
+                if (tncTxBit == 0)
+                    tncTxBit = 1;
+                else
+                    tncTxBit = 0;
+           }
+                    
+            // When the flag is done, determine if we need to send more or data.
+            if (++tncBitCount == 8) 
+            {
+                tncBitCount = 0;
+                tncShift = 0x7e;
+
+                // Once we transmit x mS of flags, send the data.
+                // txDelay bytes * 8 bits/byte * 833uS/bit = x mS
+                if (++tncIndex == TNC_TX_DELAY) 
+                {
+                    tncIndex = 0;
+                    tncShift = TNC_AX25_HEADER[0];
+                    tncBitStuff = 0;
+                    tncMode = TNC_TX_HEADER;
+                } // END if
+            } else
+                tncShift = tncShift >> 1;
+            break;
+
+        case TNC_TX_HEADER:
+            // Determine if we have sent 5 ones in a row, if we have send a zero.
+            if (tncBitStuff == 0x1f) 
+            {
+                if (tncTxBit == 0)
+                    tncTxBit = 1;
+                else
+                    tncTxBit = 0;
+
+                tncBitStuff = 0x00;
+                return;
+            }    // END if
+
+            // The variable tncShift contains the lastest data byte.
+            // NRZI enocde the data stream.
+            if ((tncShift & 0x01) == 0x00) {
+                if (tncTxBit == 0)
+                    tncTxBit = 1;
+                else
+                    tncTxBit = 0;
+           }
+
+            // Save the data stream so we can determine if bit stuffing is 
+            // required on the next bit time.
+            tncBitStuff = ((tncBitStuff << 1) | (tncShift & 0x01)) & 0x1f;
+
+            // If all the bits were shifted, get the next byte.
+            if (++tncBitCount == 8) 
+            {
+                tncBitCount = 0;
+
+                // After the header is sent, then send the data.
+                if (++tncIndex == sizeof(TNC_AX25_HEADER)) 
+                {
+                    tncIndex = 0;
+                    tncShift = tncBuffer[0];
+                    tncMode = TNC_TX_DATA;
+                } else
+                    tncShift = TNC_AX25_HEADER[tncIndex];
+
+            } else
+                tncShift = tncShift >> 1;
+
+            break;
+
+        case TNC_TX_DATA:
+            // Determine if we have sent 5 ones in a row, if we have send a zero.
+            if (tncBitStuff == 0x1f) 
+            {
+                if (tncTxBit == 0)
+                    tncTxBit = 1;
+                else
+                    tncTxBit = 0;
+
+                tncBitStuff = 0x00;
+                return;
+            }    // END if
+
+            // The variable tncShift contains the lastest data byte.
+            // NRZI enocde the data stream.
+            if ((tncShift & 0x01) == 0x00) {
+                if (tncTxBit == 0)
+                    tncTxBit = 1;
+                else
+                    tncTxBit = 0;
+           }
+
+            // Save the data stream so we can determine if bit stuffing is 
+            // required on the next bit time.
+            tncBitStuff = ((tncBitStuff << 1) | (tncShift & 0x01)) & 0x1f;
+
+            // If all the bits were shifted, get the next byte.
+            if (++tncBitCount == 8) 
+            {
+                tncBitCount = 0;
+
+                // If everything was sent, transmit closing flags.
+                if (++tncIndex == tncLength) 
+                {
+                    tncIndex = 0;
+                    tncShift = 0x7e;
+                    tncMode = TNC_TX_END;
+                } else
+                    tncShift = tncBuffer[tncIndex];
+
+            } else
+                tncShift = tncShift >> 1;
+
+            break;
+
+        case TNC_TX_END:
+            // The variable tncShift contains the lastest data byte.
+            // NRZI enocde the data stream. 
+            if ((tncShift & 0x01) == 0x00) {
+                if (tncTxBit == 0)
+                    tncTxBit = 1;
+                else
+                    tncTxBit = 0;
+           }
+
+            // If all the bits were shifted, get the next one.
+            if (++tncBitCount == 8) 
+            {
+                tncBitCount = 0;
+                tncShift = 0x7e;
+    
+                // Transmit two closing flags.
+                if (++tncIndex == 2) 
+                {
+                    tncMode = TNC_TX_READY;
+
+                    return;
+                } // END if
+            } else
+                tncShift = tncShift >> 1;
+
+            break;
+    } // END switch
+}
+
+/**
+ *   Generate the plain text position packet.
+ */
+static int tncPositionPacket(void)
+{
+    int32_t    latitude = ao_gps_data.latitude;
+    int32_t    longitude = ao_gps_data.longitude;
+    int32_t    altitude = ao_gps_data.altitude;
+
+    uint16_t   lat_deg;
+    uint16_t   lon_deg;
+    uint16_t   lat_min;
+    uint16_t   lat_frac;
+    uint16_t   lon_min;
+    uint16_t   lon_frac;
+
+    char       lat_sign = 'N', lon_sign = 'E';
+
+    if (latitude < 0) {
+       lat_sign = 'S';
+       latitude = -latitude;
+    }
+
+    if (longitude < 0) {
+       lon_sign = 'W';
+       longitude = -longitude;
+    }
+
+    /* Round latitude and longitude by 0.005 minutes */
+    latitude = latitude + 833;
+    if (latitude > 900000000)
+       latitude = 900000000;
+    longitude = longitude + 833;
+    if (longitude > 1800000000)
+           longitude = 1800000000;
+
+    lat_deg = latitude / 10000000;
+    latitude -= lat_deg * 10000000;
+    latitude *= 60;
+    lat_min = latitude / 10000000;
+    latitude -= lat_min * 10000000;
+    lat_frac = latitude / 100000;
+
+    lon_deg = longitude / 10000000;
+    longitude -= lon_deg * 10000000;
+    longitude *= 60;
+    lon_min = longitude / 10000000;
+    longitude -= lon_min * 10000000;
+    lon_frac = longitude / 100000;
+
+    if (altitude < 0)
+       altitude = 0;
+
+    altitude = (altitude * (int32_t) 10000 + (3048/2)) / (int32_t) 3048;
+    
+    return sprintf ((char *) tncBuffer, "=%02u%02u.%02u%c\\%03u%02u.%02u%cO /A=%06u\015",
+                   lat_deg, lat_min, lat_frac, lat_sign,
+                   lon_deg, lon_min, lon_frac, lon_sign,
+                   altitude);
+}
+
+static int16_t
+tncFill(uint8_t *buf, int16_t len)
+{
+    int16_t    l = 0;
+    uint8_t    b;
+    uint8_t    bit;
+
+    while (tncMode != TNC_TX_READY && l < len) {
+       b = 0;
+       for (bit = 0; bit < 8; bit++) {
+           b = b << 1 | (timeNCO >> 15);
+           timeNCO += timeNCOFreq;
+       }
+       *buf++ = b;
+       l++;
+       tnc1200TimerTick();
+    }
+    if (tncMode == TNC_TX_READY)
+       l = -l;
+    return l;
+}
+
+/** 
+ *    Prepare an AX.25 data packet.  Each time this method is called, it automatically
+ *    rotates through 1 of 3 messages.
+ *
+ *    @param dataMode enumerated type that specifies 1200bps A-FSK or 9600bps FSK
+ */
+void ao_aprs_send(void)
+{
+    uint16_t crc;
+
+    timeInit();
+    tncInit();
+    tncSetCallsign();
+
+    tncLength = tncPositionPacket();
+
+    // Calculate the CRC for the header and message.
+    crc = sysCRC16(TNC_AX25_HEADER, sizeof(TNC_AX25_HEADER), 0xffff);
+    crc = sysCRC16(tncBuffer, tncLength, crc ^ 0xffff);
+
+    // Save the CRC in the message.
+    tncBuffer[tncLength++] = crc & 0xff;
+    tncBuffer[tncLength++] = (crc >> 8) & 0xff;
+
+    // Prepare the variables that are used in the real-time clock interrupt.
+    tncBitCount = 0;
+    tncShift = 0x7e;
+    tncTxBit = 0;
+    tncIndex = 0;
+    tncMode = TNC_TX_SYNC;
+
+    ao_radio_send_lots(tncFill);
+}
+
+/** @} */
diff --git a/src/drivers/ao_aprs.h b/src/drivers/ao_aprs.h
new file mode 100644 (file)
index 0000000..a033fa0
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright © 2012 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.
+ */
+
+#ifndef _AO_APRS_H_
+#define _AO_APRS_H_
+
+void
+ao_aprs_send(void);
+
+#endif /* _AO_APRS_H_ */
index f381604796dd3d390aae7469fce3df611782e49a..c862200a8fe01232f199777abe434d2ab4160b49 100644 (file)
@@ -120,7 +120,7 @@ uint8_t
 ao_btm_get_line(void)
 {
        uint8_t ao_btm_reply_len = 0;
-       char c;
+       int c;
 
        for (;;) {
 
index f27958f96ae397776248f17a64f1f687da780b0b..3e894f762b6809493bee519fa34cf2276504568b 100644 (file)
 #define AO_RADIO_MAX_RECV      sizeof(struct ao_packet)
 #define AO_RADIO_MAX_SEND      sizeof(struct ao_packet)
 
-uint8_t ao_radio_wake;
-uint8_t ao_radio_mutex;
-uint8_t ao_radio_abort;
-uint8_t ao_radio_in_recv;
+static uint8_t ao_radio_mutex;
+
+static uint8_t ao_radio_wake;          /* radio ready. Also used as sleep address */
+static uint8_t ao_radio_abort;         /* radio operation should abort */
+static uint8_t ao_radio_mcu_wake;      /* MARC status change */
+static uint8_t ao_radio_marc_status;   /* Last read MARC status value */
 
 #define CC1120_DEBUG   AO_FEC_DEBUG
 #define CC1120_TRACE   0
@@ -218,13 +220,32 @@ ao_radio_recv_abort(void)
 #define ao_radio_rdf_value 0x55
 
 static uint8_t
-ao_radio_marc_status(void)
+ao_radio_get_marc_status(void)
 {
        return ao_radio_reg_read(CC1120_MARC_STATUS1);
 }
 
 static void
-ao_radio_tx_isr(void)
+ao_radio_mcu_wakeup_isr(void)
+{
+       ao_radio_mcu_wake = 1;
+       ao_wakeup(&ao_radio_wake);
+}
+
+
+static void
+ao_radio_check_marc_status(void)
+{
+       ao_radio_mcu_wake = 0;
+       ao_radio_marc_status = ao_radio_get_marc_status();
+       
+       /* Anyt other than 'tx/rx finished' means an error occurred */
+       if (ao_radio_marc_status & ~(CC1120_MARC_STATUS1_TX_FINISHED|CC1120_MARC_STATUS1_RX_FINISHED))
+               ao_radio_abort = 1;
+}
+
+static void
+ao_radio_isr(void)
 {
        ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
        ao_radio_wake = 1;
@@ -234,8 +255,9 @@ ao_radio_tx_isr(void)
 static void
 ao_radio_start_tx(void)
 {
-       ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_tx_isr);
+       ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
        ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
+       ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
        ao_radio_strobe(CC1120_STX);
 }
 
@@ -247,6 +269,8 @@ ao_radio_idle(void)
                if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)
                        break;
        }
+       /* Flush any pending TX bytes */
+       ao_radio_strobe(CC1120_SFTX);
 }
 
 /*
@@ -261,7 +285,7 @@ ao_radio_idle(void)
 #define PACKET_DEV_M   80
 
 /*
- * For our packet data, set the symbol rate to 38360 Baud
+ * For our packet data, set the symbol rate to 38400 Baud
  *
  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
  *     Rdata = -------------------------------------- * fosc
@@ -294,18 +318,19 @@ static const uint16_t packet_setup[] = {
                                 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
                                 (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
                                 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
+       AO_CC1120_MARC_GPIO_IOCFG,              CC1120_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP,
 };
 
 static const uint16_t packet_tx_setup[] = {
        CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
                                 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
-       CC1120_IOCFG2,          CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG,
+       AO_CC1120_INT_GPIO_IOCFG,               CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG,
 };
 
 static const uint16_t packet_rx_setup[] = {
        CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
                                 (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)),
-       CC1120_IOCFG2,          CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT,
+       AO_CC1120_INT_GPIO_IOCFG,               CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT,
 };
 
 /*
@@ -323,12 +348,12 @@ static const uint16_t packet_rx_setup[] = {
 /*
  * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
  *
- *              (2**20 - DATARATE_M) * 2 ** DATARATE_E
+ *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
  *     Rdata = -------------------------------------- * fosc
  *                          2 ** 39
  *
- *     DATARATE_M = 511705
- *     DATARATE_E = 6
+ *     DATARATE_M = 25166
+ *     DATARATE_E = 5
  *
  * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
  */
@@ -358,7 +383,64 @@ static const uint16_t rdf_setup[] = {
                                 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
 };
 
-static uint8_t ao_radio_mode;
+/*
+ * APRS deviation is 5kHz
+ *
+ *     fdev = fosc >> 24 * (256 + dev_m) << dev_e
+ *
+ *             32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
+ */
+
+#define APRS_DEV_E     3
+#define APRS_DEV_M     71
+#define APRS_PACKET_LEN        50
+
+/*
+ * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
+ *
+ *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
+ *     Rdata = -------------------------------------- * fosc
+ *                          2 ** 39
+ *
+ *     DATARATE_M = 239914
+ *     DATARATE_E = 7
+ *
+ *     Rdata = 9599.998593330383301
+ *
+ */
+#define APRS_DRATE_E   7
+#define APRS_DRATE_M   239914
+
+static const uint16_t aprs_setup[] = {
+       CC1120_DEVIATION_M,     APRS_DEV_M,
+       CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
+                                (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
+                                (APRS_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
+       CC1120_DRATE2,          ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
+                                (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
+       CC1120_DRATE1,          ((APRS_DRATE_M >> 8) & 0xff),
+       CC1120_DRATE0,          ((APRS_DRATE_M >> 0) & 0xff),
+       CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
+                                (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
+       CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
+                                (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
+                                (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
+                                (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
+};
+
+#define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) |       \
+                             (CC1120_PKT_CFG0_LENGTH_CONFIG_INFINITE << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
+                             (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |      \
+                             (0 << CC1120_PKT_CFG0_UART_MODE_EN) |     \
+                             (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
+
+#define AO_PKT_CFG0_FIXED ((0 << CC1120_PKT_CFG0_RESERVED7) |          \
+                          (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
+                          (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |         \
+                          (0 << CC1120_PKT_CFG0_UART_MODE_EN) |        \
+                          (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
+
+static uint16_t ao_radio_mode;
 
 #define AO_RADIO_MODE_BITS_PACKET      1
 #define AO_RADIO_MODE_BITS_PACKET_TX   2
@@ -366,17 +448,23 @@ static uint8_t ao_radio_mode;
 #define AO_RADIO_MODE_BITS_TX_FINISH   8
 #define AO_RADIO_MODE_BITS_PACKET_RX   16
 #define AO_RADIO_MODE_BITS_RDF         32
+#define AO_RADIO_MODE_BITS_APRS                64
+#define AO_RADIO_MODE_BITS_INFINITE    128
+#define AO_RADIO_MODE_BITS_FIXED       256
 
 #define AO_RADIO_MODE_NONE             0
 #define AO_RADIO_MODE_PACKET_TX_BUF    (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
 #define AO_RADIO_MODE_PACKET_TX_FINISH (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)
 #define AO_RADIO_MODE_PACKET_RX                (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)
 #define AO_RADIO_MODE_RDF              (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH)
+#define AO_RADIO_MODE_APRS_BUF         (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
+#define AO_RADIO_MODE_APRS_LAST_BUF    (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF)
+#define AO_RADIO_MODE_APRS_FINISH      (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH)
 
 static void
-ao_radio_set_mode(uint8_t new_mode)
+ao_radio_set_mode(uint16_t new_mode)
 {
-       uint8_t changes;
+       uint16_t changes;
        int i;
 
        if (new_mode == ao_radio_mode)
@@ -392,10 +480,10 @@ ao_radio_set_mode(uint8_t new_mode)
                        ao_radio_reg_write(packet_tx_setup[i], packet_tx_setup[i+1]);
                
        if (changes & AO_RADIO_MODE_BITS_TX_BUF)
-               ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
+               ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
 
        if (changes & AO_RADIO_MODE_BITS_TX_FINISH)
-               ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
+               ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
 
        if (changes & AO_RADIO_MODE_BITS_PACKET_RX)
                for (i = 0; i < sizeof (packet_rx_setup) / sizeof (packet_rx_setup[0]); i += 2)
@@ -404,6 +492,17 @@ ao_radio_set_mode(uint8_t new_mode)
        if (changes & AO_RADIO_MODE_BITS_RDF)
                for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
                        ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
+
+       if (changes & AO_RADIO_MODE_BITS_APRS)
+               for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
+                       ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
+
+       if (changes & AO_RADIO_MODE_BITS_INFINITE)
+               ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
+
+       if (changes & AO_RADIO_MODE_BITS_FIXED)
+               ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_FIXED);
+
        ao_radio_mode = new_mode;
 }
 
@@ -430,11 +529,21 @@ ao_radio_setup(void)
        ao_radio_configured = 1;
 }
 
+static void
+ao_radio_set_len(uint8_t len)
+{
+       static uint8_t  last_len;
+
+       if (len != last_len) {
+               ao_radio_reg_write(CC1120_PKT_LEN, len);
+               last_len = len;
+       }
+}
+
 static void
 ao_radio_get(uint8_t len)
 {
        static uint32_t last_radio_setting;
-       static uint8_t  last_len;
 
        ao_mutex_get(&ao_radio_mutex);
        if (!ao_radio_configured)
@@ -445,10 +554,7 @@ ao_radio_get(uint8_t len)
                ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
                last_radio_setting = ao_config.radio_setting;
        }
-       if (len != last_len) {
-               ao_radio_reg_write(CC1120_PKT_LEN, len);
-               last_len = len;
-       }
+       ao_radio_set_len(len);
 }
 
 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
@@ -470,9 +576,11 @@ ao_rdf_run(void)
        ao_radio_start_tx();
 
        ao_arch_block_interrupts();
-       while (!ao_radio_wake && !ao_radio_abort)
+       while (!ao_radio_wake && !ao_radio_abort && !ao_radio_mcu_wake)
                ao_sleep(&ao_radio_wake);
        ao_arch_release_interrupts();
+       if (ao_radio_mcu_wake)
+               ao_radio_check_marc_status();
        if (!ao_radio_wake)
                ao_radio_idle();
        ao_radio_put();
@@ -562,6 +670,31 @@ ao_radio_test_cmd(void)
        }
 }
 
+static void
+ao_radio_wait_isr(void)
+{
+       ao_arch_block_interrupts();
+       while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort)
+               ao_sleep(&ao_radio_wake);
+       ao_arch_release_interrupts();
+       if (ao_radio_mcu_wake)
+               ao_radio_check_marc_status();
+}
+
+static uint8_t
+ao_radio_wait_tx(uint8_t wait_fifo)
+{
+       uint8_t fifo_space = 0;
+
+       do {
+               ao_radio_wait_isr();
+               if (!wait_fifo)
+                       return 0;
+               fifo_space = ao_radio_tx_fifo_space();
+       } while (!fifo_space && !ao_radio_abort);
+       return fifo_space;
+}
+
 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
 
 void
@@ -583,6 +716,7 @@ ao_radio_send(const void *d, uint8_t size)
        while (encode_len) {
                this_len = encode_len;
 
+               ao_radio_wake = 0;
                if (this_len > fifo_space) {
                        this_len = fifo_space;
                        ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
@@ -601,16 +735,81 @@ ao_radio_send(const void *d, uint8_t size)
                        ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
                }
                        
-               do {
-                       ao_radio_wake = 0;
-                       ao_arch_block_interrupts();
-                       while (!ao_radio_wake)
-                               ao_sleep(&ao_radio_wake);
-                       ao_arch_release_interrupts();
-                       if (!encode_len)
+               fifo_space = ao_radio_wait_tx(encode_len != 0);
+               if (ao_radio_abort) {
+                       ao_radio_idle();
+                       break;
+               }
+       }
+       ao_radio_put();
+}
+
+#define AO_RADIO_LOTS  64
+
+void
+ao_radio_send_lots(ao_radio_fill_func fill)
+{
+       uint8_t buf[AO_RADIO_LOTS], *b;
+       int     cnt;
+       int     total = 0;
+       uint8_t done = 0;
+       uint8_t started = 0;
+       uint8_t fifo_space;
+
+       ao_radio_get(0xff);
+       fifo_space = CC1120_FIFO_SIZE;
+       while (!done) {
+               cnt = (*fill)(buf, sizeof(buf));
+               if (cnt < 0) {
+                       done = 1;
+                       cnt = -cnt;
+               }
+               total += cnt;
+
+               /* At the last buffer, set the total length */
+               if (done)
+                       ao_radio_set_len(total & 0xff);
+
+               b = buf;
+               while (cnt) {
+                       uint8_t this_len = cnt;
+
+                       /* Wait for some space in the fifo */
+                       while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
+                               ao_radio_wake = 0;
+                               ao_radio_wait_isr();
+                       }
+                       if (ao_radio_abort)
                                break;
-                       fifo_space = ao_radio_tx_fifo_space();
-               } while (!fifo_space);
+                       if (this_len > fifo_space)
+                               this_len = fifo_space;
+
+                       cnt -= this_len;
+
+                       if (done) {
+                               if (cnt)
+                                       ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF);
+                               else
+                                       ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
+                       } else
+                               ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
+
+                       ao_radio_fifo_write(b, this_len);
+                       b += this_len;
+
+                       if (!started) {
+                               ao_radio_start_tx();
+                               started = 1;
+                       } else
+                               ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
+               }
+               if (ao_radio_abort) {
+                       ao_radio_idle();
+                       break;
+               }
+               /* Wait for the transmitter to go idle */
+               ao_radio_wake = 0;
+               ao_radio_wait_isr();
        }
        ao_radio_put();
 }
@@ -660,14 +859,21 @@ ao_radio_rx_isr(void)
 static uint16_t
 ao_radio_rx_wait(void)
 {
-       ao_arch_block_interrupts();
-       rx_waiting = 1;
-       while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
-              !ao_radio_abort) {
-               ao_sleep(&ao_radio_wake);
-       }
-       rx_waiting = 0;
-       ao_arch_release_interrupts();
+       do {
+               if (ao_radio_mcu_wake)
+                       ao_radio_check_marc_status();
+               ao_arch_block_interrupts();
+               rx_waiting = 1;
+               while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
+                      !ao_radio_abort &&
+                      !ao_radio_mcu_wake)
+               {
+                       if (ao_sleep(&ao_radio_wake))
+                               ao_radio_abort = 1;
+               }
+               rx_waiting = 0;
+               ao_arch_release_interrupts();
+       } while (ao_radio_mcu_wake);
        if (ao_radio_abort)
                return 0;
        rx_data_consumed += AO_FEC_DECODE_BLOCK;
@@ -703,30 +909,53 @@ ao_radio_recv(__xdata void *d, uint8_t size)
        rx_data_consumed = 0;
        rx_ignore = 2;
 
+       /* Must be set before changing the frequency; any abort
+        * after the frequency is set needs to terminate the read
+        * so that the registers can be reprogrammed
+        */
        ao_radio_abort = 0;
-       ao_radio_in_recv = 1;
+
        /* configure interrupt pin */
        ao_radio_get(len);
        ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
 
        ao_radio_wake = 0;
+       ao_radio_mcu_wake = 0;
 
        stm_spi2.cr2 = 0;
 
        /* clear any RXNE */
        (void) stm_spi2.dr;
 
-       ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
+       /* Have the radio signal when the preamble quality goes high */
+       ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_PQT_REACHED);
+       ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
+                        AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_HIGH);
+       ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
        ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
+       ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
 
        ao_radio_strobe(CC1120_SRX);
 
+       /* Wait for the preamble to appear */
+       ao_radio_wait_isr();
+       if (ao_radio_abort)
+               goto abort;
+
+       ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
+       ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
+                        AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH);
+
+       ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
+       ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
+
        ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
 
        ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
 
        ao_radio_burst_read_stop();
 
+abort:
        ao_radio_strobe(CC1120_SIDLE);
 
        /* Convert from 'real' rssi to cc1111-style values */
@@ -739,11 +968,6 @@ ao_radio_recv(__xdata void *d, uint8_t size)
 
        ((uint8_t *) d)[size] = (uint8_t) rssi;
 
-       ao_radio_in_recv = 0;
-
-       if (ao_radio_abort)
-               ao_delay(1);
-
 #if AO_PROFILE
        rx_last_done_tick = rx_done_tick;
        rx_done_tick = ao_profile_tick();
@@ -963,7 +1187,7 @@ static void ao_radio_show(void) {
        printf ("Status:   %02x\n", status);
        printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
        printf ("STATE:    %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
-       printf ("MARC:     %02x\n", ao_radio_marc_status());
+       printf ("MARC:     %02x\n", ao_radio_get_marc_status());
 
        for (i = 0; i < AO_NUM_CC1120_REG; i++)
                printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
@@ -1007,11 +1231,21 @@ ao_radio_test_recv()
        }
 }
 
+#include <ao_aprs.h>
+
+static void
+ao_radio_aprs()
+{
+       ao_packet_slave_stop();
+       ao_aprs_send();
+}
+
 #endif
 
 static const struct ao_cmds ao_radio_cmds[] = {
        { ao_radio_test_cmd,    "C <1 start, 0 stop, none both>\0Radio carrier test" },
 #if CC1120_DEBUG
+       { ao_radio_aprs,        "G\0Send APRS packet" },
        { ao_radio_show,        "R\0Show CC1120 status" },
        { ao_radio_beep,        "b\0Emit an RDF beacon" },
        { ao_radio_packet,      "p\0Send a test packet" },
@@ -1043,7 +1277,13 @@ ao_radio_init(void)
        ao_enable_port(AO_CC1120_INT_PORT);
        ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
                      AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
-                     ao_radio_tx_isr);
+                     ao_radio_isr);
+
+       /* Enable the hacked up GPIO3 pin */
+       ao_enable_port(AO_CC1120_MCU_WAKEUP_PORT);
+       ao_exti_setup(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN,
+                     AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
+                     ao_radio_mcu_wakeup_isr);
 
        ao_cmd_register(&ao_radio_cmds[0]);
 }
index c749adea9de2f2da295bf2aa64f28c9642ed1103..0ebe8429124966790244e0a2fa5083782a0525a6 100644 (file)
@@ -118,10 +118,13 @@ ao_companion_status(void) __reentrant
        printf("Companion running: %d\n", ao_companion_running);
        if (!ao_companion_running)
                return;
-       printf("device: %d\n", ao_companion_setup.board_id);
-       printf("update period: %d\n", ao_companion_setup.update_period);
-       printf("channels: %d\n", ao_companion_setup.channels);
-       printf("data:");
+       printf("device: %d\n"
+              "update period: %d\n"
+              "channels: %d\n"
+              "data:",
+              ao_companion_setup.board_id,
+              ao_companion_setup.update_period,
+              ao_companion_setup.channels);
        for(i = 0; i < ao_companion_setup.channels; i++)
                printf(" %5u", ao_companion_data[i]);
        printf("\n");
index d80da97ca6ea44a2cd2828380afa55eda19f0a0b..d2f67e6b6947b1f9cd4c8e1c87fc13a018eb23b7 100644 (file)
@@ -21,6 +21,7 @@
 
 #ifndef ao_gps_getchar
 #define ao_gps_getchar ao_serial1_getchar
+#define ao_gps_fifo    ao_serial1_rx_fifo
 #endif
 
 #ifndef ao_gps_putchar
@@ -453,6 +454,8 @@ ao_gps_nmea_parse(void)
        }
 }
 
+static uint8_t ao_gps_updating;
+
 void
 ao_gps(void) __reentrant
 {
@@ -468,6 +471,13 @@ ao_gps(void) __reentrant
                if (ao_gps_getchar() == '$') {
                        ao_gps_nmea_parse();
                }
+#ifndef AO_GPS_TEST
+               while (ao_gps_updating) {
+                       ao_usb_putchar(ao_gps_getchar());
+                       if (ao_fifo_empty(ao_gps_fifo))
+                               flush();
+               }
+#endif
        }
 }
 
@@ -492,8 +502,38 @@ gps_dump(void) __reentrant
        ao_mutex_put(&ao_gps_mutex);
 }
 
+static __code uint8_t ao_gps_115200[] = {
+       SKYTRAQ_MSG_3(5,0,5,0)  /* Set to 115200 baud */
+};
+
+static void
+ao_gps_set_speed_delay(uint8_t speed) {
+       ao_delay(AO_MS_TO_TICKS(500));
+       ao_gps_set_speed(speed);
+       ao_delay(AO_MS_TO_TICKS(500));
+}
+
+static void
+gps_update(void) __reentrant
+{
+       ao_gps_updating = 1;
+       ao_task_minimize_latency = 1;
+#if HAS_ADC
+       ao_timer_set_adc_interval(0);
+#endif
+       ao_skytraq_sendstruct(ao_gps_115200);
+       ao_gps_set_speed_delay(AO_SERIAL_SPEED_4800);
+       ao_skytraq_sendstruct(ao_gps_115200);
+       ao_gps_set_speed_delay(AO_SERIAL_SPEED_115200);
+
+       /* It's a binary protocol; abandon attempts to escape */
+       for (;;)
+               ao_gps_putchar(ao_usb_getchar());
+}
+
 __code struct ao_cmds ao_gps_cmds[] = {
        { gps_dump,     "g\0Display GPS" },
+       { gps_update,   "U\0Update GPS firmware" },
        { 0, NULL },
 };
 
index 9603c1debbbd0584b4519ff59dbc034dbeec31ad..9f696acefcb9f16e003672a42eaae5bddc428e6b 100644 (file)
@@ -99,18 +99,7 @@ static __xdata uint8_t ao_m25_mutex;
 
 static __xdata uint8_t ao_m25_instruction[4];
 
-#if HAS_BOOT_RADIO
-extern uint8_t ao_radio_in_recv;
-
-static void ao_boot_radio(void) {
-       if (ao_radio_in_recv)
-               ao_radio_recv_abort();
-}
-#else
-#define ao_boot_radio()
-#endif
-
-#define M25_SELECT(cs)         do { ao_boot_radio(); ao_spi_get_mask(AO_M25_SPI_CS_PORT,cs,AO_M25_SPI_BUS, AO_SPI_SPEED_FAST); } while (0)
+#define M25_SELECT(cs)         ao_spi_get_mask(AO_M25_SPI_CS_PORT,cs,AO_M25_SPI_BUS, AO_SPI_SPEED_FAST)
 #define M25_DESELECT(cs)       ao_spi_put_mask(AO_M25_SPI_CS_PORT,cs,AO_M25_SPI_BUS)
 
 #define M25_BLOCK_SHIFT                        16
index 3c1e7a18eb643168be3520e558f0ee6781ce963f..913199232a75b46d2db390ac9e665686626529e0 100644 (file)
@@ -21,8 +21,8 @@ __xdata struct ao_packet_recv ao_rx_packet;
 __xdata struct ao_packet ao_tx_packet;
 __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used;
 
-static __xdata char tx_data[AO_PACKET_MAX];
-static __xdata char rx_data[AO_PACKET_MAX];
+static __xdata uint8_t tx_data[AO_PACKET_MAX];
+static __xdata uint8_t rx_data[AO_PACKET_MAX];
 static __pdata uint8_t rx_seq;
 
 __xdata struct ao_task ao_packet_task;
@@ -169,7 +169,7 @@ ao_packet_putchar(char c) __reentrant
                tx_data[ao_packet_tx_used++] = c;
 }
 
-char
+int
 ao_packet_pollchar(void)
 {
        /* No need to block interrupts, all variables here
index 481232dff2b821b229c29dc4ff6f8baad63f41db..023c788ba86c4be6c0d8d0efcc548f5e8df973e3 100644 (file)
@@ -20,7 +20,7 @@
 static char
 ao_packet_getchar(void)
 {
-       char c;
+       int c;
        while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) {
                if (!ao_packet_enable)
                        break;
@@ -35,7 +35,7 @@ ao_packet_getchar(void)
 static void
 ao_packet_echo(void) __reentrant
 {
-       char    c;
+       int     c;
        while (ao_packet_enable) {
                c = ao_packet_getchar();
                if (c != AO_READ_AGAIN)
index cabe9ee29290cdbf92b765682d422af239d9bcfd..d810cd4cf3c0e47a4c5424926fd9af43ef70adf6 100644 (file)
 #define AO_CC1120_INT_PORT     (&stm_gpioc)
 #define AO_CC1120_INT_PIN      14
 
+#define AO_CC1120_MCU_WAKEUP_PORT      (&stm_gpioc)
+#define AO_CC1120_MCU_WAKEUP_PIN       (0)
+
 #define AO_CC1120_INT_GPIO     2
-#define HAS_BOOT_RADIO         1
+#define AO_CC1120_INT_GPIO_IOCFG       CC1120_IOCFG2
+
+#define AO_CC1120_MARC_GPIO    3
+#define AO_CC1120_MARC_GPIO_IOCFG      CC1120_IOCFG3
 
 /*
  * Profiling Viterbi decoding
index 7d6c7388fa14f8328be8840be9b891ab03fa2323..a5fdcbb28dfbaffc28010b2561c9d07fe08f89a6 100644 (file)
@@ -37,12 +37,12 @@ INC = \
 #PROFILE=ao_profile.c
 #PROFILE_DEF=-DAO_PROFILE=1
 
-SAMPLE_PROFILE=ao_sample_profile.c \
-       ao_sample_profile_timer.c
-SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1
+#SAMPLE_PROFILE=ao_sample_profile.c \
+#      ao_sample_profile_timer.c
+#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1
 
-STACK_GUARD=ao_mpu_stm.c
-STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
+#STACK_GUARD=ao_mpu_stm.c
+#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
 
 ALTOS_SRC = \
        ao_interrupt.c \
@@ -90,6 +90,7 @@ ALTOS_SRC = \
        ao_packet.c \
        ao_companion.c \
        ao_pyro.c \
+       ao_aprs.c \
        $(PROFILE) \
        $(SAMPLE_PROFILE) \
        $(STACK_GUARD)
index cb1eb41756c5fe9ff019f08d753c6e16959d7ccd..fbdab64a8766dbbc8a43d21a8e417da4d93691d1 100644 (file)
@@ -53,7 +53,9 @@ main(void)
        ao_exti_init();
 
        ao_adc_init();
+#if HAS_BEEP
        ao_beep_init();
+#endif
        ao_cmd_init();
 
 #if HAS_MS5607
index 5ae80ac518a61cb61230011a98baee55383082b3..b1a70ea2ed56180ee1922b65a57f67380967aa3a 100644 (file)
@@ -62,6 +62,7 @@
 #define ao_gps_getchar         ao_serial3_getchar
 #define ao_gps_putchar         ao_serial3_putchar
 #define ao_gps_set_speed       ao_serial3_set_speed
+#define ao_gps_fifo            (ao_stm_usart3.rx_fifo)
 
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     0
@@ -69,6 +70,7 @@
 #define HAS_BEEP               1
 #define HAS_RADIO              1
 #define HAS_TELEMETRY          1
+#define HAS_APRS               1
 
 #define HAS_SPI_1              1
 #define SPI_1_PA5_PA6_PA7      1       /* Barometer */
@@ -280,11 +282,19 @@ struct ao_adc {
 #define AO_CC1120_SPI_CS_PIN   5
 #define AO_CC1120_SPI_BUS      AO_SPI_2_PB13_PB14_PB15
 
-#define AO_CC1120_INT_PORT     (&stm_gpioc)
-#define AO_CC1120_INT_PIN      14
+#define AO_CC1120_INT_PORT             (&stm_gpioc)
+#define AO_CC1120_INT_PIN              14
+#define AO_CC1120_MCU_WAKEUP_PORT      (&stm_gpioc)
+#define AO_CC1120_MCU_WAKEUP_PIN       (0)
 
 #define AO_CC1120_INT_GPIO     2
-#define HAS_BOOT_RADIO         1
+#define AO_CC1120_INT_GPIO_IOCFG       CC1120_IOCFG2
+
+#define AO_CC1120_MARC_GPIO    3
+#define AO_CC1120_MARC_GPIO_IOCFG      CC1120_IOCFG3
+
+
+#define HAS_BOOT_RADIO         0
 
 /*
  * Mag sensor (hmc5883)
index e270199ec701aebcc7860b7a5601aa4e8f29ff8e..007f7e2ed3ac85e675244dc547f20dac82cc78e9 100644 (file)
@@ -123,42 +123,6 @@ void ao_lcd_font_init(void);
 
 void ao_lcd_font_string(char *s);
 
-char
-ao_serial1_getchar(void);
-
-void
-ao_serial1_putchar(char c);
-
-char
-ao_serial1_pollchar(void);
-
-void
-ao_serial1_set_speed(uint8_t speed);
-
-char
-ao_serial2_getchar(void);
-
-void
-ao_serial2_putchar(char c);
-
-char
-ao_serial2_pollchar(void);
-
-void
-ao_serial2_set_speed(uint8_t speed);
-
-char
-ao_serial3_getchar(void);
-
-void
-ao_serial3_putchar(char c);
-
-char
-ao_serial3_pollchar(void);
-
-void
-ao_serial3_set_speed(uint8_t speed);
-
 extern const uint32_t  ao_radio_cal;
 
 void
index d6ab1465c73cd1b9a5f0c46080ba1ef780afd1aa..87bbe73e3b926a6b964d181f6dc5a60926cb4305 100644 (file)
@@ -210,6 +210,26 @@ ao_i2c_recv(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop);
 void
 ao_i2c_init(void);
 
+/* ao_serial_stm.c */
+struct ao_stm_usart {
+       struct ao_fifo          rx_fifo;
+       struct ao_fifo          tx_fifo;
+       struct stm_usart        *reg;
+       uint8_t                 tx_started;
+};
+
+#if HAS_SERIAL_1
+extern struct ao_stm_usart     ao_stm_usart1;
+#endif
+
+#if HAS_SERIAL_2
+extern struct ao_stm_usart     ao_stm_usart2;
+#endif
+
+#if HAS_SERIAL_3
+extern struct ao_stm_usart     ao_stm_usart3;
+#endif
+
 #define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
 
 static inline uint32_t
index 00409f4a85957e16e53825f4e8420e85a168c535..ce33f97e97416eaaf2a9eddfb54ba9f19943cb9e 100644 (file)
 
 #include <ao.h>
 
-struct ao_stm_usart {
-       struct ao_fifo          rx_fifo;
-       struct ao_fifo          tx_fifo;
-       struct stm_usart        *reg;
-       uint8_t                 tx_started;
-};
-
 void
 ao_debug_out(char c)
 {
@@ -78,16 +71,19 @@ ao_usart_getchar(struct ao_stm_usart *usart)
        return c;
 }
 
-char
+int
 ao_usart_pollchar(struct ao_stm_usart *usart)
 {
-       char    c;
+       int     c;
        
        ao_arch_block_interrupts();
        if (ao_fifo_empty(usart->rx_fifo))
                c = AO_READ_AGAIN;
-       else
-               ao_fifo_remove(usart->rx_fifo,c);
+       else {
+               uint8_t u;
+               ao_fifo_remove(usart->rx_fifo,u);
+               c = u;
+       }
        ao_arch_release_interrupts();
        return c;
 }
@@ -127,12 +123,15 @@ static const struct {
        [AO_SERIAL_SPEED_57600] = {
                AO_PCLK1 / 57600
        },
+       [AO_SERIAL_SPEED_115200] = {
+               AO_PCLK1 / 115200
+       },
 };
 
 void
 ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed)
 {
-       if (speed > AO_SERIAL_SPEED_57600)
+       if (speed > AO_SERIAL_SPEED_115200)
                return;
        usart->reg->brr = ao_usart_speeds[speed].brr;
 }
@@ -201,7 +200,7 @@ ao_serial1_putchar(char c)
        ao_usart_putchar(&ao_stm_usart1, c);
 }
 
-char
+int
 ao_serial1_pollchar(void)
 {
        return ao_usart_pollchar(&ao_stm_usart1);
@@ -232,7 +231,7 @@ ao_serial2_putchar(char c)
        ao_usart_putchar(&ao_stm_usart2, c);
 }
 
-char
+int
 ao_serial2_pollchar(void)
 {
        return ao_usart_pollchar(&ao_stm_usart2);
@@ -263,7 +262,7 @@ ao_serial3_putchar(char c)
        ao_usart_putchar(&ao_stm_usart3, c);
 }
 
-char
+int
 ao_serial3_pollchar(void)
 {
        return ao_usart_pollchar(&ao_stm_usart3);
index d93a0c174c16a7a851669241fa98fbd68083d2d9..9379e5cd62efd19a8cdf994669fa171be0a9f11b 100644 (file)
@@ -873,10 +873,10 @@ _ao_usb_out_recv(void)
        ao_usb_set_stat_rx(AO_USB_OUT_EPR, STM_USB_EPR_STAT_RX_VALID);
 }
 
-static char
+static int
 _ao_usb_pollchar(void)
 {
-       char c;
+       uint8_t c;
 
        if (!ao_usb_running)
                return AO_READ_AGAIN;
@@ -896,10 +896,10 @@ _ao_usb_pollchar(void)
        return c;
 }
 
-char
+int
 ao_usb_pollchar(void)
 {
-       char    c;
+       int     c;
        ao_arch_block_interrupts();
        c = _ao_usb_pollchar();
        ao_arch_release_interrupts();
@@ -909,7 +909,7 @@ ao_usb_pollchar(void)
 char
 ao_usb_getchar(void)
 {
-       char    c;
+       int     c;
 
        ao_arch_block_interrupts();
        while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
index 3305719a577acf5192a77cf8f4b4c8dd2ad9a0c8..7ba48c96e0bd1d3648d1b6c24e2a68ebfc333ff2 100644 (file)
@@ -43,9 +43,9 @@
        #define PACKET_HAS_SLAVE        1
 
        #define HAS_COMPANION           1
-       #define COMPANION_CS_ON_P1      1
-       #define COMPANION_CS_MASK       0x4     /* CS1 is P1_2 */
-       #define COMPANION_CS            P1_2
+       #define AO_COMPANION_CS_PORT    P1
+       #define AO_COMPANION_CS_PIN     2
+       #define AO_COMPANION_CS         P1_2
 
        #define AO_LED_RED              1
        #define LEDS_AVAILABLE          (AO_LED_RED)
@@ -53,7 +53,7 @@
        #define HAS_ACCEL_REF           1
        #define SPI_CS_ON_P1            1
        #define SPI_CS_ON_P0            0
-       #define M25_CS_MASK             0x02    /* CS0 is P1_1 */
+       #define AO_M25_SPI_CS_MASK      0x02    /* CS0 is P1_1 */
        #define M25_MAX_CHIPS           1
        #define HAS_ACCEL               1
        #define HAS_IGNITE              0
        #define SPI_CS_DIR      P0DIR
 #endif
 
+#define AO_M25_SPI_CS_PORT     SPI_CS_PORT
+
 #ifndef IGNITE_ON_P2
 #error Please define IGNITE_ON_P2
 #endif
 #define AO_IGNITER_FIRE_TIME   AO_MS_TO_TICKS(50)
 #define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000)
 
+struct ao_adc {
+       int16_t         accel;          /* accelerometer */
+       int16_t         pres;           /* pressure sensor */
+       int16_t         temp;           /* temperature sensor */
+       int16_t         v_batt;         /* battery voltage */
+       int16_t         sense_d;        /* drogue continuity sense */
+       int16_t         sense_m;        /* main continuity sense */
+#if HAS_ACCEL_REF
+       uint16_t        accel_ref;      /* acceleration reference */
+#endif
+};
+
 #endif /* _AO_PINS_H_ */
index 3f12a59cda41de833d70d87ce46cc85122d2d448..c8bf7760f89741198753c5bd857b9323b698a9e0 100644 (file)
@@ -26,6 +26,8 @@ ao_ignite_set_pins(void)
        AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT;
 }
 
+__pdata uint16_t ao_motor_number;
+
 void
 main(void)
 {
index 44cee904ab642ee24d386fe37464966e6660a25f..092bf3603b7eaf2e2aa4ba388966089a99f3938a 100644 (file)
@@ -1,7 +1,8 @@
 vpath % ..:../core:../drivers:../util
 
 PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_flight_test_mm \
-       ao_gps_test ao_gps_test_skytraq ao_convert_test ao_convert_pa_test ao_fec_test
+       ao_gps_test ao_gps_test_skytraq ao_convert_test ao_convert_pa_test ao_fec_test \
+       ao_aprs_test
 
 INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h
 
@@ -9,7 +10,7 @@ KALMAN=make-kalman
 
 CFLAGS=-I.. -I. -I../core -I../drivers -O0 -g -Wall
 
-all: $(PROGS)
+all: $(PROGS) ao_aprs_data.wav
 
 clean:
        rm -f $(PROGS) run-out.baro run-out.full
@@ -29,7 +30,7 @@ ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c  ao_sample.c ao_kal
        cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 ao_flight_test.c
 
 ao_flight_test_mm: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS)
-       cc -DMEGAMETRUM=1 $(CFLAGS) -o $@ $<
+       cc -DMEGAMETRUM=1 $(CFLAGS) -o $@ $< -lm
 
 ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h
        cc $(CFLAGS) -o $@ $<
@@ -49,5 +50,14 @@ ao_kalman.h: $(KALMAN)
 ao_fec_test: ao_fec_test.c ao_fec_tx.c ao_fec_rx.c
        cc $(CFLAGS) -DAO_FEC_DEBUG=1 -o $@ ao_fec_test.c ../core/ao_fec_tx.c ../core/ao_fec_rx.c -lm
 
+ao_aprs_test: ao_aprs_test.c ao_aprs.c
+       cc $(CFLAGS) -o $@ ao_aprs_test.c
+
+SOX_INPUT_ARGS=--type raw --encoding unsigned-integer -b 8 -c 1 -r 9600
+SOX_OUTPUT_ARGS=--type wav
+
+ao_aprs_data.wav: ao_aprs_test
+       ./ao_aprs_test | sox $(SOX_INPUT_ARGS) - $(SOX_OUTPUT_ARGS) $@
+
 check: ao_fec_test ao_flight_test ao_flight_test_baro run-tests
        ./ao_fec_test && ./run-tests
\ No newline at end of file
diff --git a/src/test/ao_aprs_test.c b/src/test/ao_aprs_test.c
new file mode 100644 (file)
index 0000000..3b31f2d
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright © 2012 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#include <ao_telemetry.h>
+
+struct ao_telemetry_location ao_gps_data;
+
+#define AO_APRS_TEST
+
+typedef int16_t (*ao_radio_fill_func)(uint8_t *buffer, int16_t len);
+
+#define DEBUG 0
+#if DEBUG
+void
+ao_aprs_bit(uint8_t bit)
+{
+       static int      seq = 0;
+       printf ("%6d %d\n", seq++, bit ? 1 : 0);
+}
+#else
+void
+ao_aprs_bit(uint8_t bit)
+{
+       putchar (bit ? 0xc0 : 0x40);
+}
+#endif
+
+void
+ao_radio_send_lots(ao_radio_fill_func fill);
+
+#include <ao_aprs.c>
+
+/*
+ * @section copyright_sec Copyright
+ *
+ * Copyright (c) 2001-2009 Michael Gray, KD7LMO
+
+
+ *
+ *
+ * @section gpl_sec GNU General Public License
+ *
+ *  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.
+ *
+ *  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
+ *  
+
+ */
+
+static void
+audio_gap(int secs)
+{
+#if !DEBUG
+       int     samples = secs * 9600;
+
+       while (samples--)
+               ao_aprs_bit(0);
+#endif
+}
+
+// This is where we go after reset.
+int main(int argc, char **argv)
+{
+    audio_gap(1);
+
+    ao_gps_data.latitude = (45.0 + 28.25 / 60.0) * 10000000;
+    ao_gps_data.longitude = (-(122 + 44.2649 / 60.0)) * 10000000;
+    ao_gps_data.altitude = 84;
+
+    /* Transmit one packet */
+    ao_aprs_send();
+
+    tncBuffer[strlen((char *) tncBuffer) - 2] = '\0';
+    fprintf(stderr, "packet: %s\n", tncBuffer);
+
+    exit(0);
+}
+
+void
+ao_radio_send_lots(ao_radio_fill_func fill)
+{
+       int16_t len;
+       uint8_t done = 0;
+       uint8_t buf[16], *b, c;
+       uint8_t bit;
+
+       while (!done) {
+               len = (*fill)(buf, sizeof (buf));
+               if (len < 0) {
+                       done = 1;
+                       len = -len;
+               }
+               b = buf;
+               while (len--) {
+                       c = *b++;
+                       for (bit = 0; bit < 8; bit++) {
+                               ao_aprs_bit(c & 0x80);
+                               c <<= 1;
+                       }
+               }
+       }
+}
index 7180f02d2cd4b5dba6ea2df607049e7a71fd404d..cdd1f2369898726ce1739ded988043d6c4924386 100644 (file)
@@ -236,10 +236,14 @@ extern int32_t    ao_accel_scale;
 extern alt_t   ao_ground_height;
 extern alt_t   ao_sample_alt;
 
+double ao_sample_qangle;
+
 int ao_sample_prev_tick;
 uint16_t       prev_tick;
 
+
 #include "ao_kalman.c"
+#include "ao_sqrt.c"
 #include "ao_sample.c"
 #include "ao_flight.c"
 
@@ -309,7 +313,7 @@ ao_mpu6000_accel(int16_t sensor)
 }
 
 static double
-ao_mpu6000_gyro(int16_t sensor)
+ao_mpu6000_gyro(int32_t sensor)
 {
        return sensor / 32767.0 * MPU6000_GYRO_FULLSCALE;
 }
@@ -370,6 +374,7 @@ ao_insert(void)
                if (!ao_summary) {
                        printf("%7.2f height %8.2f accel %8.3f "
 #if MEGAMETRUM
+                              "roll %8.3f angle %8.3f qangle %8.3f "
                               "accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f "
 #endif
                               "state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d\n",
@@ -377,6 +382,9 @@ ao_insert(void)
                               height,
                               accel,
 #if MEGAMETRUM
+                              ao_mpu6000_gyro(ao_sample_roll_angle) / 100.0,
+                              ao_mpu6000_gyro(ao_sample_angle) / 100.0,
+                              ao_sample_qangle,
                               ao_mpu6000_accel(ao_data_static.mpu6000.accel_x),
                               ao_mpu6000_accel(ao_data_static.mpu6000.accel_y),
                               ao_mpu6000_accel(ao_data_static.mpu6000.accel_z),
@@ -547,6 +555,207 @@ int32(uint8_t *bytes, int off)
 
 static int log_format;
 
+#if MEGAMETRUM
+
+static double
+ao_vec_norm(double x, double y, double z)
+{
+       return x*x + y*y + z*z;
+}
+
+static void
+ao_vec_normalize(double *x, double *y, double *z)
+{
+       double  scale = 1/sqrt(ao_vec_norm(*x, *y, *z));
+
+       *x *= scale;
+       *y *= scale;
+       *z *= scale;
+}
+
+struct ao_quat {
+       double  q0, q1, q2, q3;
+};
+
+static void
+ao_quat_mul(struct ao_quat *r, struct ao_quat *a, struct ao_quat *b)
+{
+       r->q0 = a->q0 * b->q0 - a->q1 * b->q1 - a->q2 * b->q2 - a->q3 * b->q3;
+       r->q1 = a->q0 * b->q1 + a->q1 * b->q0 + a->q2 * b->q3 - a->q3 * b->q2;
+       r->q2 = a->q0 * b->q2 - a->q1 * b->q3 + a->q2 * b->q0 + a->q3 * b->q1;
+       r->q3 = a->q0 * b->q3 + a->q1 * b->q2 - a->q2 * b->q1 + a->q3 * b->q0;
+}
+
+#if 0
+static void
+ao_quat_scale(struct ao_quat *r, struct ao_quat *a, double s)
+{
+       r->q0 = a->q0 * s;
+       r->q1 = a->q1 * s;
+       r->q2 = a->q2 * s;
+       r->q3 = a->q3 * s;
+}
+#endif
+
+static void
+ao_quat_conj(struct ao_quat *r, struct ao_quat *a)
+{
+       r->q0 =  a->q0;
+       r->q1 = -a->q1;
+       r->q2 = -a->q2;
+       r->q3 = -a->q3;
+}
+
+static void
+ao_quat_rot(struct ao_quat *r, struct ao_quat *a, struct ao_quat *q)
+{
+       struct ao_quat  t;
+       struct ao_quat  c;
+       ao_quat_mul(&t, q, a);
+       ao_quat_conj(&c, q);
+       ao_quat_mul(r, &t, &c);
+}
+
+static void
+ao_quat_from_angle(struct ao_quat *r,
+                  double x_rad,
+                  double y_rad,
+                  double z_rad)
+{
+       double angle = sqrt (x_rad * x_rad + y_rad * y_rad + z_rad * z_rad);
+       double s = sin(angle/2);
+       double c = cos(angle/2);
+
+       r->q0 = c;
+       r->q1 = x_rad * s / angle;
+       r->q2 = y_rad * s / angle;
+       r->q3 = z_rad * s / angle;
+}
+
+static void
+ao_quat_from_vector(struct ao_quat *r, double x, double y, double z)
+{
+       ao_vec_normalize(&x, &y, &z);
+       double  x_rad = atan2(z, y);
+       double  y_rad = atan2(x, z);
+       double  z_rad = atan2(y, x);
+
+       ao_quat_from_angle(r, x_rad, y_rad, z_rad);
+}
+
+static double
+ao_quat_norm(struct ao_quat *a)
+{
+       return (a->q0 * a->q0 +
+               a->q1 * a->q1 +
+               a->q2 * a->q2 +
+               a->q3 * a->q3);
+}
+
+static void
+ao_quat_normalize(struct ao_quat *a)
+{
+       double  norm = ao_quat_norm(a);
+
+       if (norm) {
+               double m = 1/sqrt(norm);
+
+               a->q0 *= m;
+               a->q1 *= m;
+               a->q2 *= m;
+               a->q3 *= m;
+       }
+}
+
+static struct ao_quat  ao_up, ao_current;
+static struct ao_quat  ao_orient;
+static int             ao_orient_tick;
+
+void
+set_orientation(double x, double y, double z, int tick)
+{
+       struct ao_quat  t;
+
+       printf ("set_orientation %g %g %g\n", x, y, z);
+       ao_quat_from_vector(&ao_orient, x, y, z);
+       ao_up.q1 = ao_up.q2 = 0;
+       ao_up.q0 = ao_up.q3 = sqrt(2)/2;
+       ao_orient_tick = tick;
+
+       ao_orient.q0 = 1;
+       ao_orient.q1 = 0;
+       ao_orient.q2 = 0;
+       ao_orient.q3 = 0;
+
+       printf ("orient (%g) %g %g %g up (%g) %g %g %g\n",
+               ao_orient.q0,
+               ao_orient.q1,
+               ao_orient.q2,
+               ao_orient.q3,
+               ao_up.q0,
+               ao_up.q1,
+               ao_up.q2,
+               ao_up.q3);
+
+       ao_quat_rot(&t, &ao_up, &ao_orient);
+       printf ("pad orient (%g) %g %g %g\n",
+               t.q0,
+               t.q1,
+               t.q2,
+               t.q3);
+
+}
+
+void
+update_orientation (double rate_x, double rate_y, double rate_z, int tick)
+{
+       struct ao_quat  q_dot;
+       double          lambda;
+       double          dt = (tick - ao_orient_tick) / 100.0;
+
+       ao_orient_tick = tick;
+//     lambda = 1 - ao_quat_norm(&ao_orient);
+       lambda = 0;
+
+       q_dot.q0 = -0.5 * (ao_orient.q1 * rate_x + ao_orient.q2 * rate_y + ao_orient.q3 * rate_z) + lambda * ao_orient.q0;
+       q_dot.q1 =  0.5 * (ao_orient.q0 * rate_x + ao_orient.q2 * rate_z - ao_orient.q3 * rate_y) + lambda * ao_orient.q1;
+       q_dot.q2 =  0.5 * (ao_orient.q0 * rate_y + ao_orient.q3 * rate_x - ao_orient.q1 * rate_z) + lambda * ao_orient.q2;
+       q_dot.q3 =  0.5 * (ao_orient.q0 * rate_z + ao_orient.q1 * rate_y - ao_orient.q2 * rate_x) + lambda * ao_orient.q3;
+
+#if 0
+       printf ("update_orientation %g %g %g (%g s)\n", rate_x, rate_y, rate_z, dt);
+       printf ("q_dot (%g) %g %g %g\n",
+               q_dot.q0,
+               q_dot.q1,
+               q_dot.q2,
+               q_dot.q3);
+#endif
+
+       ao_orient.q0 += q_dot.q0 * dt;
+       ao_orient.q1 += q_dot.q1 * dt;
+       ao_orient.q2 += q_dot.q2 * dt;
+       ao_orient.q3 += q_dot.q3 * dt;
+
+       ao_quat_normalize(&ao_orient);
+
+       ao_quat_rot(&ao_current, &ao_up, &ao_orient);
+
+       ao_sample_qangle = 180 / M_PI * acos(ao_current.q3 * sqrt(2));
+#if 0
+       printf ("orient (%g) %g %g %g current (%g) %g %g %g\n",
+               ao_orient.q0,
+               ao_orient.q1,
+               ao_orient.q2,
+               ao_orient.q3,
+               ao_current.q0,
+               ao_current.q1,
+               ao_current.q2,
+               ao_current.q3);
+#endif
+}
+#endif
+
 void
 ao_sleep(void *wchan)
 {
@@ -635,6 +844,21 @@ ao_sleep(void *wchan)
                                                f(gyro_x);
                                                f(gyro_y);
                                                f(gyro_z);
+
+                                               double          accel_x = ao_mpu6000_accel(ao_ground_mpu6000.accel_x);
+                                               double          accel_y = ao_mpu6000_accel(ao_ground_mpu6000.accel_y);
+                                               double          accel_z = ao_mpu6000_accel(ao_ground_mpu6000.accel_z);
+
+                                               /* X and Y are in the ground plane, arbitraryily picked as MPU X and Z axes
+                                                * Z is normal to the ground, the MPU y axis
+                                                */
+                                               set_orientation(accel_x, accel_z, accel_y, tick);
+                                       } else {
+                                               double          rate_x = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_x - ao_ground_mpu6000.gyro_x);
+                                               double          rate_y = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_y - ao_ground_mpu6000.gyro_y);
+                                               double          rate_z = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_z - ao_ground_mpu6000.gyro_z);
+
+                                               update_orientation(rate_x * M_PI / 180, rate_z * M_PI / 180, rate_y * M_PI / 180, tick);
                                        }
                                        ao_records_read++;
                                        ao_insert();
@@ -779,6 +1003,8 @@ ao_sleep(void *wchan)
                                continue;
 
 #if MEGAMETRUM
+                       (void) a;
+                       (void) b;
 #else
                        switch (type) {
                        case 'F':
index d75a12ecbfad77bf5a4f75d65a02a4200fd217f0..3844a3265452f623d5065f48e31b6061cdabe002 100644 (file)
@@ -88,6 +88,7 @@ ao_mutex_put(uint8_t *mutex)
 static int
 ao_gps_fd;
 
+#if 0
 static void
 ao_dbg_char(char c)
 {
@@ -103,6 +104,7 @@ ao_dbg_char(char c)
        }
        write(1, line, strlen(line));
 }
+#endif
 
 #define QUEUE_LEN      4096
 
@@ -391,6 +393,7 @@ ao_serial1_putchar(char c)
 
 #define AO_SERIAL_SPEED_4800   0
 #define AO_SERIAL_SPEED_57600  1
+#define AO_SERIAL_SPEED_115200 2
 
 static void
 ao_serial1_set_speed(uint8_t speed)
@@ -407,6 +410,9 @@ ao_serial1_set_speed(uint8_t speed)
        case AO_SERIAL_SPEED_57600:
                cfsetspeed(&termios, B57600);
                break;
+       case AO_SERIAL_SPEED_115200:
+               cfsetspeed(&termios, B115200);
+               break;
        }
        tcsetattr(fd, TCSAFLUSH, &termios);
        tcflush(fd, TCIFLUSH);
@@ -420,7 +426,6 @@ ao_serial1_set_speed(uint8_t speed)
 void
 ao_dump_state(void *wchan)
 {
-       double  lat, lon;
        int     i;
        if (wchan == &ao_gps_data)
                ao_gps_print(&ao_gps_data);
@@ -510,4 +515,5 @@ main (int argc, char **argv)
        }
        ao_gps_setup();
        ao_gps();
+       return 0;
 }
index 846daa9443825b02fc322b9ca1d6f9fe5b806d36..81008b39ebc282e6aa4682779691d6e2580528b2 100644 (file)
@@ -397,6 +397,7 @@ ao_serial1_putchar(char c)
 #define AO_SERIAL_SPEED_4800   0
 #define AO_SERIAL_SPEED_9600   1
 #define AO_SERIAL_SPEED_57600  2
+#define AO_SERIAL_SPEED_115200 3
 
 static void
 ao_serial1_set_speed(uint8_t speed)
@@ -411,11 +412,14 @@ ao_serial1_set_speed(uint8_t speed)
                cfsetspeed(&termios, B4800);
                break;
        case AO_SERIAL_SPEED_9600:
-               cfsetspeed(&termios, B38400);
+               cfsetspeed(&termios, B9600);
                break;
        case AO_SERIAL_SPEED_57600:
                cfsetspeed(&termios, B57600);
                break;
+       case AO_SERIAL_SPEED_115200:
+               cfsetspeed(&termios, B115200);
+               break;
        }
        tcsetattr(fd, TCSAFLUSH, &termios);
        tcflush(fd, TCIFLUSH);
@@ -423,6 +427,10 @@ ao_serial1_set_speed(uint8_t speed)
 
 #define ao_time() 0
 
+uint8_t        ao_task_minimize_latency;
+
+#define ao_usb_getchar()       0
+
 #include "ao_gps_print.c"
 #include "ao_gps_skytraq.c"