/* 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;
+
+ /* 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)) {
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;
return r;
}
-
+
public int compare_version(String other) {
int[] me = parse_version(version);
int[] them = parse_version(other);
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;
+ 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) {}
+ }
+
+ /* 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;
}
}
+ 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();
+ }
+
+ 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);
+ }
+
+ 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());
+ }
+ }
+
+ 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;
+ }
+ }
+
}
\ No newline at end of file
--- /dev/null
+/*
+ * 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();
+}
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;
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();
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();
AltosLib_JAVA = \
$(SRC)/AltosLib.java \
$(SRC)/AltosConfigData.java \
+ $(SRC)/AltosConfigValues.java \
$(SRC)/AltosConvert.java \
$(SRC)/AltosCRCException.java \
$(SRC)/AltosEepromChunk.java \
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)
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;
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;
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();
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 {
}
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);
}
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 {
public class AltosConfigUI
extends AltosDialog
- implements ActionListener, ItemListener, DocumentListener
+ implements ActionListener, ItemListener, DocumentListener, AltosConfigValues
{
Container pane;
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() {
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() {
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);
}
-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
--- /dev/null
+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
--- /dev/null
+.\"
+.\" 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+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
--- /dev/null
+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
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
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
])
build-stamp: configure-stamp
dh_testdir
- $(MAKE) VERSION=$(PKG_VERSION)
+ $(MAKE)
(cd doc ; $(MAKE))
touch $@
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)
return c;
}
-char
+int
ao_usb_pollchar(void)
{
- char c;
+ int c;
cli();
c = _ao_usb_pollchar();
sei();
char
ao_usb_getchar(void) __critical
{
- char c;
+ int c;
cli();
while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
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) {
#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
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)
{
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);
/* .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;
}
#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);
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;
}
#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);
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;
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;
char
ao_usb_getchar(void) __critical
{
- char c;
+ int c;
while ((c = ao_usb_pollchar()) == AO_READ_AGAIN)
ao_sleep(&ao_stdin_ready);
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);
* 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;
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;
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)
{
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
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 },
{ "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 },
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();
void
ao_packet_putchar(char c) __reentrant;
-char
+int
ao_packet_pollchar(void);
#if PACKET_HAS_MASTER
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)
{
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;
#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;
char
ao_serial0_getchar(void);
+int
+ao_serial0_pollchar(void);
+
void
ao_serial0_putchar(char c);
char
ao_serial1_getchar(void);
-char
+int
ao_serial1_pollchar(void);
void
char
ao_serial2_getchar(void);
-char
+int
ao_serial2_pollchar(void);
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);
char
getchar(void) __reentrant
{
- char c;
+ int c;
ao_arch_critical(
int8_t stdio = ao_cur_stdio;
}
int8_t
-ao_add_stdio(char (*pollchar)(void),
+ao_add_stdio(int (*pollchar)(void),
void (*putchar)(char),
void (*flush)(void)) __reentrant
{
);
}
+__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
}
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;
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();
}
}
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
/* 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 */
ao_btm_get_line(void)
{
uint8_t ao_btm_reply_len = 0;
- char c;
+ int c;
for (;;) {
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");
#ifndef ao_gps_getchar
#define ao_gps_getchar ao_serial1_getchar
+#define ao_gps_fifo ao_serial1_rx_fifo
#endif
#ifndef ao_gps_putchar
}
}
+static uint8_t ao_gps_updating;
+
void
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
}
}
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 },
};
__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;
tx_data[ao_packet_tx_used++] = c;
}
-char
+int
ao_packet_pollchar(void)
{
/* No need to block interrupts, all variables here
static char
ao_packet_getchar(void)
{
- char c;
+ int c;
while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) {
if (!ao_packet_enable)
break;
static void
ao_packet_echo(void) __reentrant
{
- char c;
+ int c;
while (ao_packet_enable) {
c = ao_packet_getchar();
if (c != AO_READ_AGAIN)
#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
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
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
#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)
{
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;
}
[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;
}
ao_usart_putchar(&ao_stm_usart1, c);
}
-char
+int
ao_serial1_pollchar(void)
{
return ao_usart_pollchar(&ao_stm_usart1);
ao_usart_putchar(&ao_stm_usart2, c);
}
-char
+int
ao_serial2_pollchar(void)
{
return ao_usart_pollchar(&ao_stm_usart2);
ao_usart_putchar(&ao_stm_usart3, c);
}
-char
+int
ao_serial3_pollchar(void)
{
return ao_usart_pollchar(&ao_stm_usart3);
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;
return c;
}
-char
+int
ao_usb_pollchar(void)
{
- char c;
+ int c;
ao_arch_block_interrupts();
c = _ao_usb_pollchar();
ao_arch_release_interrupts();
char
ao_usb_getchar(void)
{
- char c;
+ int c;
ao_arch_block_interrupts();
while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
#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)
#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_ */
AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT;
}
+__pdata uint16_t ao_motor_number;
+
void
main(void)
{
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 $@ $<
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;
+
+ 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);
+
+ 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);
+
+ 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
+
void
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, rate_z, rate_y, tick);
}
ao_records_read++;
ao_insert();
continue;
#if MEGAMETRUM
+ (void) a;
+ (void) b;
#else
switch (type) {
case 'F':
static int
ao_gps_fd;
+#if 0
static void
ao_dbg_char(char c)
{
}
write(1, line, strlen(line));
}
+#endif
#define QUEUE_LEN 4096
#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)
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);
void
ao_dump_state(void *wchan)
{
- double lat, lon;
int i;
if (wchan == &ao_gps_data)
ao_gps_print(&ao_gps_data);
}
ao_gps_setup();
ao_gps();
+ return 0;
}
#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)
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);
#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"