summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--altosui/Altos.java2
-rw-r--r--altosui/AltosBTDevice.java7
-rw-r--r--altosui/AltosCSVUI.java2
-rw-r--r--altosui/AltosConfig.java3
-rw-r--r--altosui/AltosConfigureUI.java33
-rw-r--r--altosui/AltosDataChooser.java2
-rw-r--r--altosui/AltosDevice.java1
-rw-r--r--altosui/AltosDeviceDialog.java36
-rw-r--r--altosui/AltosEepromDownload.java12
-rw-r--r--altosui/AltosEepromManage.java3
-rw-r--r--altosui/AltosFlashUI.java4
-rw-r--r--altosui/AltosIgniteUI.java3
-rw-r--r--altosui/AltosLanded.java4
-rw-r--r--altosui/AltosLaunch.java201
-rw-r--r--altosui/AltosLaunchUI.java517
-rw-r--r--altosui/AltosPreferences.java39
-rw-r--r--altosui/AltosScanUI.java6
-rw-r--r--altosui/AltosSerial.java4
-rw-r--r--altosui/AltosUI.java20
-rw-r--r--altosui/AltosUSBDevice.java7
-rw-r--r--altosui/Makefile.am5
-rw-r--r--altosui/libaltos/libaltos.c175
-rw-r--r--altosui/libaltos/libaltos.h13
-rw-r--r--configure.ac4
-rw-r--r--src/Makefile28
-rw-r--r--src/Makefile.proto380
-rw-r--r--src/ao_aes.c142
-rw-r--r--src/ao_radio_cmac.c406
-rw-r--r--src/ao_telelaunch.c (renamed from src/ao_main.c)21
-rw-r--r--src/avr-demo/Makefile105
-rw-r--r--src/avr-demo/ao_demo.c52
-rw-r--r--src/avr/ao_adc_avr.c168
-rw-r--r--src/avr/ao_arch.h158
-rw-r--r--src/avr/ao_avr_stdio.c52
-rw-r--r--src/avr/ao_clock.c77
-rw-r--r--src/avr/ao_debug_avr.c78
-rw-r--r--src/avr/ao_led.c67
-rw-r--r--src/avr/ao_pins.h88
-rw-r--r--src/avr/ao_romconfig.c (renamed from src/ao_log_telem.c)12
-rw-r--r--src/avr/ao_serial_avr.c166
-rw-r--r--src/avr/ao_spi_slave.c115
-rw-r--r--src/avr/ao_spi_usart.c112
-rw-r--r--src/avr/ao_timer.c89
-rw-r--r--src/avr/ao_usb.h (renamed from src/ao_usb.h)0
-rw-r--r--src/avr/ao_usb_avr.c688
-rw-r--r--src/cc1111/Makefile.cc111127
-rw-r--r--src/cc1111/_bp.c (renamed from src/_bp.c)0
-rw-r--r--src/cc1111/ao_adc.c (renamed from src/ao_adc.c)4
-rw-r--r--src/cc1111/ao_arch.h207
-rw-r--r--src/cc1111/ao_beep.c (renamed from src/ao_beep.c)0
-rw-r--r--src/cc1111/ao_dbg.c (renamed from src/ao_dbg.c)0
-rw-r--r--src/cc1111/ao_dma.c (renamed from src/ao_dma.c)0
-rw-r--r--src/cc1111/ao_ignite.c (renamed from src/ao_ignite.c)28
-rw-r--r--src/cc1111/ao_intflash.c (renamed from src/ao_intflash.c)0
-rw-r--r--src/cc1111/ao_launch.c209
-rw-r--r--src/cc1111/ao_led.c (renamed from src/ao_led.c)0
-rw-r--r--src/cc1111/ao_packet.c (renamed from src/ao_packet.c)0
-rw-r--r--src/cc1111/ao_packet_master.c (renamed from src/ao_packet_master.c)6
-rw-r--r--src/cc1111/ao_packet_slave.c (renamed from src/ao_packet_slave.c)0
-rw-r--r--src/cc1111/ao_pins.h (renamed from src/ao_pins.h)106
-rw-r--r--src/cc1111/ao_radio.c (renamed from src/ao_radio.c)14
-rw-r--r--src/cc1111/ao_reboot.c (renamed from src/ao_reboot.c)0
-rw-r--r--src/cc1111/ao_romconfig.c (renamed from src/ao_romconfig.c)0
-rw-r--r--src/cc1111/ao_serial.c (renamed from src/ao_serial.c)0
-rw-r--r--src/cc1111/ao_spi.c (renamed from src/ao_spi.c)0
-rw-r--r--src/cc1111/ao_timer.c (renamed from src/ao_timer.c)1
-rw-r--r--src/cc1111/ao_usb.c (renamed from src/ao_usb.c)0
-rw-r--r--src/cc1111/ao_usb.h100
-rw-r--r--src/cc1111/cc1111.h (renamed from src/cc1111.h)24
-rw-r--r--src/core/altitude.h (renamed from src/altitude.h)0
-rw-r--r--src/core/ao.h (renamed from src/ao.h)350
-rw-r--r--src/core/ao_cmd.c (renamed from src/ao_cmd.c)60
-rw-r--r--src/core/ao_config.c (renamed from src/ao_config.c)44
-rw-r--r--src/core/ao_convert.c (renamed from src/ao_convert.c)0
-rw-r--r--src/core/ao_convert_test.c (renamed from src/ao_convert_test.c)0
-rw-r--r--src/core/ao_ee_fake.c (renamed from src/ao_ee_fake.c)0
-rw-r--r--src/core/ao_flight.c (renamed from src/ao_flight.c)19
-rw-r--r--src/core/ao_flight_nano.c (renamed from src/ao_flight_nano.c)0
-rw-r--r--src/core/ao_gps_print.c (renamed from src/ao_gps_print.c)0
-rw-r--r--src/core/ao_gps_report.c (renamed from src/ao_gps_report.c)0
-rw-r--r--src/core/ao_host.h (renamed from src/ao_host.h)0
-rw-r--r--src/core/ao_kalman.c (renamed from src/ao_kalman.c)0
-rw-r--r--src/core/ao_log.c (renamed from src/ao_log.c)0
-rw-r--r--src/core/ao_log_big.c (renamed from src/ao_log_big.c)0
-rw-r--r--src/core/ao_log_single.c198
-rw-r--r--src/core/ao_log_telem.c127
-rw-r--r--src/core/ao_log_telescience.c117
-rw-r--r--src/core/ao_log_tiny.c (renamed from src/ao_log_tiny.c)0
-rw-r--r--src/core/ao_monitor.c (renamed from src/ao_monitor.c)39
-rw-r--r--src/core/ao_mutex.c (renamed from src/ao_mutex.c)0
-rw-r--r--src/core/ao_panic.c (renamed from src/ao_panic.c)9
-rw-r--r--src/core/ao_product.c (renamed from src/ao_product.c)0
-rw-r--r--src/core/ao_report.c (renamed from src/ao_report.c)24
-rw-r--r--src/core/ao_rssi.c (renamed from src/ao_rssi.c)0
-rw-r--r--src/core/ao_sample.c (renamed from src/ao_sample.c)0
-rw-r--r--src/core/ao_state.c (renamed from src/ao_state.c)0
-rw-r--r--src/core/ao_stdio.c (renamed from src/ao_stdio.c)0
-rw-r--r--src/core/ao_storage.c (renamed from src/ao_storage.c)0
-rw-r--r--src/core/ao_task.c (renamed from src/ao_task.c)164
-rw-r--r--src/core/ao_telem.h (renamed from src/ao_telem.h)0
-rw-r--r--src/core/ao_telemetry.c (renamed from src/ao_telemetry.c)31
-rw-r--r--src/drivers/ao_25lc1024.c (renamed from src/ao_ee.c)2
-rw-r--r--src/drivers/ao_25lc1024.h (renamed from src/25lc1024.h)0
-rw-r--r--src/drivers/ao_at45db161d.c (renamed from src/ao_flash.c)2
-rw-r--r--src/drivers/ao_at45db161d.h (renamed from src/at45db161d.h)0
-rw-r--r--src/drivers/ao_btm.c (renamed from src/ao_btm.c)88
-rw-r--r--src/drivers/ao_companion.c (renamed from src/ao_companion.c)2
-rw-r--r--src/drivers/ao_gps_sirf.c (renamed from src/ao_gps_sirf.c)0
-rw-r--r--src/drivers/ao_gps_skytraq.c (renamed from src/ao_gps_skytraq.c)0
-rw-r--r--src/drivers/ao_lcd.c281
-rw-r--r--src/drivers/ao_m25.c (renamed from src/ao_m25.c)2
-rw-r--r--src/drivers/ao_pyro_slave.c51
-rw-r--r--src/drivers/ao_science_slave.c62
-rw-r--r--src/product/Makefile.telebt98
-rw-r--r--src/product/Makefile.teledongle98
-rw-r--r--src/product/Makefile.telelaunch101
-rw-r--r--src/product/Makefile.telemetrum111
-rw-r--r--src/product/Makefile.telemini100
-rw-r--r--src/product/Makefile.telenano99
-rw-r--r--src/product/ao_telebt.c (renamed from src/ao_telebt.c)13
-rw-r--r--src/product/ao_teledongle.c (renamed from src/ao_teledongle.c)2
-rw-r--r--src/product/ao_telemetrum.c (renamed from src/ao_telemetrum.c)0
-rw-r--r--src/product/ao_telemini.c (renamed from src/ao_telemini.c)0
-rw-r--r--src/product/ao_telenano.c (renamed from src/ao_telenano.c)0
-rw-r--r--src/product/ao_telepyro.c (renamed from src/ao_adc_fake.c)23
-rw-r--r--src/product/ao_telescience.c39
-rw-r--r--src/product/ao_teleterra.c (renamed from src/ao_teleterra.c)0
-rw-r--r--src/product/ao_test.c (renamed from src/ao_test.c)0
-rw-r--r--src/product/ao_tidongle.c (renamed from src/ao_tidongle.c)2
-rw-r--r--src/telebt-v0.0/Makefile10
-rw-r--r--src/telebt-v0.0/Makefile.defs8
-rw-r--r--src/telebt-v0.1/Makefile22
-rw-r--r--src/telebt-v0.1/Makefile.defs8
-rw-r--r--src/teledongle-v0.1/.sdcdbrc1
-rw-r--r--src/teledongle-v0.1/Makefile9
-rw-r--r--src/teledongle-v0.1/Makefile.defs9
-rw-r--r--src/teledongle-v0.2/Makefile9
-rw-r--r--src/teledongle-v0.2/Makefile.defs9
-rw-r--r--src/telelaunch-v0.1/.gitignore2
-rw-r--r--src/telelaunch-v0.1/.sdcdbrc1
-rw-r--r--src/telelaunch-v0.1/Makefile4
-rw-r--r--src/telelaunch-v0.1/Makefile.defs14
-rw-r--r--src/telemetrum-v0.1-sirf/Makefile17
-rw-r--r--src/telemetrum-v0.1-sirf/Makefile.defs12
-rw-r--r--src/telemetrum-v0.1-sky/Makefile17
-rw-r--r--src/telemetrum-v0.1-sky/Makefile.defs12
-rw-r--r--src/telemetrum-v1.0/Makefile17
-rw-r--r--src/telemetrum-v1.0/Makefile.defs13
-rw-r--r--src/telemetrum-v1.1/Makefile17
-rw-r--r--src/telemetrum-v1.1/Makefile.defs13
-rw-r--r--src/telemini-v1.0/Makefile9
-rw-r--r--src/telemini-v1.0/Makefile.defs9
-rw-r--r--src/telenano-v0.1/Makefile10
-rw-r--r--src/telenano-v0.1/Makefile.defs9
-rw-r--r--src/telepyro-v0.1/Makefile101
-rw-r--r--src/telescience-v0.1/Makefile112
-rw-r--r--src/test/Makefile20
-rw-r--r--src/test/ao_flight_test.c (renamed from src/ao_flight_test.c)0
-rw-r--r--src/test/ao_gps_test.c (renamed from src/ao_gps_test.c)0
-rw-r--r--src/test/ao_gps_test_skytraq.c (renamed from src/ao_gps_test_skytraq.c)0
-rw-r--r--src/tidongle/Makefile95
-rw-r--r--src/tidongle/Makefile.defs9
-rw-r--r--src/util/ao-make-product.5c (renamed from src/ao-make-product.5c)0
-rw-r--r--src/util/check-avr-mem9
-rwxr-xr-xsrc/util/check-stack (renamed from src/check-stack)0
-rwxr-xr-xsrc/util/gps-cksum (renamed from src/gps-cksum)0
-rw-r--r--src/util/make-altitude (renamed from src/make-altitude)0
-rw-r--r--src/util/make-kalman (renamed from src/make-kalman)4
-rwxr-xr-xsrc/util/sirf-cksum (renamed from src/sirf-cksum)0
-rw-r--r--src/util/skytraq-cksum (renamed from src/skytraq-cksum)0
170 files changed, 6860 insertions, 942 deletions
diff --git a/altosui/Altos.java b/altosui/Altos.java
index e4f974f9..aa2fd77a 100644
--- a/altosui/Altos.java
+++ b/altosui/Altos.java
@@ -498,5 +498,5 @@ public class Altos {
public final static String bt_product_telebt = bt_product_telebt();
-// public static AltosBTKnown bt_known = new AltosBTKnown();
+ public static AltosBTKnown bt_known = new AltosBTKnown();
}
diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java
index 7a876c25..55b8f8fc 100644
--- a/altosui/AltosBTDevice.java
+++ b/altosui/AltosBTDevice.java
@@ -42,6 +42,13 @@ public class AltosBTDevice extends altos_bt_device implements AltosDevice {
return getAddr();
}
+ public String getErrorString() {
+ altos_error error = new altos_error();
+
+ libaltos.altos_get_last_error(error);
+ return String.format("%s (%d)", error.getString(), error.getCode());
+ }
+
public int getSerial() {
String name = getName();
if (name == null)
diff --git a/altosui/AltosCSVUI.java b/altosui/AltosCSVUI.java
index e1b6002d..a212409e 100644
--- a/altosui/AltosCSVUI.java
+++ b/altosui/AltosCSVUI.java
@@ -99,7 +99,7 @@ public class AltosCSVUI
writer.close();
} catch (FileNotFoundException ee) {
JOptionPane.showMessageDialog(frame,
- file.getName(),
+ ee.getMessage(),
"Cannot open file",
JOptionPane.ERROR_MESSAGE);
}
diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java
index 122ebecc..93def70d 100644
--- a/altosui/AltosConfig.java
+++ b/altosui/AltosConfig.java
@@ -480,8 +480,7 @@ public class AltosConfig implements ActionListener {
}
} catch (FileNotFoundException ee) {
JOptionPane.showMessageDialog(owner,
- String.format("Cannot open device \"%s\"",
- device.toShortString()),
+ ee.getMessage(),
"Cannot open target device",
JOptionPane.ERROR_MESSAGE);
} catch (AltosSerialInUseException si) {
diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java
index bcb9636b..980068c0 100644
--- a/altosui/AltosConfigureUI.java
+++ b/altosui/AltosConfigureUI.java
@@ -52,8 +52,7 @@ public class AltosConfigureUI
JRadioButton serial_debug;
-// BLUETOOTH
-// JButton manage_bluetooth;
+ JButton manage_bluetooth;
JButton manage_frequencies;
final static String[] font_size_names = { "Small", "Medium", "Large" };
@@ -241,19 +240,18 @@ public class AltosConfigureUI
c.anchor = GridBagConstraints.WEST;
pane.add(serial_debug, c);
-// BLUETOOTH
-// manage_bluetooth = new JButton("Manage Bluetooth");
-// manage_bluetooth.addActionListener(new ActionListener() {
-// public void actionPerformed(ActionEvent e) {
-// AltosBTManage.show(owner, Altos.bt_known);
-// }
-// });
-// c.gridx = 0;
-// c.gridy = row++;
-// c.gridwidth = 2;
-// c.fill = GridBagConstraints.NONE;
-// c.anchor = GridBagConstraints.WEST;
-// pane.add(manage_bluetooth, c);
+ manage_bluetooth = new JButton("Manage Bluetooth");
+ manage_bluetooth.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ AltosBTManage.show(owner, Altos.bt_known);
+ }
+ });
+ c.gridx = 0;
+ c.gridy = row;
+ c.gridwidth = 2;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.WEST;
+ pane.add(manage_bluetooth, c);
manage_frequencies = new JButton("Manage Frequencies");
manage_frequencies.addActionListener(new ActionListener() {
@@ -262,9 +260,8 @@ public class AltosConfigureUI
}
});
manage_frequencies.setToolTipText("Configure which values are shown in frequency menus");
-// BLUETOOTH
-// c.gridx = 2;
- c.gridx = 1;
+ c.gridx = 2;
+ c.gridx = 2;
c.gridy = row++;
c.gridwidth = 2;
c.fill = GridBagConstraints.NONE;
diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java
index 15de05c2..d81ca6d1 100644
--- a/altosui/AltosDataChooser.java
+++ b/altosui/AltosDataChooser.java
@@ -61,7 +61,7 @@ public class AltosDataChooser extends JFileChooser {
}
} catch (FileNotFoundException fe) {
JOptionPane.showMessageDialog(frame,
- filename,
+ fe.getMessage(),
"Cannot open file",
JOptionPane.ERROR_MESSAGE);
}
diff --git a/altosui/AltosDevice.java b/altosui/AltosDevice.java
index 3357c550..1b5c1a91 100644
--- a/altosui/AltosDevice.java
+++ b/altosui/AltosDevice.java
@@ -26,5 +26,6 @@ public interface AltosDevice {
public abstract int getSerial();
public abstract String getPath();
public abstract boolean matchProduct(int product);
+ public abstract String getErrorString();
public SWIGTYPE_p_altos_file open();
}
diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java
index fa9587bc..610bb73e 100644
--- a/altosui/AltosDeviceDialog.java
+++ b/altosui/AltosDeviceDialog.java
@@ -30,8 +30,7 @@ public class AltosDeviceDialog extends JDialog implements ActionListener {
private JList list;
private JButton cancel_button;
private JButton select_button;
-// BLUETOOTH
-// private JButton manage_bluetooth_button;
+ private JButton manage_bluetooth_button;
private Frame frame;
private int product;
@@ -42,17 +41,15 @@ public class AltosDeviceDialog extends JDialog implements ActionListener {
private AltosDevice[] devices() {
java.util.List<AltosDevice> usb_devices = AltosUSBDevice.list(product);
int num_devices = usb_devices.size();
-// BLUETOOTH
-// java.util.List<AltosDevice> bt_devices = Altos.bt_known.list(product);
-// num_devices += bt_devices.size();
+ java.util.List<AltosDevice> bt_devices = Altos.bt_known.list(product);
+ num_devices += bt_devices.size();
AltosDevice[] devices = new AltosDevice[num_devices];
for (int i = 0; i < usb_devices.size(); i++)
devices[i] = usb_devices.get(i);
-// BLUETOOTH
-// int off = usb_devices.size();
-// for (int j = 0; j < bt_devices.size(); j++)
-// devices[off + j] = bt_devices.get(j);
+ int off = usb_devices.size();
+ for (int j = 0; j < bt_devices.size(); j++)
+ devices[off + j] = bt_devices.get(j);
return devices;
}
@@ -75,10 +72,9 @@ public class AltosDeviceDialog extends JDialog implements ActionListener {
cancel_button.setActionCommand("cancel");
cancel_button.addActionListener(this);
-// BLUETOOTH
-// manage_bluetooth_button = new JButton("Manage Bluetooth");
-// manage_bluetooth_button.setActionCommand("manage");
-// manage_bluetooth_button.addActionListener(this);
+ manage_bluetooth_button = new JButton("Manage Bluetooth");
+ manage_bluetooth_button.setActionCommand("manage");
+ manage_bluetooth_button.addActionListener(this);
select_button = new JButton("Select");
select_button.setActionCommand("select");
@@ -152,8 +148,7 @@ public class AltosDeviceDialog extends JDialog implements ActionListener {
buttonPane.add(Box.createHorizontalGlue());
buttonPane.add(cancel_button);
buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
-// BLUETOOTH
-// buttonPane.add(manage_bluetooth_button);
+ buttonPane.add(manage_bluetooth_button);
buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
buttonPane.add(select_button);
@@ -173,12 +168,11 @@ public class AltosDeviceDialog extends JDialog implements ActionListener {
public void actionPerformed(ActionEvent e) {
if ("select".equals(e.getActionCommand()))
value = (AltosDevice)(list.getSelectedValue());
-// BLUETOOTH
-// if ("manage".equals(e.getActionCommand())) {
-// AltosBTManage.show(frame, Altos.bt_known);
-// update_devices();
-// return;
-// }
+ if ("manage".equals(e.getActionCommand())) {
+ AltosBTManage.show(frame, Altos.bt_known);
+ update_devices();
+ return;
+ }
setVisible(false);
}
diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java
index 358ad337..e7e52466 100644
--- a/altosui/AltosEepromDownload.java
+++ b/altosui/AltosEepromDownload.java
@@ -248,6 +248,10 @@ public class AltosEepromDownload implements Runnable {
done = true;
}
+ void CaptureTelemetry(AltosEepromChunk eechunk) throws IOException {
+
+ }
+
void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException {
int block, state_block = 0;
int log_format = flights.config_data.log_format;
@@ -300,10 +304,10 @@ public class AltosEepromDownload implements Runnable {
extension = "eeprom";
CaptureTiny(eechunk);
break;
-// case Altos.AO_LOG_FORMAT_TELEMETRY:
-// extension = "telem";
-// CaptureTelemetry(eechunk);
-// break;
+ case Altos.AO_LOG_FORMAT_TELEMETRY:
+ extension = "telem";
+ CaptureTelemetry(eechunk);
+ break;
case Altos.AO_LOG_FORMAT_TELESCIENCE:
extension = "science";
CaptureTeleScience(eechunk);
diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java
index 2e520628..083c7372 100644
--- a/altosui/AltosEepromManage.java
+++ b/altosui/AltosEepromManage.java
@@ -219,8 +219,7 @@ public class AltosEepromManage implements ActionListener {
t.start();
} catch (FileNotFoundException ee) {
JOptionPane.showMessageDialog(frame,
- String.format("Cannot open device \"%s\"",
- device.toShortString()),
+ ee.getMessage(),
"Cannot open target device",
JOptionPane.ERROR_MESSAGE);
} catch (AltosSerialInUseException si) {
diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java
index 3874b500..3956ff20 100644
--- a/altosui/AltosFlashUI.java
+++ b/altosui/AltosFlashUI.java
@@ -200,8 +200,8 @@ public class AltosFlashUI
void exception (Exception e) {
if (e instanceof FileNotFoundException) {
JOptionPane.showMessageDialog(frame,
- "Cannot open image",
- file.toString(),
+ ((FileNotFoundException) e).getMessage(),
+ "Cannot open file",
JOptionPane.ERROR_MESSAGE);
} else if (e instanceof AltosSerialInUseException) {
JOptionPane.showMessageDialog(frame,
diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java
index c11a8614..b215c228 100644
--- a/altosui/AltosIgniteUI.java
+++ b/altosui/AltosIgniteUI.java
@@ -122,8 +122,7 @@ public class AltosIgniteUI
void ignite_exception(Exception e) {
if (e instanceof FileNotFoundException) {
JOptionPane.showMessageDialog(owner,
- String.format("Cannot open device \"%s\"",
- device.toShortString()),
+ ((FileNotFoundException) e).getMessage(),
"Cannot open target device",
JOptionPane.ERROR_MESSAGE);
} else if (e instanceof AltosSerialInUseException) {
diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java
index 50e6b542..4dd9a2dd 100644
--- a/altosui/AltosLanded.java
+++ b/altosui/AltosLanded.java
@@ -250,7 +250,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio
FileInputStream in = new FileInputStream(file);
records = new AltosTelemetryIterable(in);
} else {
- throw new FileNotFoundException();
+ throw new FileNotFoundException(filename);
}
try {
new AltosGraphUI(records, filename);
@@ -259,7 +259,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio
}
} catch (FileNotFoundException fe) {
JOptionPane.showMessageDialog(null,
- filename,
+ fe.getMessage(),
"Cannot open file",
JOptionPane.ERROR_MESSAGE);
}
diff --git a/altosui/AltosLaunch.java b/altosui/AltosLaunch.java
new file mode 100644
index 00000000..77f681b8
--- /dev/null
+++ b/altosui/AltosLaunch.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright © 2010 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 altosui;
+
+import java.io.*;
+import java.util.concurrent.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import javax.swing.event.*;
+
+public class AltosLaunch {
+ AltosDevice device;
+ AltosSerial serial;
+ boolean serial_started;
+ int launcher_serial;
+ int launcher_channel;
+ int rssi;
+
+ final static int Unknown = -1;
+ final static int Good = 0;
+ final static int Bad = 1;
+
+ int armed;
+ int igniter;
+
+ private void start_serial() throws InterruptedException {
+ serial_started = true;
+ }
+
+ private void stop_serial() throws InterruptedException {
+ if (!serial_started)
+ return;
+ serial_started = false;
+ if (serial == null)
+ return;
+ }
+
+ class string_ref {
+ String value;
+
+ public String get() {
+ return value;
+ }
+ public void set(String i) {
+ value = i;
+ }
+ public string_ref() {
+ value = null;
+ }
+ }
+
+ private 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;
+ }
+ }
+
+ public boolean status() throws InterruptedException, TimeoutException {
+ boolean ok = false;
+ if (serial == null)
+ return false;
+ string_ref status_name = new string_ref();
+ start_serial();
+ serial.printf("l %d %d\n", launcher_serial, launcher_channel);
+ for (;;) {
+ String line = serial.get_reply(20000);
+ if (line == null)
+ throw new TimeoutException();
+ if (get_string(line, "Rssi: ", status_name)) {
+ try {
+ rssi = Altos.fromdec(status_name.get());
+ } catch (NumberFormatException ne) {
+ }
+ break;
+ } else if (get_string(line, "Armed: ", status_name)) {
+ armed = Good;
+ String status = status_name.get();
+ if (status.startsWith("igniter good"))
+ igniter = Good;
+ else if (status.startsWith("igniter bad"))
+ igniter = Bad;
+ else
+ igniter = Unknown;
+ ok = true;
+ } else if (get_string(line, "Disarmed: ", status_name)) {
+ armed = Bad;
+ if (status_name.get().startsWith("igniter good"))
+ igniter = Good;
+ else if (status_name.get().startsWith("igniter bad"))
+ igniter = Bad;
+ else
+ igniter = Unknown;
+ ok = true;
+ } else if (get_string(line, "Error ", status_name)) {
+ armed = Unknown;
+ igniter = Unknown;
+ ok = false;
+ break;
+ }
+ }
+ stop_serial();
+ if (!ok) {
+ armed = Unknown;
+ igniter = Unknown;
+ }
+ return ok;
+ }
+
+ public static String status_string(int status) {
+ switch (status) {
+ case Good:
+ return "good";
+ case Bad:
+ return "open";
+ }
+ return "unknown";
+ }
+
+ public void arm() {
+ if (serial == null)
+ return;
+ try {
+ start_serial();
+ serial.printf("a %d %d\n", launcher_serial, launcher_channel);
+ serial.flush_output();
+ } catch (InterruptedException ie) {
+ } finally {
+ try {
+ stop_serial();
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ public void fire() {
+ if (serial == null)
+ return;
+ try {
+ start_serial();
+ serial.printf("i %d %d\n", launcher_serial, launcher_channel);
+ serial.flush_output();
+ } catch (InterruptedException ie) {
+ } finally {
+ try {
+ stop_serial();
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ public void close() {
+ try {
+ stop_serial();
+ } catch (InterruptedException ie) {
+ }
+ serial.close();
+ serial = null;
+ }
+
+ public void set_frame(Frame frame) {
+ serial.set_frame(frame);
+ }
+
+ public void set_remote(int in_serial, int in_channel) {
+ launcher_serial = in_serial;
+ launcher_channel = in_channel;
+ }
+
+ public AltosLaunch(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException {
+
+ device = in_device;
+ serial = new AltosSerial(device);
+ }
+} \ No newline at end of file
diff --git a/altosui/AltosLaunchUI.java b/altosui/AltosLaunchUI.java
new file mode 100644
index 00000000..47365e03
--- /dev/null
+++ b/altosui/AltosLaunchUI.java
@@ -0,0 +1,517 @@
+/*
+ * Copyright © 2010 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 altosui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import javax.swing.event.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.*;
+
+class FireButton extends JButton {
+ protected void processMouseEvent(MouseEvent e) {
+ super.processMouseEvent(e);
+ switch (e.getID()) {
+ case MouseEvent.MOUSE_PRESSED:
+ if (actionListener != null)
+ actionListener.actionPerformed(new ActionEvent(this, e.getID(), "fire_down"));
+ break;
+ case MouseEvent.MOUSE_RELEASED:
+ if (actionListener != null)
+ actionListener.actionPerformed(new ActionEvent(this, e.getID(), "fire_up"));
+ break;
+ }
+ }
+
+ public FireButton(String s) {
+ super(s);
+ }
+}
+
+public class AltosLaunchUI
+ extends JDialog
+ implements ActionListener
+{
+ AltosDevice device;
+ JFrame owner;
+ JLabel label;
+
+ int radio_channel;
+ JLabel radio_channel_label;
+ JTextField radio_channel_text;
+
+ int launcher_serial;
+ JLabel launcher_serial_label;
+ JTextField launcher_serial_text;
+
+ int launcher_channel;
+ JLabel launcher_channel_label;
+ JTextField launcher_channel_text;
+
+ JLabel armed_label;
+ JLabel armed_status_label;
+ JLabel igniter;
+ JLabel igniter_status_label;
+ JToggleButton arm;
+ FireButton fire;
+ javax.swing.Timer arm_timer;
+ javax.swing.Timer fire_timer;
+
+ boolean firing;
+ boolean armed;
+ int armed_status;
+ int igniter_status;
+ int rssi;
+
+ final static int arm_timeout = 1 * 1000;
+ final static int fire_timeout = 250;
+
+ int armed_count;
+
+ LinkedBlockingQueue<String> command_queue;
+
+ class LaunchHandler implements Runnable {
+ AltosLaunch launch;
+ JFrame owner;
+
+ void send_exception(Exception e) {
+ final Exception f_e = e;
+ Runnable r = new Runnable() {
+ public void run() {
+ launch_exception(f_e);
+ }
+ };
+ SwingUtilities.invokeLater(r);
+ }
+
+ public void run () {
+ try {
+ launch = new AltosLaunch(device);
+ } catch (Exception e) {
+ send_exception(e);
+ return;
+ }
+ launch.set_frame(owner);
+ launch.set_remote(launcher_serial, launcher_channel);
+
+ for (;;) {
+ Runnable r;
+
+ try {
+ String command = command_queue.take();
+ String reply = null;
+
+ if (command.equals("get_status")) {
+ launch.status();
+ reply = "status";
+ armed_status = launch.armed;
+ igniter_status = launch.igniter;
+ rssi = launch.rssi;
+ } else if (command.equals("set_remote")) {
+ launch.set_remote(launcher_serial, launcher_channel);
+ reply = "remote set";
+ } else if (command.equals("arm")) {
+ launch.arm();
+ reply = "armed";
+ } else if (command.equals("fire")) {
+ launch.fire();
+ reply = "fired";
+ } else if (command.equals("quit")) {
+ launch.close();
+ break;
+ } else {
+ throw new ParseException(String.format("invalid command %s", command), 0);
+ }
+ final String f_reply = reply;
+ r = new Runnable() {
+ public void run() {
+ launch_reply(f_reply);
+ }
+ };
+ SwingUtilities.invokeLater(r);
+ } catch (Exception e) {
+ send_exception(e);
+ }
+ }
+ }
+
+ public LaunchHandler(JFrame in_owner) {
+ owner = in_owner;
+ }
+ }
+
+ void launch_exception(Exception e) {
+ if (e instanceof FileNotFoundException) {
+ JOptionPane.showMessageDialog(owner,
+ ((FileNotFoundException) e).getMessage(),
+ "Cannot open target device",
+ JOptionPane.ERROR_MESSAGE);
+ } else if (e instanceof AltosSerialInUseException) {
+ JOptionPane.showMessageDialog(owner,
+ String.format("Device \"%s\" already in use",
+ device.toShortString()),
+ "Device in use",
+ JOptionPane.ERROR_MESSAGE);
+ } else if (e instanceof IOException) {
+ IOException ee = (IOException) e;
+ JOptionPane.showMessageDialog(owner,
+ device.toShortString(),
+ ee.getLocalizedMessage(),
+ JOptionPane.ERROR_MESSAGE);
+ } else {
+ JOptionPane.showMessageDialog(owner,
+ String.format("Connection to \"%s\" failed",
+ device.toShortString()),
+ "Connection Failed",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ close();
+ }
+
+ void launch_reply(String reply) {
+ if (reply == null)
+ return;
+ if (reply.equals("remote set"))
+ poll_launch_status();
+ if (reply.equals("status")) {
+ set_launch_status();
+ }
+ }
+
+ void set_arm_text() {
+ if (arm.isSelected())
+ arm.setText(String.format("%d", armed_count));
+ else
+ arm.setText("Arm");
+ }
+
+ void start_arm_timer() {
+ armed_count = 30;
+ set_arm_text();
+ }
+
+ void stop_arm_timer() {
+ armed_count = 0;
+ armed = false;
+ arm.setSelected(false);
+ fire.setEnabled(false);
+ set_arm_text();
+ }
+
+ void cancel () {
+ fire.setEnabled(false);
+ firing = false;
+ stop_arm_timer();
+ }
+
+ void send_command(String command) {
+ try {
+ command_queue.put(command);
+ } catch (Exception ex) {
+ launch_exception(ex);
+ }
+ }
+
+ boolean getting_status = false;
+
+ void set_launch_status() {
+ getting_status = false;
+ armed_status_label.setText(String.format("\"%s\"", AltosLaunch.status_string(armed_status)));
+ igniter_status_label.setText(String.format("\"%s\"", AltosLaunch.status_string(igniter_status)));
+ }
+
+ void poll_launch_status() {
+ if (!getting_status && !firing && !armed) {
+ getting_status = true;
+ send_command("get_status");
+ }
+ }
+
+ void fired() {
+ firing = false;
+ cancel();
+ }
+
+ void close() {
+ send_command("quit");
+ arm_timer.stop();
+ setVisible(false);
+ dispose();
+ }
+
+ void tick_arm_timer() {
+ if (armed_count > 0) {
+ --armed_count;
+ if (armed_count <= 0) {
+ armed_count = 0;
+ cancel();
+ } else {
+ if (!firing) {
+ send_command("arm");
+ set_arm_text();
+ }
+ }
+ }
+ poll_launch_status();
+ }
+
+ void arm() {
+ if (arm.isSelected()) {
+ fire.setEnabled(true);
+ start_arm_timer();
+ if (!firing)
+ send_command("arm");
+ armed = true;
+ } else
+ cancel();
+ }
+
+ void fire_more() {
+ if (firing)
+ send_command("fire");
+ }
+
+ void fire_down() {
+ if (arm.isEnabled() && arm.isSelected() && armed_count > 0) {
+ firing = true;
+ fire_more();
+ fire_timer.restart();
+ }
+ }
+
+ void fire_up() {
+ firing = false;
+ fire_timer.stop();
+ }
+
+ void set_radio() {
+ try {
+ radio_channel = Integer.parseInt(radio_channel_text.getText());
+ } catch (NumberFormatException ne) {
+ radio_channel_text.setText(String.format("%d", radio_channel));
+ }
+ }
+
+ void set_serial() {
+ try {
+ launcher_serial = Integer.parseInt(launcher_serial_text.getText());
+ AltosPreferences.set_launcher_serial(launcher_serial);
+ send_command("set_remote");
+ } catch (NumberFormatException ne) {
+ launcher_serial_text.setText(String.format("%d", launcher_serial));
+ }
+ }
+
+ void set_channel() {
+ try {
+ launcher_channel = Integer.parseInt(launcher_channel_text.getText());
+ AltosPreferences.set_launcher_serial(launcher_channel);
+ send_command("set_remote");
+ } catch (NumberFormatException ne) {
+ launcher_channel_text.setText(String.format("%d", launcher_channel));
+ }
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ String cmd = e.getActionCommand();
+ System.out.printf("cmd %s\n", cmd);
+ if (cmd.equals("armed") || cmd.equals("igniter")) {
+ stop_arm_timer();
+ }
+
+ if (cmd.equals("arm"))
+ arm();
+ if (cmd.equals("tick_arm"))
+ tick_arm_timer();
+ if (cmd.equals("close"))
+ close();
+ if (cmd.equals("fire_down"))
+ fire_down();
+ if (cmd.equals("fire_up"))
+ fire_up();
+ if (cmd.equals("tick_fire"))
+ fire_more();
+ if (cmd.equals("new_serial"))
+ set_serial();
+ if (cmd.equals("new_channel"))
+ set_channel();
+ }
+
+ /* A window listener to catch closing events and tell the config code */
+ class ConfigListener extends WindowAdapter {
+ AltosLaunchUI ui;
+
+ public ConfigListener(AltosLaunchUI this_ui) {
+ ui = this_ui;
+ }
+
+ public void windowClosing(WindowEvent e) {
+ ui.actionPerformed(new ActionEvent(e.getSource(),
+ ActionEvent.ACTION_PERFORMED,
+ "close"));
+ }
+ }
+
+ private boolean open() {
+ command_queue = new LinkedBlockingQueue<String>();
+
+ device = AltosDeviceDialog.show(owner, Altos.product_any);
+ if (device != null) {
+ LaunchHandler handler = new LaunchHandler(owner);
+ Thread t = new Thread(handler);
+ t.start();
+ return true;
+ }
+ return false;
+ }
+
+ public AltosLaunchUI(JFrame in_owner) {
+
+ launcher_channel = AltosPreferences.launcher_channel();
+ launcher_serial = AltosPreferences.launcher_serial();
+ owner = in_owner;
+ armed_status = AltosLaunch.Unknown;
+ igniter_status = AltosLaunch.Unknown;
+
+ if (!open())
+ return;
+
+ Container pane = getContentPane();
+ GridBagConstraints c = new GridBagConstraints();
+ Insets i = new Insets(4,4,4,4);
+
+ arm_timer = new javax.swing.Timer(arm_timeout, this);
+ arm_timer.setActionCommand("tick_arm");
+ arm_timer.restart();
+
+ fire_timer = new javax.swing.Timer(fire_timeout, this);
+ fire_timer.setActionCommand("tick_fire");
+
+ owner = in_owner;
+
+ pane.setLayout(new GridBagLayout());
+
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.CENTER;
+ c.insets = i;
+ c.weightx = 1;
+ c.weighty = 1;
+
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridwidth = 2;
+ c.anchor = GridBagConstraints.CENTER;
+ label = new JLabel ("Launch Controller");
+ pane.add(label, c);
+
+ c.gridx = 0;
+ c.gridy = 1;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ launcher_serial_label = new JLabel("Launcher Serial");
+ pane.add(launcher_serial_label, c);
+
+ c.gridx = 1;
+ c.gridy = 1;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ launcher_serial_text = new JTextField(7);
+ launcher_serial_text.setText(String.format("%d", launcher_serial));
+ launcher_serial_text.setActionCommand("new_serial");
+ launcher_serial_text.addActionListener(this);
+ pane.add(launcher_serial_text, c);
+
+ c.gridx = 0;
+ c.gridy = 2;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ launcher_channel_label = new JLabel("Launcher Channel");
+ pane.add(launcher_channel_label, c);
+
+ c.gridx = 1;
+ c.gridy = 2;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ launcher_channel_text = new JTextField(7);
+ launcher_channel_text.setText(String.format("%d", launcher_channel));
+ launcher_channel_text.setActionCommand("new_channel");
+ launcher_channel_text.addActionListener(this);
+ pane.add(launcher_channel_text, c);
+
+ c.gridx = 0;
+ c.gridy = 3;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ armed_label = new JLabel ("Armed");
+ pane.add(armed_label, c);
+
+ c.gridx = 1;
+ c.gridy = 3;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ armed_status_label = new JLabel();
+ pane.add(armed_status_label, c);
+
+ c.gridx = 0;
+ c.gridy = 4;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ igniter = new JLabel ("Igniter");
+ pane.add(igniter, c);
+
+ c.gridx = 1;
+ c.gridy = 4;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ igniter_status_label = new JLabel();
+ pane.add(igniter_status_label, c);
+
+ c.gridx = 0;
+ c.gridy = 5;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.CENTER;
+ arm = new JToggleButton ("Arm");
+ pane.add(arm, c);
+ arm.addActionListener(this);
+ arm.setActionCommand("arm");
+ arm.setEnabled(true);
+
+ c.gridx = 1;
+ c.gridy = 5;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.CENTER;
+ fire = new FireButton ("Fire");
+ fire.setEnabled(false);
+ pane.add(fire, c);
+ fire.addActionListener(this);
+ fire.setActionCommand("fire");
+
+ pack();
+ setLocationRelativeTo(owner);
+
+ addWindowListener(new ConfigListener(this));
+
+ setVisible(true);
+ }
+} \ No newline at end of file
diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java
index 716559ab..48aed441 100644
--- a/altosui/AltosPreferences.java
+++ b/altosui/AltosPreferences.java
@@ -58,6 +58,12 @@ class AltosPreferences {
/* font size preferences name */
final static String fontSizePreference = "FONT-SIZE";
+ /* Launcher serial preference name */
+ final static String launcherSerialPreference = "LAUNCHER-SERIAL";
+
+ /* Launcher channel prefernce name */
+ final static String launcherChannelPreference = "LAUNCHER-CHANNEL";
+
/* Default logdir is ~/TeleMetrum */
final static String logdirName = "TeleMetrum";
@@ -143,6 +149,9 @@ class AltosPreferences {
node.put(String.format(description_format, i), frequencies[i].description);
}
}
+ static int launcher_serial;
+
+ static int launcher_channel;
public static void init() {
preferences = Preferences.userRoot().node("/org/altusmetrum/altosui");
@@ -176,6 +185,10 @@ class AltosPreferences {
font_size = preferences.getInt(fontSizePreference, Altos.font_size_medium);
Altos.set_fonts(font_size);
+ launcher_serial = preferences.getInt(launcherSerialPreference, 0);
+
+ launcher_channel = preferences.getInt(launcherChannelPreference, 0);
+
String firmwaredir_string = preferences.get(firmwaredirPreference, null);
if (firmwaredir_string != null)
firmwaredir = new File(firmwaredir_string);
@@ -390,6 +403,32 @@ class AltosPreferences {
return serial_debug;
}
+ public static void set_launcher_serial(int new_launcher_serial) {
+ launcher_serial = new_launcher_serial;
+ System.out.printf("set launcher serial to %d\n", new_launcher_serial);
+ synchronized (preferences) {
+ preferences.putInt(launcherSerialPreference, launcher_serial);
+ flush_preferences();
+ }
+ }
+
+ public static int launcher_serial() {
+ return launcher_serial;
+ }
+
+ public static void set_launcher_channel(int new_launcher_channel) {
+ launcher_channel = new_launcher_channel;
+ System.out.printf("set launcher channel to %d\n", new_launcher_channel);
+ synchronized (preferences) {
+ preferences.putInt(launcherChannelPreference, launcher_channel);
+ flush_preferences();
+ }
+ }
+
+ public static int launcher_channel() {
+ return launcher_channel;
+ }
+
public static Preferences bt_devices() {
return preferences.node("bt_devices");
}
diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java
index bce4b32c..df5c51d4 100644
--- a/altosui/AltosScanUI.java
+++ b/altosui/AltosScanUI.java
@@ -130,8 +130,7 @@ public class AltosScanUI
void scan_exception(Exception e) {
if (e instanceof FileNotFoundException) {
JOptionPane.showMessageDialog(owner,
- String.format("Cannot open device \"%s\"",
- device.toShortString()),
+ ((FileNotFoundException) e).getMessage(),
"Cannot open target device",
JOptionPane.ERROR_MESSAGE);
} else if (e instanceof AltosSerialInUseException) {
@@ -326,8 +325,7 @@ public class AltosScanUI
return true;
} catch (FileNotFoundException ee) {
JOptionPane.showMessageDialog(owner,
- String.format("Cannot open device \"%s\"",
- device.toShortString()),
+ ee.getMessage(),
"Cannot open target device",
JOptionPane.ERROR_MESSAGE);
} catch (AltosSerialInUseException si) {
diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java
index 0a531aa9..4cf306d0 100644
--- a/altosui/AltosSerial.java
+++ b/altosui/AltosSerial.java
@@ -323,8 +323,10 @@ public class AltosSerial implements Runnable {
}
altos = device.open();
if (altos == null) {
+ final String message = device.getErrorString();
close();
- throw new FileNotFoundException(device.toShortString());
+ throw new FileNotFoundException(String.format("%s (%s)",
+ device.toShortString(), message));
}
if (debug)
System.out.printf("Open %s\n", device.getPath());
diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java
index 27c41838..3e5bcf43 100644
--- a/altosui/AltosUI.java
+++ b/altosui/AltosUI.java
@@ -52,8 +52,7 @@ public class AltosUI extends JFrame {
new AltosFlightUI(voice, reader, device.getSerial());
} catch (FileNotFoundException ee) {
JOptionPane.showMessageDialog(AltosUI.this,
- String.format("Cannot open device \"%s\"",
- device.toShortString()),
+ ee.getMessage(),
"Cannot open target device",
JOptionPane.ERROR_MESSAGE);
} catch (AltosSerialInUseException si) {
@@ -210,6 +209,13 @@ public class AltosUI extends JFrame {
});
b.setToolTipText("Check flight readiness of altimeter in idle mode");
+ b = addButton(3, 2, "Launch Controller");
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ LaunchController();
+ }
+ });
+
setTitle("AltOS");
pane.doLayout();
@@ -272,6 +278,10 @@ public class AltosUI extends JFrame {
new AltosSiteMapPreload(AltosUI.this);
}
+ void LaunchController() {
+ new AltosLaunchUI(AltosUI.this);
+ }
+
/*
* Replay a flight from telemetry data
*/
@@ -345,7 +355,7 @@ public class AltosUI extends JFrame {
else
return new AltosTelemetryIterable(in);
} catch (FileNotFoundException fe) {
- System.out.printf("Cannot open '%s'\n", filename);
+ System.out.printf("%s\n", fe.getMessage());
return null;
}
}
@@ -355,7 +365,7 @@ public class AltosUI extends JFrame {
try {
return new AltosCSV(file);
} catch (FileNotFoundException fe) {
- System.out.printf("Cannot open '%s'\n", filename);
+ System.out.printf("%s\n", fe.getMessage());
return null;
}
}
@@ -365,7 +375,7 @@ public class AltosUI extends JFrame {
try {
return new AltosKML(file);
} catch (FileNotFoundException fe) {
- System.out.printf("Cannot open '%s'\n", filename);
+ System.out.printf("%s\n", fe.getMessage());
return null;
}
}
diff --git a/altosui/AltosUSBDevice.java b/altosui/AltosUSBDevice.java
index dc746a64..b11a3934 100644
--- a/altosui/AltosUSBDevice.java
+++ b/altosui/AltosUSBDevice.java
@@ -39,6 +39,13 @@ public class AltosUSBDevice extends altos_device implements AltosDevice {
}
+ public String getErrorString() {
+ altos_error error = new altos_error();
+
+ libaltos.altos_get_last_error(error);
+ return String.format("%s (%d)", error.getString(), error.getCode());
+ }
+
public SWIGTYPE_p_altos_file open() {
return libaltos.altos_open(this);
}
diff --git a/altosui/Makefile.am b/altosui/Makefile.am
index ba1c830c..c4d1e611 100644
--- a/altosui/Makefile.am
+++ b/altosui/Makefile.am
@@ -68,6 +68,8 @@ altosui_JAVA = \
AltosIdleMonitorUI.java \
AltosIgnite.java \
AltosIgniteUI.java \
+ AltosLaunch.java \
+ AltosLaunchUI.java \
AltosInfoTable.java \
AltosKML.java \
AltosLanded.java \
@@ -116,7 +118,8 @@ altosui_JAVA = \
AltosGraphUI.java \
AltosDataChooser.java \
AltosVersion.java \
- AltosVoice.java
+ AltosVoice.java \
+ $(altosui_BT)
JFREECHART_CLASS= \
jfreechart.jar
diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c
index d1f445bd..48e00a44 100644
--- a/altosui/libaltos/libaltos.c
+++ b/altosui/libaltos/libaltos.c
@@ -49,6 +49,22 @@ altos_fini(void)
{
}
+static struct altos_error last_error;
+
+static void
+altos_set_last_error(int code, char *string)
+{
+ last_error.code = code;
+ strncpy(last_error.string, string, sizeof (last_error.string) -1);
+ last_error.string[sizeof(last_error.string)-1] = '\0';
+}
+
+PUBLIC void
+altos_get_last_error(struct altos_error *error)
+{
+ *error = last_error;
+}
+
#ifdef DARWIN
#undef USE_POLL
@@ -96,6 +112,12 @@ struct altos_file {
int in_read;
};
+static void
+altos_set_last_posix_error(void)
+{
+ altos_set_last_error(errno, strerror(errno));
+}
+
PUBLIC struct altos_file *
altos_open(struct altos_device *device)
{
@@ -103,12 +125,18 @@ altos_open(struct altos_device *device)
int ret;
struct termios term;
- if (!file)
+ if (!file) {
+ altos_set_last_posix_error();
return NULL;
+ }
+
+// altos_set_last_error(12, "yeah yeah, failed again");
+// free(file);
+// return NULL;
file->fd = open(device->path, O_RDWR | O_NOCTTY);
if (file->fd < 0) {
- perror(device->path);
+ altos_set_last_posix_error();
free(file);
return NULL;
}
@@ -117,7 +145,7 @@ altos_open(struct altos_device *device)
#else
file->out_fd = open(device->path, O_RDWR | O_NOCTTY);
if (file->out_fd < 0) {
- perror(device->path);
+ altos_set_last_posix_error();
close(file->fd);
free(file);
return NULL;
@@ -125,7 +153,7 @@ altos_open(struct altos_device *device)
#endif
ret = tcgetattr(file->fd, &term);
if (ret < 0) {
- perror("tcgetattr");
+ altos_set_last_posix_error();
close(file->fd);
#ifndef USE_POLL
close(file->out_fd);
@@ -143,7 +171,7 @@ altos_open(struct altos_device *device)
#endif
ret = tcsetattr(file->fd, TCSAFLUSH, &term);
if (ret < 0) {
- perror("tcsetattr");
+ altos_set_last_posix_error();
close(file->fd);
#ifndef USE_POLL
close(file->out_fd);
@@ -195,8 +223,10 @@ altos_flush(struct altos_file *file)
#else
ret = write (file->out_fd, file->out_data, file->out_used);
#endif
- if (ret < 0)
+ if (ret < 0) {
+ altos_set_last_posix_error();
return -errno;
+ }
if (ret) {
memmove(file->out_data, file->out_data + ret,
file->out_used - ret);
@@ -248,7 +278,7 @@ altos_fill(struct altos_file *file, int timeout)
fd[1].events = POLLIN;
ret = poll(fd, 2, timeout);
if (ret < 0) {
- perror("altos_getchar");
+ altos_set_last_posix_error();
return LIBALTOS_ERROR;
}
if (ret == 0)
@@ -261,7 +291,7 @@ altos_fill(struct altos_file *file, int timeout)
{
ret = read(file->fd, file->in_data, USB_BUF_SIZE);
if (ret < 0) {
- perror("altos_getchar");
+ altos_set_last_posix_error();
return LIBALTOS_ERROR;
}
file->in_read = 0;
@@ -598,7 +628,6 @@ altos_list_finish(struct altos_list *usbdevs)
free(usbdevs);
}
-#if HAS_BLUETOOTH
struct altos_bt_list {
inquiry_info *ii;
int sock;
@@ -701,8 +730,10 @@ altos_bt_open(struct altos_bt_device *device)
if (!file)
goto no_file;
file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
- if (file->fd < 0)
+ if (file->fd < 0) {
+ altos_set_last_posix_error();
goto no_sock;
+ }
addr.rc_family = AF_BLUETOOTH;
addr.rc_channel = 1;
@@ -712,7 +743,7 @@ altos_bt_open(struct altos_bt_device *device)
(struct sockaddr *)&addr,
sizeof(addr));
if (status < 0) {
- perror("connect");
+ altos_set_last_posix_error();
goto no_link;
}
sleep(1);
@@ -730,7 +761,6 @@ no_sock:
no_file:
return NULL;
}
-#endif /* HAS_BLUETOOTH */
#endif
@@ -844,6 +874,48 @@ altos_list_finish(struct altos_list *list)
free(list);
}
+struct altos_bt_list {
+ int sock;
+ int dev_id;
+ int rsp;
+ int num_rsp;
+};
+
+#define INQUIRY_MAX_RSP 255
+
+struct altos_bt_list *
+altos_bt_list_start(int inquiry_time)
+{
+ return NULL;
+}
+
+int
+altos_bt_list_next(struct altos_bt_list *bt_list,
+ struct altos_bt_device *device)
+{
+ return 0;
+}
+
+void
+altos_bt_list_finish(struct altos_bt_list *bt_list)
+{
+}
+
+void
+altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
+{
+ strncpy(device->name, name, sizeof (device->name));
+ device->name[sizeof(device->name)-1] = '\0';
+ strncpy(device->addr, addr, sizeof (device->addr));
+ device->addr[sizeof(device->addr)-1] = '\0';
+}
+
+struct altos_file *
+altos_bt_open(struct altos_bt_device *device)
+{
+ return NULL;
+}
+
#endif
@@ -872,6 +944,21 @@ struct altos_file {
OVERLAPPED ov_write;
};
+static void
+altos_set_last_windows_error(void)
+{
+ DWORD error = GetLastError();
+ TCHAR message[1024];
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ 0,
+ error,
+ 0,
+ message,
+ sizeof (message) / sizeof (TCHAR),
+ NULL);
+ altos_set_last_error(error, message);
+}
+
PUBLIC struct altos_list *
altos_list_start(void)
{
@@ -882,7 +969,7 @@ altos_list_start(void)
list->dev_info = SetupDiGetClassDevs(NULL, "USB", NULL,
DIGCF_ALLCLASSES|DIGCF_PRESENT);
if (list->dev_info == INVALID_HANDLE_VALUE) {
- printf("SetupDiGetClassDevs failed %ld\n", GetLastError());
+ altos_set_last_windows_error();
free(list);
return NULL;
}
@@ -916,6 +1003,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
DICS_FLAG_GLOBAL, 0, DIREG_DEV,
KEY_READ);
if (dev_key == INVALID_HANDLE_VALUE) {
+ altos_set_last_windows_error();
printf("cannot open device registry key\n");
continue;
}
@@ -926,6 +1014,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
result = RegQueryValueEx(dev_key, "SymbolicName", NULL, NULL,
symbolic, &symbolic_len);
if (result != 0) {
+ altos_set_last_windows_error();
printf("cannot find SymbolicName value\n");
RegCloseKey(dev_key);
continue;
@@ -948,6 +1037,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
port, &port_len);
RegCloseKey(dev_key);
if (result != 0) {
+ altos_set_last_windows_error();
printf("failed to get PortName\n");
continue;
}
@@ -963,6 +1053,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
sizeof(friendlyname),
&friendlyname_len))
{
+ altos_set_last_windows_error();
printf("Failed to get friendlyname\n");
continue;
}
@@ -975,8 +1066,10 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
return 1;
}
result = GetLastError();
- if (result != ERROR_NO_MORE_ITEMS)
+ if (result != ERROR_NO_MORE_ITEMS) {
+ altos_set_last_windows_error();
printf ("SetupDiEnumDeviceInfo failed error %d\n", (int) result);
+ }
return 0;
}
@@ -995,8 +1088,10 @@ altos_queue_read(struct altos_file *file)
return LIBALTOS_SUCCESS;
if (!ReadFile(file->handle, file->in_data, USB_BUF_SIZE, &got, &file->ov_read)) {
- if (GetLastError() != ERROR_IO_PENDING)
+ if (GetLastError() != ERROR_IO_PENDING) {
+ altos_set_last_windows_error();
return LIBALTOS_ERROR;
+ }
file->pend_read = TRUE;
} else {
file->pend_read = FALSE;
@@ -1021,8 +1116,10 @@ altos_wait_read(struct altos_file *file, int timeout)
ret = WaitForSingleObject(file->ov_read.hEvent, timeout);
switch (ret) {
case WAIT_OBJECT_0:
- if (!GetOverlappedResult(file->handle, &file->ov_read, &got, FALSE))
+ if (!GetOverlappedResult(file->handle, &file->ov_read, &got, FALSE)) {
+ altos_set_last_windows_error();
return LIBALTOS_ERROR;
+ }
file->pend_read = FALSE;
file->in_read = 0;
file->in_used = got;
@@ -1066,15 +1163,20 @@ altos_flush(struct altos_file *file)
while (used) {
if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) {
- if (GetLastError() != ERROR_IO_PENDING)
+ if (GetLastError() != ERROR_IO_PENDING) {
+ altos_set_last_windows_error();
return LIBALTOS_ERROR;
+ }
ret = WaitForSingleObject(file->ov_write.hEvent, INFINITE);
switch (ret) {
case WAIT_OBJECT_0:
- if (!GetOverlappedResult(file->handle, &file->ov_write, &put, FALSE))
+ if (!GetOverlappedResult(file->handle, &file->ov_write, &put, FALSE)) {
+ altos_set_last_windows_error();
return LIBALTOS_ERROR;
+ }
break;
default:
+ altos_set_last_windows_error();
return LIBALTOS_ERROR;
}
}
@@ -1102,6 +1204,7 @@ altos_open(struct altos_device *device)
0, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
if (file->handle == INVALID_HANDLE_VALUE) {
+ altos_set_last_windows_error();
free(file);
return NULL;
}
@@ -1117,6 +1220,7 @@ altos_open(struct altos_device *device)
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (!GetCommState(file->handle, &dcbSerialParams)) {
+ altos_set_last_windows_error();
CloseHandle(file->handle);
free(file);
return NULL;
@@ -1126,6 +1230,7 @@ altos_open(struct altos_device *device)
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(file->handle, &dcbSerialParams)) {
+ altos_set_last_windows_error();
CloseHandle(file->handle);
free(file);
return NULL;
@@ -1180,4 +1285,38 @@ altos_getchar(struct altos_file *file, int timeout)
return file->in_data[file->in_read++];
}
+struct altos_bt_list *
+altos_bt_list_start(int inquiry_time)
+{
+ return NULL;
+}
+
+int
+altos_bt_list_next(struct altos_bt_list *bt_list,
+ struct altos_bt_device *device)
+{
+ return 0;
+}
+
+void
+altos_bt_list_finish(struct altos_bt_list *bt_list)
+{
+ free(bt_list);
+}
+
+void
+altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
+{
+ strncpy(device->name, name, sizeof (device->name));
+ device->name[sizeof(device->name)-1] = '\0';
+ strncpy(device->addr, addr, sizeof (device->addr));
+ device->addr[sizeof(device->addr)-1] = '\0';
+}
+
+struct altos_file *
+altos_bt_open(struct altos_bt_device *device)
+{
+ return NULL;
+}
+
#endif
diff --git a/altosui/libaltos/libaltos.h b/altosui/libaltos/libaltos.h
index 363a84fd..f90fbb87 100644
--- a/altosui/libaltos/libaltos.h
+++ b/altosui/libaltos/libaltos.h
@@ -51,6 +51,11 @@ struct altos_bt_device {
//%mutable;
};
+struct altos_error {
+ int code;
+ char string[1024];
+};
+
#define LIBALTOS_SUCCESS 0
#define LIBALTOS_ERROR -1
#define LIBALTOS_TIMEOUT -2
@@ -62,6 +67,9 @@ altos_init(void);
PUBLIC void
altos_fini(void);
+PUBLIC void
+altos_get_last_error(struct altos_error *error);
+
PUBLIC struct altos_list *
altos_list_start(void);
@@ -93,9 +101,6 @@ altos_flush(struct altos_file *file);
PUBLIC int
altos_getchar(struct altos_file *file, int timeout);
-// #define HAS_BLUETOOTH 1
-#if HAS_BLUETOOTH
-
PUBLIC struct altos_bt_list *
altos_bt_list_start(int inquiry_time);
@@ -111,6 +116,4 @@ altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device);
PUBLIC struct altos_file *
altos_bt_open(struct altos_bt_device *device);
-#endif
-
#endif /* _LIBALTOS_H_ */
diff --git a/configure.ac b/configure.ac
index 27d56751..959f3b4d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,8 +18,8 @@ dnl
dnl Process this file with autoconf to create configure.
AC_PREREQ(2.57)
-AC_INIT([altos], 1.0.1)
-AC_CONFIG_SRCDIR([src/ao.h])
+AC_INIT([altos], 1.0.9.0)
+AC_CONFIG_SRCDIR([src/core/ao.h])
AM_INIT_AUTOMAKE([foreign dist-bzip2])
AM_MAINTAINER_MODE
diff --git a/src/Makefile b/src/Makefile
index 018f0c5c..5da7c855 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -2,7 +2,13 @@
# AltOS build
#
#
-CC=sdcc
+
+vpath make-altitude util
+vpath make-kalman util
+vpath kalman.5c kalman
+vpath kalman_filter.5c kalman
+vpath load_csv.5c kalman
+vpath matrix.5c kalman
include Version
@@ -12,9 +18,10 @@ SUBDIRS=\
telemini-v1.0 telenano-v0.1 \
telebt-v0.0 telebt-v0.1 \
telemetrum-v0.1-sky telemetrum-v0.1-sirf \
- tidongle test
+ telelaunch-v0.1 \
+ tidongle test telescience-v0.1 telepyro-v0.1
-all: all-recursive
+all: all-local all-recursive
RECURSIVE_TARGETS = all-recursive clean-recursive install-recursive
@@ -27,8 +34,21 @@ $(RECURSIVE_TARGETS):
distclean: clean
-clean: clean-recursive
+clean: clean-local clean-recursive
install: install-recursive
uninstall:
+
+all-recursive: all-local
+
+all-local: altitude.h ao_kalman.h
+
+altitude.h: make-altitude
+ nickle $< > $@
+
+ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c
+ bash $< kalman > $@
+
+clean-local:
+ rm -f altitude.h ao_kalman.h
diff --git a/src/Makefile.proto b/src/Makefile.proto
deleted file mode 100644
index 8f98d354..00000000
--- a/src/Makefile.proto
+++ /dev/null
@@ -1,380 +0,0 @@
-#
-# AltOS build
-#
-#
-vpath %.c ..
-vpath %.h ..
-vpath make-altitude ..
-vpath make-kalman ..
-vpath kalman.5c ../kalman
-vpath kalman_filter.5c ../kalman
-vpath load_csv.5c ../kalman
-vpath matrix.5c ../kalman
-vpath ao-make-product.5c ..
-
-CC=sdcc
-
-ifndef VERSION
-include ../Version
-endif
-
-CFLAGS=--model-small --debug --opt-code-speed -DCODESIZE=$(CODESIZE)
-
-CODESIZE ?= 0x8000
-
-LDFLAGS=--out-fmt-ihx --code-loc 0x0000 --code-size $(CODESIZE) \
- --xram-loc 0xf000 --xram-size 0xda2 --iram-size 0xff
-
-INC = \
- ao.h \
- ao_pins.h \
- cc1111.h \
- altitude.h \
- ao_kalman.h \
- 25lc1024.h
-
-#
-# Common AltOS sources
-#
-ALTOS_SRC = \
- ao_cmd.c \
- ao_dma.c \
- ao_mutex.c \
- ao_panic.c \
- ao_task.c \
- ao_timer.c \
- ao_romconfig.c \
- _bp.c
-
-#
-# Shared AltOS drivers
-#
-ALTOS_DRIVER_SRC = \
- ao_config.c \
- ao_led.c \
- ao_radio.c \
- ao_stdio.c
-
-BEEP_DRIVER_SRC = \
- ao_beep.c
-
-USB_DRIVER_SRC = \
- ao_usb.c
-
-TELE_COMMON_SRC = \
- ao_packet.c
-
-#
-# Receiver code
-#
-TELE_RECEIVER_SRC =\
- ao_monitor.c \
- ao_gps_print.c \
- ao_packet_master.c \
- ao_state.c \
- ao_rssi.c
-
-#
-# Shared Tele drivers (on TeleMetrum, TeleTerra, TeleDongle)
-#
-
-TELE_DRIVER_SRC = \
- ao_convert.c
-
-#
-# Serial port driver
-#
-SERIAL_DRIVER_SRC = \
- ao_serial.c
-
-#
-# Spi bus driver
-#
-SPI_DRIVER_SRC = \
- ao_spi.c
-
-#
-# Debug dongle driver (only on TI)
-#
-DBG_SRC = \
- ao_dbg.c
-
-#
-# Drivers only on TeleMetrum
-#
-TM_DRIVER_SRC = \
- ao_adc.c \
- ao_gps_report.c \
- ao_ignite.c \
- ao_packet_slave.c \
- $(BEEP_DRIVER_SRC) \
- $(USB_DRIVER_SRC)
-
-#
-# 25LC1024 driver source
-EE_DRIVER_SRC = \
- ao_storage.c \
- ao_ee.c
-
-#
-# AT45DB161D driver source
-
-FLASH_DRIVER_SRC = \
- ao_storage.c \
- ao_flash.c
-
-#
-# Numonyx M25P80 driver source
-#
-
-M25_DRIVER_SRC = \
- ao_storage.c \
- ao_m25.c
-
-#
-# SiRF driver source
-#
-SIRF_DRIVER_SRC = \
- ao_gps_sirf.c
-
-#
-# Skytraq driver source
-#
-SKY_DRIVER_SRC = \
- ao_gps_skytraq.c
-
-
-#
-# BTM-182 driver source
-#
-BTM_DRIVER_SRC = \
- ao_btm.c
-
-#
-# Companion port driver source
-#
-COMPANION_SRC = \
- ao_companion.c
-
-#
-# Tasks run on TeleMetrum
-#
-TM_TASK_SRC = \
- ao_flight.c \
- ao_sample.c \
- ao_kalman.c \
- ao_log.c \
- ao_log_big.c \
- ao_report.c \
- ao_telemetry.c
-
-TM_MAIN_SRC = \
- ao_telemetrum.c
-
-#
-# Base sources for TeleMetrum
-#
-TM_BASE_SRC = \
- $(ALTOS_SRC) \
- $(ALTOS_DRIVER_SRC) \
- $(TELE_DRIVER_SRC) \
- $(SERIAL_DRIVER_SRC) \
- $(TELE_COMMON_SRC) \
- $(TM_DRIVER_SRC) \
- $(TM_TASK_SRC) \
- $(TM_MAIN_SRC)
-
-#
-# Sources for TeleMini
-TMINI_DRIVER_SRC = \
- ao_adc.c \
- ao_ignite.c \
- ao_config.c \
- ao_storage.c \
- ao_packet_slave.c \
- ao_intflash.c
-
-TMINI_TASK_SRC = \
- ao_flight.c \
- ao_sample.c \
- ao_kalman.c \
- ao_log.c \
- ao_log_tiny.c \
- ao_report.c \
- ao_telemetry.c
-
-TMINI_MAIN_SRC = \
- ao_telemini.c
-
-TMINI_BASE_SRC = \
- $(ALTOS_SRC) \
- $(ALTOS_DRIVER_SRC) \
- $(TELE_DRIVER_SRC) \
- $(TELE_COMMON_SRC) \
- $(TMINI_DRIVER_SRC) \
- $(TMINI_TASK_SRC) \
- $(TMINI_MAIN_SRC)
-
-#
-# Sources for TeleNano
-TNANO_DRIVER_SRC = \
- ao_adc.c \
- ao_config.c \
- ao_storage.c \
- ao_packet_slave.c \
- ao_intflash.c
-
-TNANO_TASK_SRC = \
- ao_flight_nano.c \
- ao_sample.c \
- ao_kalman.c \
- ao_log.c \
- ao_log_tiny.c \
- ao_report.c \
- ao_telemetry.c
-
-TNANO_MAIN_SRC = \
- ao_telenano.c
-
-TNANO_BASE_SRC = \
- $(ALTOS_SRC) \
- $(ALTOS_DRIVER_SRC) \
- $(TELE_DRIVER_SRC) \
- $(TELE_COMMON_SRC) \
- $(TNANO_DRIVER_SRC) \
- $(TNANO_TASK_SRC) \
- $(TNANO_MAIN_SRC)
-
-#
-# Sources for TeleBluetooth
-#
-
-TBT_MAIN_SRC = \
- ao_telebt.c
-
-TBT_BASE_SRC = \
- $(ALTOS_SRC) \
- $(ALTOS_DRIVER_SRC) \
- $(TELE_RECEIVER_SRC) \
- $(TELE_COMMON_SRC) \
- $(SERIAL_DRIVER_SRC) \
- $(USB_DRIVER_SRC) \
- $(BTM_DRIVER_SRC) \
- $(DBG_SRC) \
- $(TBT_MAIN_SRC)
-
-TBT_V_0_1_SRC = \
- $(TBT_BASE_SRC) \
- $(SPI_DRIVER_SRC) \
- $(M25_DRIVER_SRC) \
- $(BEEP_DRIVER_SRC) \
- ao_log_telem.c
-
-#
-# TI Dongle sources
-#
-TI_MAIN_SRC = \
- ao_tidongle.c
-
-#
-# All sources for the TI debug dongle
-#
-TI_SRC = \
- $(ALTOS_SRC) \
- $(ALTOS_DRIVER_SRC) \
- $(TELE_RECEIVER_SRC) \
- $(TELE_COMMON_SRC) \
- $(USB_DRIVER_SRC) \
- $(TI_MAIN_SRC) \
- $(DBG_SRC)
-
-TT_MAIN_SRC = \
- ao_teleterra.c
-#
-# All sources for TeleTerra
-#
-TT_SRC = \
- $(ALTOS_SRC) \
- $(ALTOS_DRIVER_SRC) \
- $(TELE_RECEIVER_SRC) \
- $(TELE_DRIVER_SRC) \
- $(TELE_COMMON_SRC) \
- $(USB_DRIVER_SRC) \
- $(TT_MAIN_SRC)
-
-
-#
-# Sources for TeleDongle
-#
-
-TD_MAIN_SRC = \
- ao_teledongle.c
-
-TD_SRC = \
- $(ALTOS_SRC) \
- $(ALTOS_DRIVER_SRC) \
- $(TELE_RECEIVER_SRC) \
- $(TELE_COMMON_SRC) \
- $(USB_DRIVER_SRC) \
- $(TD_MAIN_SRC)
-
-include Makefile.defs
-
-CFLAGS += $(PRODUCT_DEF) -I.
-
-NICKLE=nickle
-CHECK_STACK=sh ../check-stack
-
-REL=$(SRC:.c=.rel) ao_product.rel
-ADB=$(REL:.rel=.adb)
-ASM=$(REL:.rel=.asm)
-LNK=$(REL:.rel=.lnk)
-LST=$(REL:.rel=.lst)
-RST=$(REL:.rel=.rst)
-SYM=$(REL:.rel=.sym)
-
-PCDB=$(PROG:.ihx=.cdb)
-PLNK=$(PROG:.ihx=.lnk)
-PMAP=$(PROG:.ihx=.map)
-PMEM=$(PROG:.ihx=.mem)
-PAOM=$(PROG:.ihx=)
-
-V=0
-# The user has explicitly enabled quiet compilation.
-ifeq ($(V),0)
-quiet = @printf " $1 $2 $@\n"; $($1)
-endif
-# Otherwise, print the full command line.
-quiet ?= $($1)
-
-%.rel : %.c $(INC)
- $(call quiet,CC,$(PRODUCT_DEF)) $(CFLAGS) -c -o$@ $<
-
-all: ../$(PROG)
-
-../$(PROG): $(REL) Makefile Makefile.defs ../Makefile.proto
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
- $(call quiet,CHECK_STACK) ../ao.h $(PMEM)
-
-../altitude.h: make-altitude
- nickle $< > $@
-
-../ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c
- sh $< > $@
-
-ao_product.h: ao-make-product.5c ../Version
- $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
-
-$(REL): ao_product.h
-
-distclean: clean
-
-clean:
- rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM)
- rm -f $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
- rm -f ao_product.h
- rm -f ../$(PROG)
-
-install:
-
-uninstall:
diff --git a/src/ao_aes.c b/src/ao_aes.c
new file mode 100644
index 00000000..d50fecfb
--- /dev/null
+++ b/src/ao_aes.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+#if !HAS_AES
+#error Must define HAS_AES 1
+#endif
+
+__xdata uint8_t ao_aes_mutex;
+__xdata uint8_t ao_aes_done;
+__xdata uint8_t ao_aes_dma_in, ao_aes_dma_out;
+__xdata uint8_t ao_aes_dma_in_done, ao_aes_dma_out_done;
+__pdata enum ao_aes_mode ao_aes_current_mode;
+
+void
+ao_aes_isr(void) __interrupt 4
+{
+ S0CON = 0;
+ if (ENCCCS & ENCCCS_RDY) {
+ ao_aes_done = 1;
+ ao_wakeup(&ao_aes_done);
+ }
+}
+
+void
+ao_aes_set_mode(enum ao_aes_mode mode)
+{
+ ao_aes_current_mode = mode;
+}
+
+void
+ao_aes_set_key(__xdata uint8_t *in)
+{
+ ao_dma_set_transfer(ao_aes_dma_in,
+ in,
+ &ENCDIXADDR,
+ AO_AES_LEN,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_ENC_DW,
+ DMA_CFG1_SRCINC_1 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_LOW);
+ ao_dma_start(ao_aes_dma_in);
+ ao_aes_done = 0;
+ ENCCCS = ENCCCS_MODE_CBC_MAC |
+ ENCCCS_CMD_LOAD_KEY;
+ ENCCCS |= ENCCCS_START;
+ __critical while (!ao_aes_done)
+ ao_sleep(&ao_aes_done);
+}
+
+void
+ao_aes_zero_iv(void)
+{
+ uint8_t b;
+
+ ENCCCS = ENCCCS_MODE_CBC_MAC | ENCCCS_CMD_LOAD_IV | ENCCCS_START;
+ for (b = 0; b < AO_AES_LEN; b++)
+ ENCDI = 0;
+}
+
+void
+ao_aes_run(__xdata uint8_t *in,
+ __xdata uint8_t *out)
+{
+ uint8_t b;
+ if (in) {
+ ao_dma_set_transfer(ao_aes_dma_in,
+ in,
+ &ENCDIXADDR,
+ AO_AES_LEN,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_ENC_DW,
+ DMA_CFG1_SRCINC_1 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_LOW);
+ }
+ if (out) {
+ ao_dma_set_transfer(ao_aes_dma_out,
+ &ENCDOXADDR,
+ out,
+ AO_AES_LEN,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_ENC_UP,
+ DMA_CFG1_SRCINC_0 |
+ DMA_CFG1_DESTINC_1 |
+ DMA_CFG1_PRIORITY_LOW);
+ }
+ switch (ao_aes_current_mode) {
+ case ao_aes_mode_cbc_mac:
+ if (out)
+ b = (ENCCCS_MODE_CBC |
+ ENCCCS_CMD_ENCRYPT);
+ else
+ b = (ENCCCS_MODE_CBC_MAC |
+ ENCCCS_CMD_ENCRYPT);
+ break;
+ default:
+ return;
+ }
+ ao_aes_done = 0;
+ if (in)
+ ao_dma_start(ao_aes_dma_in);
+ if (out)
+ ao_dma_start(ao_aes_dma_out);
+ ENCCCS = b;
+ ENCCCS |= ENCCCS_START;
+ if (out) {
+ __critical while (!ao_aes_dma_out_done)
+ ao_sleep(&ao_aes_dma_out_done);
+ } else {
+ __critical while (!ao_aes_done)
+ ao_sleep(&ao_aes_done);
+ }
+}
+
+void
+ao_aes_init(void)
+{
+ ao_aes_dma_in = ao_dma_alloc(&ao_aes_dma_in_done);
+ ao_aes_dma_out = ao_dma_alloc(&ao_aes_dma_out_done);
+ S0CON = 0;
+ ENCIE = 1;
+}
diff --git a/src/ao_radio_cmac.c b/src/ao_radio_cmac.c
new file mode 100644
index 00000000..41fbbe1f
--- /dev/null
+++ b/src/ao_radio_cmac.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+#define AO_CMAC_KEY_LEN AO_AES_LEN
+#define AO_CMAC_MAX_LEN (128 - AO_CMAC_KEY_LEN)
+
+static __xdata uint8_t ao_radio_cmac_mutex;
+__pdata int16_t ao_radio_cmac_rssi;
+static __xdata uint8_t cmac_data[AO_CMAC_MAX_LEN + AO_CMAC_KEY_LEN + 2 + AO_CMAC_KEY_LEN];
+static __pdata uint8_t ao_radio_cmac_len;
+
+static uint8_t
+getnibble(void)
+{
+ int8_t b;
+
+ b = ao_cmd_hexchar(getchar());
+ if (b < 0) {
+ ao_cmd_status = ao_cmd_lex_error;
+ return 0;
+ }
+ return (uint8_t) b;
+}
+
+static uint8_t
+getbyte(void)
+{
+ uint8_t b;
+ b = getnibble() << 4;
+ b |= getnibble();
+ return b;
+}
+
+static uint8_t
+round_len(uint8_t len)
+{
+ uint8_t rem;
+
+ /* Make sure we transfer at least one packet, and
+ * then make sure every packet is full. Note that
+ * there is no length encoded, and that the receiver
+ * must deal with any extra bytes in the packet
+ */
+ if (len < AO_CMAC_KEY_LEN)
+ len = AO_CMAC_KEY_LEN;
+ rem = len % AO_CMAC_KEY_LEN;
+ if (rem != 0)
+ len += (AO_CMAC_KEY_LEN - rem);
+ return len;
+}
+
+/*
+ * Sign and deliver the data sitting in the cmac buffer
+ */
+static void
+radio_cmac_send(uint8_t len) __reentrant
+{
+ uint8_t i;
+
+ len = round_len(len);
+ /* Make sure the AES key is loaded */
+ ao_config_get();
+
+#if HAS_MONITOR
+ ao_set_monitor(0);
+#endif
+
+ ao_mutex_get(&ao_aes_mutex);
+ ao_aes_set_mode(ao_aes_mode_cbc_mac);
+ ao_aes_set_key(ao_config.aes_key);
+ ao_aes_zero_iv();
+ for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
+ if (i + AO_CMAC_KEY_LEN < len)
+ ao_aes_run(&cmac_data[i], NULL);
+ else
+ ao_aes_run(&cmac_data[i], &cmac_data[len]);
+ }
+ ao_mutex_put(&ao_aes_mutex);
+
+ ao_radio_send(cmac_data, len + AO_CMAC_KEY_LEN);
+}
+
+/*
+ * Receive and validate an incoming packet
+ */
+
+static int8_t
+radio_cmac_recv(uint8_t len, uint16_t timeout) __reentrant
+{
+ uint8_t i;
+
+ len = round_len(len);
+#if HAS_MONITOR
+ ao_set_monitor(0);
+#endif
+ if (timeout)
+ ao_alarm(timeout);
+
+ i = ao_radio_recv(cmac_data, len + AO_CMAC_KEY_LEN + 2);
+ ao_clear_alarm();
+
+ if (!i) {
+ ao_radio_cmac_rssi = 0;
+ return AO_RADIO_CMAC_TIMEOUT;
+ }
+
+ ao_radio_cmac_rssi = (int16_t) (((int8_t) cmac_data[len + AO_CMAC_KEY_LEN]) >> 1) - 74;
+ if (!(cmac_data[len + AO_CMAC_KEY_LEN +1] & PKT_APPEND_STATUS_1_CRC_OK))
+ return AO_RADIO_CMAC_CRC_ERROR;
+
+ ao_config_get();
+
+ /* Compute the packet signature
+ */
+ ao_mutex_get(&ao_aes_mutex);
+ ao_aes_set_mode(ao_aes_mode_cbc_mac);
+ ao_aes_set_key(ao_config.aes_key);
+ ao_aes_zero_iv();
+ for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
+ if (i + AO_CMAC_KEY_LEN < len)
+ ao_aes_run(&cmac_data[i], NULL);
+ else
+ ao_aes_run(&cmac_data[i], &cmac_data[len + AO_CMAC_KEY_LEN + 2]);
+ }
+ ao_mutex_put(&ao_aes_mutex);
+
+ /* Check the packet signature against the signature provided
+ * over the link
+ */
+
+ if (memcmp(&cmac_data[len],
+ &cmac_data[len + AO_CMAC_KEY_LEN + 2],
+ AO_CMAC_KEY_LEN) != 0) {
+ return AO_RADIO_CMAC_MAC_ERROR;
+ }
+
+ return AO_RADIO_CMAC_OK;
+}
+
+int8_t
+ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant
+{
+ if (len > AO_CMAC_MAX_LEN)
+ return AO_RADIO_CMAC_LEN_ERROR;
+ ao_mutex_get(&ao_radio_cmac_mutex);
+ memcpy(cmac_data, packet, len);
+ radio_cmac_send(len);
+ ao_mutex_put(&ao_radio_cmac_mutex);
+ return AO_RADIO_CMAC_OK;
+}
+
+int8_t
+ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant
+{
+ uint8_t i;
+ if (len > AO_CMAC_MAX_LEN)
+ return AO_RADIO_CMAC_LEN_ERROR;
+ ao_mutex_get(&ao_radio_cmac_mutex);
+ i = radio_cmac_recv(len, timeout);
+ if (i == AO_RADIO_CMAC_OK)
+ memcpy(packet, cmac_data, len);
+ ao_mutex_put(&ao_radio_cmac_mutex);
+ return i;
+}
+
+static void
+radio_cmac_send_cmd(void) __reentrant
+{
+ uint8_t i;
+ uint8_t len;
+
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ len = ao_cmd_lex_i;
+ if (len > AO_CMAC_MAX_LEN) {
+ ao_cmd_status = ao_cmd_syntax_error;
+ return;
+ }
+ flush();
+ ao_mutex_get(&ao_radio_cmac_mutex);
+ len = ao_cmd_lex_i;
+ for (i = 0; i < len; i++) {
+ cmac_data[i] = getbyte();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ }
+ radio_cmac_send(len);
+ ao_mutex_put(&ao_radio_cmac_mutex);
+}
+
+static void
+radio_cmac_recv_cmd(void) __reentrant
+{
+ uint8_t len, i;
+ uint16_t timeout;
+
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ len = ao_cmd_lex_i;
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ timeout = AO_MS_TO_TICKS(ao_cmd_lex_i);
+ ao_mutex_get(&ao_radio_cmac_mutex);
+ i = radio_cmac_recv(len, timeout);
+ if (i == AO_RADIO_CMAC_OK) {
+ printf ("PACKET ");
+ for (i = 0; i < len; i++)
+ printf("%02x", cmac_data[i]);
+ printf (" %d\n", ao_radio_cmac_rssi);
+ } else
+ printf ("ERROR %d %d\n", i, ao_radio_cmac_rssi);
+ ao_mutex_put(&ao_radio_cmac_mutex);
+}
+
+static __xdata struct ao_launch_command command;
+static __xdata struct ao_launch_query query;
+static pdata uint16_t launch_serial;
+static pdata uint8_t launch_channel;
+static pdata uint16_t tick_offset;
+
+static void
+launch_args(void) __reentrant
+{
+ ao_cmd_decimal();
+ launch_serial = ao_cmd_lex_i;
+ ao_cmd_decimal();
+ launch_channel = ao_cmd_lex_i;
+}
+
+static int8_t
+launch_query(void)
+{
+ uint8_t i;
+ int8_t r = AO_RADIO_CMAC_OK;
+
+ tick_offset = ao_time();
+ for (i = 0; i < 10; i++) {
+ printf ("."); flush();
+ command.tick = ao_time();
+ command.serial = launch_serial;
+ command.cmd = AO_LAUNCH_QUERY;
+ command.channel = launch_channel;
+ ao_radio_cmac_send(&command, sizeof (command));
+ r = ao_radio_cmac_recv(&query, sizeof (query), AO_MS_TO_TICKS(500));
+ if (r == AO_RADIO_CMAC_OK)
+ break;
+ }
+ tick_offset -= query.tick;
+ printf("\n"); flush();
+ return r;
+}
+
+static void
+launch_report_cmd(void) __reentrant
+{
+ int8_t r;
+
+ launch_args();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ r = launch_query();
+ switch (r) {
+ case AO_RADIO_CMAC_OK:
+ if (query.valid) {
+ switch (query.arm_status) {
+ case ao_igniter_ready:
+ case ao_igniter_active:
+ printf ("Armed: ");
+ break;
+ default:
+ printf("Disarmed: ");
+ }
+ switch (query.igniter_status) {
+ default:
+ printf("unknown\n");
+ break;
+ case ao_igniter_ready:
+ printf("igniter good\n");
+ break;
+ case ao_igniter_open:
+ printf("igniter bad\n");
+ break;
+ }
+ } else {
+ printf("Invalid channel %d\n", launch_channel);
+ }
+ printf("Rssi: %d\n", ao_radio_cmac_rssi);
+ break;
+ default:
+ printf("Error %d\n", r);
+ break;
+ }
+}
+
+static void
+launch_arm(void) __reentrant
+{
+ command.tick = ao_time() - tick_offset;
+ command.serial = launch_serial;
+ command.cmd = AO_LAUNCH_ARM;
+ command.channel = launch_channel;
+ ao_radio_cmac_send(&command, sizeof (command));
+}
+
+static void
+launch_ignite(void) __reentrant
+{
+ command.tick = ao_time() - tick_offset;
+ command.serial = launch_serial;
+ command.cmd = AO_LAUNCH_FIRE;
+ command.channel = 0;
+ ao_radio_cmac_send(&command, sizeof (command));
+}
+
+static void
+launch_fire_cmd(void) __reentrant
+{
+ static __xdata struct ao_launch_command command;
+ uint8_t secs;
+ uint8_t i;
+ int8_t r;
+
+ launch_args();
+ ao_cmd_decimal();
+ secs = ao_cmd_lex_i;
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ r = launch_query();
+ if (r != AO_RADIO_CMAC_OK) {
+ printf("query failed %d\n", r);
+ return;
+ }
+
+ for (i = 0; i < 4; i++) {
+ printf("arm %d\n", i); flush();
+ launch_arm();
+ }
+
+ secs = secs * 10 - 5;
+ if (secs > 100)
+ secs = 100;
+ for (i = 0; i < secs; i++) {
+ printf("fire %d\n", i); flush();
+ launch_ignite();
+ ao_delay(AO_MS_TO_TICKS(100));
+ }
+}
+
+static void
+launch_arm_cmd(void) __reentrant
+{
+ uint8_t i;
+ int8_t r;
+ launch_args();
+ r = launch_query();
+ if (r != AO_RADIO_CMAC_OK) {
+ printf("query failed %d\n", r);
+ return;
+ }
+ for (i = 0; i < 4; i++)
+ launch_arm();
+}
+
+static void
+launch_ignite_cmd(void) __reentrant
+{
+ uint8_t i;
+ launch_args();
+ for (i = 0; i < 4; i++)
+ launch_ignite();
+}
+
+static __code struct ao_cmds ao_radio_cmac_cmds[] = {
+ { radio_cmac_send_cmd, "s <length>\0Send AES-CMAC packet. Bytes to send follow on next line" },
+ { radio_cmac_recv_cmd, "S <length> <timeout>\0Receive AES-CMAC packet. Timeout in ms" },
+ { launch_report_cmd, "l <serial> <channel>\0Get remote launch status" },
+ { launch_fire_cmd, "f <serial> <channel> <secs>\0Fire remote igniter" },
+ { launch_arm_cmd, "a <serial> <channel>\0Arm remote igniter" },
+ { launch_ignite_cmd, "i <serial> <channel>\0Pulse remote igniter" },
+ { 0, NULL },
+};
+
+void
+ao_radio_cmac_init(void)
+{
+ ao_cmd_register(&ao_radio_cmac_cmds[0]);
+}
diff --git a/src/ao_main.c b/src/ao_telelaunch.c
index 25acccfc..506431de 100644
--- a/src/ao_main.c
+++ b/src/ao_telelaunch.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ * Copyright © 2011 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
@@ -16,6 +16,7 @@
*/
#include "ao.h"
+#include "ao_pins.h"
void
main(void)
@@ -23,21 +24,23 @@ main(void)
ao_clock_init();
/* Turn on the red LED until the system is stable */
- ao_led_init();
+ ao_led_init(LEDS_AVAILABLE);
ao_led_on(AO_LED_RED);
ao_timer_init();
ao_adc_init();
ao_beep_init();
ao_cmd_init();
- ao_ee_init();
- ao_flight_init();
- ao_log_init();
- ao_report_init();
+ ao_spi_init();
+ ao_storage_init();
ao_usb_init();
- ao_serial_init();
- ao_gps_init();
- ao_telemetry_init();
ao_radio_init();
+#if HAS_DBG
+ ao_dbg_init();
+#endif
+ ao_aes_init();
+ ao_radio_cmac_init();
+ ao_launch_init();
+ ao_config_init();
ao_start_scheduler();
}
diff --git a/src/avr-demo/Makefile b/src/avr-demo/Makefile
new file mode 100644
index 00000000..93295166
--- /dev/null
+++ b/src/avr-demo/Makefile
@@ -0,0 +1,105 @@
+#
+# AltOS build
+#
+#
+vpath % ..:../core:../product:../drivers:../avr
+vpath make-altitude ..
+vpath make-kalman ..
+vpath kalman.5c ../kalman
+vpath kalman_filter.5c ../kalman
+vpath load_csv.5c ../kalman
+vpath matrix.5c ../kalman
+vpath ao-make-product.5c ../util
+
+MCU=atmega32u4
+DUDECPUTYPE=m32u4
+#PROGRAMMER=stk500v2 -P usb
+PROGRAMMER=usbtiny
+LOADCMD=avrdude
+LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
+CC=avr-gcc
+OBJCOPY=avr-objcopy
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ altitude.h \
+ ao_kalman.h
+
+#
+# Common AltOS sources
+#
+ALTOS_SRC = \
+ ao_cmd.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_product.c \
+ ao_romconfig.c \
+ ao_serial_avr.c \
+ ao_avr_stdio.c \
+ ao_stdio.c \
+ ao_task.c \
+ ao_timer.c \
+ ao_led.c \
+ ao_usb_avr.c \
+ ao_lcd.c
+
+PRODUCT=AvrDemo-v0.0
+MCU=atmega32u4
+PRODUCT_DEF=-DAVR_DEMO
+IDPRODUCT=0x000a
+CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../core -I..
+CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -Os -mcall-prologues
+
+NICKLE=nickle
+
+PROG=avr-demo
+
+SRC=$(ALTOS_SRC) ao_demo.c ao_debug_avr.c
+OBJ=$(SRC:.c=.o)
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: $(PROG)
+
+$(PROG): Makefile $(OBJ)
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ)
+
+$(PROG).hex: $(PROG)
+ avr-size $(PROG)
+ $(OBJCOPY) -R .eeprom -O ihex $(PROG) $@
+
+
+load: $(PROG).hex
+ $(LOADCMD) $(LOADARG)$(PROG).hex
+
+../altitude.h: make-altitude
+ nickle $< > $@
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+ao_product.rel: ao_product.c ao_product.h
+ $(call quiet,CC) -c $(CFLAGS) -D PRODUCT_DEFS='\"ao_product.h\"' -o$@ $<
+
+distclean: clean
+
+clean:
+ rm -f $(OBJ)
+ rm -f ao_product.h
+
+install:
+
+uninstall:
+
+$(OBJ): ao.h ao_product.h \ No newline at end of file
diff --git a/src/avr-demo/ao_demo.c b/src/avr-demo/ao_demo.c
new file mode 100644
index 00000000..756dd0d4
--- /dev/null
+++ b/src/avr-demo/ao_demo.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+struct ao_task demo_task;
+
+void
+ao_demo(void)
+{
+ for (;;) {
+ ao_led_toggle(AO_LED_RED);
+ printf ("hello %d\n", ao_time());
+ ao_delay(AO_MS_TO_TICKS(200));
+ }
+}
+
+int
+main(void)
+{
+ ao_clock_init();
+
+ ao_serial_init();
+
+ ao_led_init(LEDS_AVAILABLE);
+ ao_avr_stdio_init();
+ printf ("stdio initialized\n");
+// ao_debug_init();
+ ao_timer_init();
+ ao_cmd_init();
+ ao_usb_init();
+ ao_lcd_init();
+
+// ao_add_task(&demo_task, ao_demo, "demo");
+ /* Turn on the LED until the system is stable */
+ ao_start_scheduler();
+ return 0;
+}
diff --git a/src/avr/ao_adc_avr.c b/src/avr/ao_adc_avr.c
new file mode 100644
index 00000000..8c0cade0
--- /dev/null
+++ b/src/avr/ao_adc_avr.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING];
+volatile __data uint8_t ao_adc_head;
+
+#ifdef TELESCIENCE
+const uint8_t adc_channels[AO_LOG_TELESCIENCE_NUM_ADC] = {
+ 0x00,
+ 0x01,
+ 0x04,
+ 0x05,
+ 0x06,
+ 0x07,
+ 0x20,
+ 0x21,
+ 0x22,
+ 0x23,
+ 0x24,
+ 0x25,
+};
+#endif
+
+#ifdef TELEPYRO
+const uint8_t adc_channels[AO_TELEPYRO_NUM_ADC] = {
+ 0x00, /* ADC0 v_batt */
+ 0x04, /* ADC4 sense_a */
+ 0x05, /* ADC5 sense_b */
+ 0x06, /* ADC6 sense_c */
+ 0x07, /* ADC7 sense_d */
+ 0x23, /* ADC11 sense_e */
+ 0x22, /* ADC10 sense_f */
+ 0x21, /* ADC9 sense_g */
+ 0x20, /* ADC8 sense_h */
+};
+#endif
+
+#define NUM_ADC (sizeof (adc_channels) / sizeof (adc_channels[0]))
+
+static uint8_t ao_adc_channel;
+
+#define ADC_CHANNEL_LOW(c) (((c) & 0x1f) << MUX0)
+#define ADC_CHANNEL_HIGH(c) ((((c) & 0x20) >> 5) << MUX5)
+
+#define ADCSRA_INIT ((1 << ADEN) | /* Enable ADC */ \
+ (0 << ADATE) | /* No auto ADC trigger */ \
+ (1 << ADIF) | /* Clear interrupt */ \
+ (0 << ADIE) | /* Enable interrupt */ \
+ (6 << ADPS0)) /* Prescale clock by 64 */
+
+#define ADCSRB_INIT ((0 << ADHSM) | /* No high-speed mode */ \
+ (0 << ACME) | /* Some comparitor thing */ \
+ (0 << ADTS0)) /* Free running mode (don't care) */
+
+static void
+ao_adc_start(void)
+{
+ uint8_t channel = adc_channels[ao_adc_channel];
+ ADMUX = ((0 << REFS1) | /* AVcc reference */
+ (1 << REFS0) | /* AVcc reference */
+ (1 << ADLAR) | /* Left-shift results */
+ (ADC_CHANNEL_LOW(channel))); /* Select channel */
+
+ ADCSRB = (ADCSRB_INIT |
+ ADC_CHANNEL_HIGH(channel)); /* High channel bit */
+
+ ADCSRA = (ADCSRA_INIT |
+ (1 << ADSC) |
+ (1 << ADIE)); /* Start conversion */
+}
+
+ISR(ADC_vect)
+{
+ uint16_t value;
+
+ /* Must read ADCL first or the value there will be lost */
+ value = ADCL;
+ value |= (ADCH << 8);
+ ao_adc_ring[ao_adc_head].adc[ao_adc_channel] = value;
+ if (++ao_adc_channel < NUM_ADC)
+ ao_adc_start();
+ else {
+ ADCSRA = ADCSRA_INIT;
+ ao_adc_ring[ao_adc_head].tick = ao_time();
+ ao_adc_head = ao_adc_ring_next(ao_adc_head);
+ ao_wakeup((void *) &ao_adc_head);
+ ao_cpu_sleep_disable = 0;
+ }
+}
+
+void
+ao_adc_poll(void)
+{
+ ao_cpu_sleep_disable = 1;
+ ao_adc_channel = 0;
+ ao_adc_start();
+}
+
+void
+ao_adc_get(__xdata struct ao_adc *packet)
+{
+ uint8_t i = ao_adc_ring_prev(ao_adc_head);
+ memcpy(packet, (void *) &ao_adc_ring[i], sizeof (struct ao_adc));
+}
+
+static void
+ao_adc_dump(void) __reentrant
+{
+ static __xdata struct ao_adc packet;
+ uint8_t i;
+ ao_adc_get(&packet);
+#ifdef TELEPYRO
+ printf("ADMUX: %02x\n", ADMUX);
+ printf("ADCSRA: %02x\n", ADCSRA);
+ printf("ADCSRB: %02x\n", ADCSRB);
+ printf("DIDR0: %02x\n", DIDR0);
+ printf("DIDR2: %02x\n", DIDR2);
+ printf("PORTF: %02x\n", PORTF);
+ printf("DDRF: %02x\n", DDRF);
+ printf("PINF: %02x\n", PINF);
+#endif
+ printf("tick: %5u", packet.tick);
+ for (i = 0; i < NUM_ADC; i++)
+ printf (" %2d: %5u", i, packet.adc[i]);
+
+
+#ifdef TELEPYRO
+ ADMUX = 0x60;
+ ADCSRB = 0x00;
+ ADCSRA = 0xc6;
+ while (ADCSRA & 0x40)
+ ;
+ printf ("ADCL: %02x\n", ADCL);
+ printf ("ADCH: %02x\n", ADCH);
+ printf ("\n");
+#endif
+}
+
+__code struct ao_cmds ao_adc_cmds[] = {
+ { ao_adc_dump, "a\0Display current ADC values" },
+ { 0, NULL },
+};
+
+void
+ao_adc_init(void)
+{
+ DIDR0 = 0xf3;
+ DIDR2 = 0x3f;
+ ADCSRB = ADCSRB_INIT;
+ ADCSRA = ADCSRA_INIT;
+ ao_cmd_register(&ao_adc_cmds[0]);
+}
diff --git a/src/avr/ao_arch.h b/src/avr/ao_arch.h
new file mode 100644
index 00000000..c695a725
--- /dev/null
+++ b/src/avr/ao_arch.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_ARCH_H_
+#define _AO_ARCH_H_
+
+#include <stdio.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/sleep.h>
+
+#ifdef AVR_DEMO
+#define TEENSY 1
+#endif
+
+#if TEENSY
+#define F_CPU 16000000UL // 16 MHz
+#else
+#define F_CPU 8000000UL // 8 MHz
+#endif
+
+/*
+ * AVR definitions and code fragments for AltOS
+ */
+
+#define AO_STACK_SIZE 128
+
+/* Various definitions to make GCC look more like SDCC */
+
+#define ao_arch_naked_declare __attribute__((naked))
+#define ao_arch_naked_define
+#define __pdata
+#define __data
+#define __xdata
+#define __code const
+#define __reentrant
+#define __critical
+#define __interrupt(n)
+#define __at(n)
+
+#define ao_arch_reboot() /* XXX */
+
+#define ao_arch_nop() asm("nop")
+
+#define ao_arch_interrupt(n) /* nothing */
+
+#undef putchar
+#undef getchar
+#define putchar(c) ao_putchar(c)
+#define getchar ao_getchar
+
+extern void putchar(char c);
+extern char getchar(void);
+extern void ao_avr_stdio_init(void);
+
+extern const uint16_t ao_serial_number;
+
+#define AVR_PUSH8(stack, val) (*((stack)--) = (val))
+
+extern uint8_t ao_cpu_sleep_disable;
+
+#define ao_arch_task_globals uint8_t ao_cpu_sleep_disable;
+
+#define ao_arch_task_members\
+ uint8_t *sp; /* saved stack pointer */
+
+#define ao_arch_init_stack(task, start) do { \
+ uint8_t *sp = task->stack + AO_STACK_SIZE - 1; \
+ uint16_t a = (uint16_t) start; \
+ int i; \
+ \
+ /* Return address */ \
+ AVR_PUSH8(sp, a); \
+ AVR_PUSH8(sp, (a >> 8)); \
+ \
+ /* Clear register values */ \
+ i = 32; \
+ while (i--) \
+ AVR_PUSH8(sp, 0); \
+ \
+ /* SREG with interrupts enabled */ \
+ AVR_PUSH8(sp, 0x80); \
+ task->sp = sp; \
+} while (0);
+
+#define ao_arch_save_regs() do { \
+ asm("push r31" "\n\t" "push r30"); \
+ asm("push r29" "\n\t" "push r28" "\n\t" "push r27" "\n\t" "push r26" "\n\t" "push r25"); \
+ asm("push r24" "\n\t" "push r23" "\n\t" "push r22" "\n\t" "push r21" "\n\t" "push r20"); \
+ asm("push r19" "\n\t" "push r18" "\n\t" "push r17" "\n\t" "push r16" "\n\t" "push r15"); \
+ asm("push r14" "\n\t" "push r13" "\n\t" "push r12" "\n\t" "push r11" "\n\t" "push r10"); \
+ asm("push r9" "\n\t" "push r8" "\n\t" "push r7" "\n\t" "push r6" "\n\t" "push r5"); \
+ asm("push r4" "\n\t" "push r3" "\n\t" "push r2" "\n\t" "push r1" "\n\t" "push r0"); \
+ cli(); \
+ asm("in r0, __SREG__" "\n\t" "push r0"); \
+ sei(); \
+ } while (0)
+
+#define ao_arch_save_stack() do { \
+ uint8_t sp_l, sp_h; \
+ asm("in %0,__SP_L__" : "=&r" (sp_l) ); \
+ asm("in %0,__SP_H__" : "=&r" (sp_h) ); \
+ ao_cur_task->sp = (uint8_t *) ((uint16_t) sp_l | ((uint16_t) sp_h << 8)); \
+ } while (0)
+
+#define ao_arch_isr_stack() /* nothing */
+
+#define ao_arch_cpu_idle() do { \
+ if (!ao_cpu_sleep_disable) \
+ sleep_cpu(); \
+ } while (0)
+
+#define ao_arch_restore_stack() do { \
+ uint8_t sp_l, sp_h; \
+ sp_l = (uint16_t) ao_cur_task->sp; \
+ sp_h = ((uint16_t) ao_cur_task->sp) >> 8; \
+ cli(); \
+ asm("out __SP_H__,%0" : : "r" (sp_h) ); \
+ asm("out __SP_L__,%0" : : "r" (sp_l) ); \
+ asm("pop r0" "\n\t" \
+ "out __SREG__, r0"); \
+ asm("pop r0" "\n\t" "pop r1" "\n\t" "pop r2" "\n\t" "pop r3" "\n\t" "pop r4"); \
+ asm("pop r5" "\n\t" "pop r6" "\n\t" "pop r7" "\n\t" "pop r8" "\n\t" "pop r9"); \
+ asm("pop r10" "\n\t" "pop r11" "\n\t" "pop r12" "\n\t" "pop r13" "\n\t" "pop r14"); \
+ asm("pop r15" "\n\t" "pop r16" "\n\t" "pop r17" "\n\t" "pop r18" "\n\t" "pop r19"); \
+ asm("pop r20" "\n\t" "pop r21" "\n\t" "pop r22" "\n\t" "pop r23" "\n\t" "pop r24"); \
+ asm("pop r25" "\n\t" "pop r26" "\n\t" "pop r27" "\n\t" "pop r28" "\n\t" "pop r29"); \
+ asm("pop r30" "\n\t" "pop r31"); \
+ asm("ret"); \
+ } while(0)
+
+#define ao_arch_critical(b) do { cli(); b; sei(); } while (0)
+
+#define AO_TELESCIENCE_NUM_ADC 12
+
+struct ao_adc {
+ uint16_t tick; /* tick when the sample was read */
+ uint16_t adc[AO_TELESCIENCE_NUM_ADC]; /* samples */
+};
+
+#define AO_ADC_RING 16
+
+#endif /* _AO_ARCH_H_ */
+
diff --git a/src/avr/ao_avr_stdio.c b/src/avr/ao_avr_stdio.c
new file mode 100644
index 00000000..ba562dbf
--- /dev/null
+++ b/src/avr/ao_avr_stdio.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+int
+stdio_put(char c, FILE *stream)
+{
+ if (ao_cur_task && ao_num_stdios)
+ putchar(c);
+ else
+ {
+ if (c == '\n')
+ stdio_put('\r', stream);
+ loop_until_bit_is_set(UCSR1A, UDRE1);
+ UDR1 = c;
+ }
+
+ return 0;
+}
+
+int
+stdio_get(FILE *stream)
+{
+ return (int) getchar() & 0xff;
+}
+
+static FILE mystdout = FDEV_SETUP_STREAM(stdio_put, NULL, _FDEV_SETUP_WRITE);
+
+static FILE mystdin = FDEV_SETUP_STREAM(NULL, stdio_get, _FDEV_SETUP_READ);
+
+void
+ao_avr_stdio_init(void)
+{
+ stdout = &mystdout;
+ stdin = &mystdin;
+ printf("%d stdios registered\n", ao_num_stdios);
+}
diff --git a/src/avr/ao_clock.c b/src/avr/ao_clock.c
new file mode 100644
index 00000000..0d42b6d5
--- /dev/null
+++ b/src/avr/ao_clock.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+/*
+ * AltOS always cranks the clock to the max frequency
+ */
+
+void
+ao_clock_init(void)
+{
+ /* disable RC clock */
+ CLKSEL0 &= ~(1 << RCE);
+
+ /* Disable PLL */
+ PLLCSR &= ~(1 << PLLE);
+
+ /* Enable external clock */
+ CLKSEL0 |= (1 << EXTE);
+
+ /* wait for external clock to be ready */
+ while ((CLKSTA & (1 << EXTON)) == 0)
+ ;
+
+ /* select external clock */
+ CLKSEL0 |= (1 << CLKS);
+
+ /* Disable the clock prescaler */
+ cli();
+ CLKPR = (1 << CLKPCE);
+
+ /* Always run the system clock at 8MHz */
+#if AVR_CLOCK > 12000000UL
+ CLKPR = 1;
+#else
+ CLKPR = 0;
+#endif
+ sei();
+
+ /* Set up the PLL to use the crystal */
+
+ /* Use primary system clock as PLL source */
+ PLLFRQ = ((0 << PINMUX) | /* Use primary clock */
+ (0 << PLLUSB) | /* No divide by 2 for USB */
+ (0 << PLLTM0) | /* Disable high speed timer */
+ (0x4 << PDIV0)); /* 48MHz PLL clock */
+
+ /* Set the frequency of the crystal */
+#if AVR_CLOCK > 12000000UL
+ PLLCSR |= (1 << PINDIV); /* For 16MHz crystal on Teensy board */
+#else
+ PLLCSR &= ~(1 << PINDIV); /* For 8MHz crystal on TeleScience board */
+#endif
+
+ /* Enable the PLL */
+ PLLCSR |= (1 << PLLE);
+ while (!(PLLCSR & (1 << PLOCK)))
+ ;
+
+ set_sleep_mode(SLEEP_MODE_IDLE);
+ sleep_enable();
+}
diff --git a/src/avr/ao_debug_avr.c b/src/avr/ao_debug_avr.c
new file mode 100644
index 00000000..2e41e15a
--- /dev/null
+++ b/src/avr/ao_debug_avr.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+void
+uart_send(char c)
+{
+ loop_until_bit_is_set(UCSR1A, UDRE1);
+ UDR1 = c;
+}
+
+int
+uart_put(char c, FILE *stream)
+{
+ if (c == '\n')
+ uart_send('\r');
+ uart_send(c);
+ return 0;
+}
+
+int
+uart_get(FILE *stream)
+{
+ loop_until_bit_is_set(UCSR1A, RXC1);
+ return (int) UDR1 & 0xff;
+}
+
+void
+uart_init(uint16_t baud)
+{
+ PRR1 &= ~(1 << PRUSART1);
+ UBRR1L = baud;
+ UBRR1H = baud >> 8;
+ UCSR1A = 0;
+ UCSR1B = ((1 << RXEN1) | /* Enable receiver */
+ (1 << TXEN1)); /* Enable transmitter */
+ UCSR1C = ((0 << UMSEL10) | /* Asynchronous mode */
+ (0 << UPM10) | /* No parity */
+ (0 << USBS1) | /* 1 stop bit */
+ (3 << UCSZ10) | /* 8 bit characters */
+ (0 << UCPOL1)); /* MBZ for async mode */
+}
+
+static FILE mystdout = FDEV_SETUP_STREAM(uart_put, NULL, _FDEV_SETUP_WRITE);
+
+static FILE mystdin = FDEV_SETUP_STREAM(NULL, uart_get, _FDEV_SETUP_READ);
+
+void ao_debug_init(void)
+{
+ uart_init(F_CPU / (16UL * 9600UL) - 1);
+
+ stdout = &mystdout;
+ stdin = &mystdin;
+
+ if (DDRB & AO_LED_RED) {
+ printf ("oops, starting all over\n");
+ for (;;)
+ ;
+ }
+ DDRB |= (1 << 7);
+ PORTB |= (1 << 7);
+ printf ("debug initialized\n");
+}
diff --git a/src/avr/ao_led.c b/src/avr/ao_led.c
new file mode 100644
index 00000000..91dfb85e
--- /dev/null
+++ b/src/avr/ao_led.c
@@ -0,0 +1,67 @@
+/*
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+__pdata uint8_t ao_led_enable;
+
+#define LED_PORT PORTB
+#define LED_DDR DDRB
+
+void
+ao_led_on(uint8_t colors)
+{
+ LED_PORT |= (colors & ao_led_enable);
+}
+
+void
+ao_led_off(uint8_t colors)
+{
+ LED_PORT &= ~(colors & ao_led_enable);
+}
+
+void
+ao_led_set(uint8_t colors)
+{
+ LED_PORT = (LED_PORT & ~(ao_led_enable)) | (colors & ao_led_enable);
+}
+
+void
+ao_led_toggle(uint8_t colors)
+{
+ LED_PORT ^= (colors & ao_led_enable);
+}
+
+void
+ao_led_for(uint8_t colors, uint16_t ticks) __reentrant
+{
+ ao_led_on(colors);
+ ao_delay(ticks);
+ ao_led_off(colors);
+}
+
+void
+ao_led_init(uint8_t enable)
+{
+ ao_led_enable = enable;
+ if ((LED_DDR & enable)) {
+ printf ("oops! restarted\n");
+ ao_panic(AO_PANIC_REBOOT);
+ }
+ LED_PORT &= ~enable;
+ LED_DDR |= enable;
+}
diff --git a/src/avr/ao_pins.h b/src/avr/ao_pins.h
new file mode 100644
index 00000000..6b72530b
--- /dev/null
+++ b/src/avr/ao_pins.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#ifdef AVR_DEMO
+ #define AO_LED_RED (1<<7)
+ #define LEDS_AVAILABLE (AO_LED_RED)
+ #define USE_SERIAL_STDIN 1
+ #define HAS_USB 1
+ #define PACKET_HAS_SLAVE 0
+ #define HAS_SERIAL_1 1
+ #define TEENSY 1
+ #define AVR_VCC_5V 1
+ #define AVR_VCC_3V3 0
+ #define AVR_CLOCK 16000000UL
+ #define HAS_BEEP 0
+#endif
+
+#ifdef TELESCIENCE
+ #define LEDS_AVAILABLE 0
+ #define HAS_USB 1
+ #define HAS_LOG 1
+ #define TEENSY 0
+ #define USE_SERIAL_STDIN 1
+ #define HAS_SERIAL_1 1
+ #define HAS_USB 1
+ #define HAS_ADC 1
+ #define PACKET_HAS_SLAVE 0
+ #define HAS_BEEP 0
+
+ #define AVR_VCC_5V 0
+ #define AVR_VCC_3V3 1
+ #define AVR_CLOCK 8000000UL
+
+ #define SPI_CS_PORT PORTE
+ #define SPI_CS_DIR DDRE
+ #define M25_CS_MASK (1 << PORTE6)
+ #define M25_MAX_CHIPS 1
+
+ #define SPI_SLAVE_CS_PORT PORTB
+ #define SPI_SLAVE_CS_PIN PINB
+ #define SPI_SLAVE_CS_PIN_NO PINB0
+
+ #define SPI_SLAVE_PIN_0_3 1
+ #define SPI_SLAVE_PIN_2_5 0
+#endif
+
+#ifdef TELEPYRO
+ #define LEDS_AVAILABLE 0
+ #define HAS_USB 1
+ #define HAS_LOG 0
+ #define TEENSY 0
+ #define USE_SERIAL_STDIN 1
+ #define HAS_SERIAL_1 1
+ #define HAS_USB 1
+ #define HAS_ADC 1
+ #define PACKET_HAS_SLAVE 0
+ #define HAS_BEEP 0
+
+ #define AVR_VCC_5V 0
+ #define AVR_VCC_3V3 1
+ #define AVR_CLOCK 8000000UL
+
+ #define SPI_SLAVE_CS_PORT PORTB
+ #define SPI_SLAVE_CS_PIN PINB
+ #define SPI_SLAVE_CS_PIN_NO PINB0
+
+ #define SPI_SLAVE_PIN_0_3 1
+ #define SPI_SLAVE_PIN_2_5 0
+#endif
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/ao_log_telem.c b/src/avr/ao_romconfig.c
index 1b472efe..bbb677e2 100644
--- a/src/ao_log_telem.c
+++ b/src/avr/ao_romconfig.c
@@ -17,14 +17,4 @@
#include "ao.h"
-void
-ao_log_write_erase(uint8_t pos)
-{
- (void) pos;
-}
-
-uint8_t
-ao_log_present(void)
-{
- return 0;
-}
+const uint16_t ao_serial_number = 0;
diff --git a/src/avr/ao_serial_avr.c b/src/avr/ao_serial_avr.c
new file mode 100644
index 00000000..2fe39755
--- /dev/null
+++ b/src/avr/ao_serial_avr.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+__xdata struct ao_fifo ao_usart1_rx_fifo;
+__xdata struct ao_fifo ao_usart1_tx_fifo;
+
+void
+ao_debug_out(char c)
+{
+ if (c == '\n')
+ ao_debug_out('\r');
+ loop_until_bit_is_set(UCSR1A, UDRE1);
+ UDR1 = c;
+}
+
+ISR(USART1_RX_vect)
+{
+ if (!ao_fifo_full(ao_usart1_rx_fifo))
+ ao_fifo_insert(ao_usart1_rx_fifo, UDR1);
+ ao_wakeup(&ao_usart1_rx_fifo);
+#if USE_SERIAL_STDIN
+ ao_wakeup(&ao_stdin_ready);
+#endif
+}
+
+static __xdata uint8_t ao_serial_tx1_started;
+
+static void
+ao_serial_tx1_start(void)
+{
+ if (!ao_fifo_empty(ao_usart1_tx_fifo) &&
+ !ao_serial_tx1_started)
+ {
+ ao_serial_tx1_started = 1;
+ ao_fifo_remove(ao_usart1_tx_fifo, UDR1);
+ }
+}
+
+ISR(USART1_UDRE_vect)
+{
+ ao_serial_tx1_started = 0;
+ ao_serial_tx1_start();
+ ao_wakeup(&ao_usart1_tx_fifo);
+}
+
+char
+ao_serial_getchar(void) __critical
+{
+ char c;
+ cli();
+ while (ao_fifo_empty(ao_usart1_rx_fifo))
+ ao_sleep(&ao_usart1_rx_fifo);
+ ao_fifo_remove(ao_usart1_rx_fifo, c);
+ sei();
+ return c;
+}
+
+#if USE_SERIAL_STDIN
+char
+ao_serial_pollchar(void) __critical
+{
+ char c;
+ cli();
+ if (ao_fifo_empty(ao_usart1_rx_fifo)) {
+ sei();
+ return AO_READ_AGAIN;
+ }
+ ao_fifo_remove(ao_usart1_rx_fifo,c);
+ sei();
+ return c;
+}
+#endif
+
+void
+ao_serial_putchar(char c) __critical
+{
+ cli();
+ while (ao_fifo_full(ao_usart1_tx_fifo))
+ ao_sleep(&ao_usart1_tx_fifo);
+ ao_fifo_insert(ao_usart1_tx_fifo, c);
+ ao_serial_tx1_start();
+ sei();
+}
+
+void
+ao_serial_drain(void) __critical
+{
+ cli();
+ while (!ao_fifo_empty(ao_usart1_tx_fifo))
+ ao_sleep(&ao_usart1_tx_fifo);
+ sei();
+}
+
+static const struct {
+ uint16_t ubrr;
+} ao_serial_speeds[] = {
+ /* [AO_SERIAL_SPEED_4800] = */ {
+ F_CPU / (16UL * 4800UL) - 1
+ },
+ /* [AO_SERIAL_SPEED_9600] = */ {
+ F_CPU / (16UL * 9600UL) - 1
+ },
+ /* [AO_SERIAL_SPEED_19200] = */ {
+ F_CPU / (16UL * 19200UL) - 1
+ },
+ /* [AO_SERIAL_SPEED_57600] = */ {
+ F_CPU / (16UL * 57600UL) - 1
+ },
+};
+
+void
+ao_serial_set_speed(uint8_t speed)
+{
+ ao_serial_drain();
+ if (speed > AO_SERIAL_SPEED_57600)
+ return;
+ UBRR1L = ao_serial_speeds[speed].ubrr;
+ UBRR1H = ao_serial_speeds[speed].ubrr >> 8;
+}
+
+void
+ao_serial_init(void)
+{
+ /* Ensure the uart is powered up */
+
+ PRR1 &= ~(1 << PRUSART1);
+
+ /* Pick a 9600 baud rate */
+ ao_serial_set_speed(AO_SERIAL_SPEED_9600);
+
+ UCSR1A = 0;
+ UCSR1C = ((0 << UMSEL10) | /* Asynchronous mode */
+ (0 << UPM10) | /* No parity */
+ (0 << USBS1) | /* 1 stop bit */
+ (3 << UCSZ10) | /* 8 bit characters */
+ (0 << UCPOL1)); /* MBZ for async mode */
+ UCSR1B = ((1 << RXEN1) | /* Enable receiver */
+ (1 << TXEN1) | /* Enable transmitter */
+ (1 << RXCIE1) | /* Enable receive interrupts */
+ (1 << UDRIE1)); /* Enable transmit empty interrupts */
+#if 0
+#if USE_SERIAL_STDIN
+ int8_t i;
+ i = ao_add_stdio(ao_serial_pollchar,
+ ao_serial_putchar,
+ NULL);
+ printf("Register serial stdio as %d\n", i);
+#endif
+#endif
+}
diff --git a/src/avr/ao_spi_slave.c b/src/avr/ao_spi_slave.c
new file mode 100644
index 00000000..76f574c6
--- /dev/null
+++ b/src/avr/ao_spi_slave.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+uint8_t
+ao_spi_read(uint8_t *buf, uint8_t len)
+{
+ while (len--) {
+ while (!(SPSR & (1 << SPIF)))
+ if ((PINB & (1 << PINB0)))
+ return 0;
+ *buf++ = SPDR;
+ }
+ return 1;
+}
+
+void
+ao_spi_write(uint8_t *buf, uint8_t len)
+{
+ while (len--) {
+ SPDR = *buf++;
+ while (!(SPSR & (1 << SPIF)))
+ if ((PINB & (1 << PINB0)))
+ return;
+ }
+ /* Clear pending SPIF bit by reading */
+ (void) SPDR;
+}
+
+static uint8_t ao_spi_slave_running;
+
+ISR(PCINT0_vect)
+{
+ cli();
+#if SPI_SLAVE_PIN_0_3
+ if ((PINB & (1 << PORTB0)) == 0)
+#endif
+#if SPI_SLAVE_PIN_2_5
+ if ((PINB & (1 << PORTB2)) == 0)
+#endif
+ {
+ if (!ao_spi_slave_running) {
+ ao_spi_slave_running = 1;
+ ao_spi_slave();
+ }
+ } else {
+ ao_spi_slave_running = 0;
+ }
+ sei();
+}
+
+void
+ao_spi_slave_init(void)
+{
+ /* We'd like to have a pull-up on SS so that disconnecting the
+ * TM would cause any SPI transaction to abort. However, when
+ * I tried that, SPI transactions would spontaneously abort,
+ * making me assume that we needed a less aggressive pull-up
+ * than is offered inside the AVR
+ */
+#if SPI_SLAVE_PIN_0_3
+ PCMSK0 |= (1 << PCINT0); /* Enable PCINT0 pin change */
+ PCICR |= (1 << PCIE0); /* Enable pin change interrupt */
+
+ DDRB = ((DDRB & 0xf0) |
+ (1 << 3) | /* MISO, output */
+ (0 << 2) | /* MOSI, input */
+ (0 << 1) | /* SCK, input */
+ (0 << 0)); /* SS, input */
+
+ PORTB = ((PORTB & 0xf0) |
+ (1 << 3) | /* MISO, output */
+ (0 << 2) | /* MOSI, no pull-up */
+ (0 << 1) | /* SCK, no pull-up */
+ (0 << 0)); /* SS, no pull-up */
+#endif
+#if SPI_SLAVE_PIN_2_5
+ PCMSK0 |= (1 << PCINT2); /* Enable PCINT2 pin change */
+ PCICR |= (1 << PCIE0); /* Enable pin change interrupt */
+
+ DDRB = ((DDRB & 0xf0) |
+ (0 << 5) | /* SCK, input */
+ (1 << 4) | /* MISO, output */
+ (0 << 3) | /* MOSI, input */
+ (0 << 2)); /* SS, input */
+
+ PORTB = ((PORTB & 0xf0) |
+ (0 << 5) | /* SCK, no pull-up */
+ (1 << 4) | /* MISO, output */
+ (0 << 3) | /* MOSI, no pull-up */
+ (0 << 2)); /* SS, no pull-up */
+#endif
+
+ SPCR = (0 << SPIE) | /* Disable SPI interrupts */
+ (1 << SPE) | /* Enable SPI */
+ (0 << DORD) | /* MSB first */
+ (0 << MSTR) | /* Slave mode */
+ (0 << CPOL) | /* Clock low when idle */
+ (0 << CPHA); /* Sample at leading clock edge */
+}
diff --git a/src/avr/ao_spi_usart.c b/src/avr/ao_spi_usart.c
new file mode 100644
index 00000000..6ed708ff
--- /dev/null
+++ b/src/avr/ao_spi_usart.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+/*
+ * Atmega32u4 USART in MSPIM (master SPI mode)
+ */
+
+__xdata uint8_t ao_spi_mutex;
+
+/* Send bytes over SPI.
+ *
+ * This just polls; the SPI is set to go as fast as possible,
+ * so using interrupts would take way too long
+ */
+void
+ao_spi_send(void __xdata *block, uint16_t len) __reentrant
+{
+ uint8_t *d = block;
+
+ ao_mutex_get(&ao_spi_mutex);
+ while (len--) {
+ while (!(UCSR1A & (1 << UDRE1)));
+ UDR1 = *d++;
+ while (!(UCSR1A & (1 << RXC1)));
+ (void) UDR1;
+ }
+ ao_mutex_put(&ao_spi_mutex);
+}
+
+/* Receive bytes over SPI.
+ *
+ * This sets up tow DMA engines, one reading the data and another
+ * writing constant values to the SPI transmitter as that is what
+ * clocks the data coming in.
+ */
+void
+ao_spi_recv(void __xdata *block, uint16_t len) __reentrant
+{
+ uint8_t *d = block;
+
+ ao_mutex_get(&ao_spi_mutex);
+ while (len--) {
+ while (!(UCSR1A & (1 << UDRE1)));
+ UDR1 = 0;
+ while (!(UCSR1A & (1 << RXC1)));
+ *d++ = UDR1;
+ }
+ ao_mutex_put(&ao_spi_mutex);
+}
+
+/*
+ * Initialize USART0 for SPI using config alt 2
+ *
+ * MO P1_5
+ * MI P1_4
+ * CLK P1_3
+ *
+ * Chip select is the responsibility of the caller
+ */
+
+#define XCK1_DDR DDRD
+#define XCK1_PORT PORTD
+#define XCK1 PORTD5
+#define XMS1_DDR DDRE
+#define XMS1_PORT PORTE
+#define XMS1 PORTE6
+
+void
+ao_spi_init(void)
+{
+ /* Ensure the USART is powered */
+ PRR1 &= ~(1 << PRUSART1);
+
+ /*
+ * Set pin directions
+ */
+ XCK1_DDR |= (1 << XCK1);
+
+ /* Clear chip select (which is negated) */
+ XMS1_PORT |= (1 < XMS1);
+ XMS1_DDR |= (1 << XMS1);
+
+ /* Set baud register to zero (required before turning transmitter on) */
+ UBRR1 = 0;
+
+ UCSR1C = ((0x3 << UMSEL10) | /* Master SPI mode */
+ (0 << UCSZ10) | /* SPI mode 0 */
+ (0 << UCPOL1)); /* SPI mode 0 */
+
+ /* Enable transmitter and receiver */
+ UCSR1B = ((1 << RXEN1) |
+ (1 << TXEN1));
+
+ /* It says that 0 is a legal value; we'll see... */
+ UBRR1 = 0;
+}
diff --git a/src/avr/ao_timer.c b/src/avr/ao_timer.c
new file mode 100644
index 00000000..eef14345
--- /dev/null
+++ b/src/avr/ao_timer.c
@@ -0,0 +1,89 @@
+/*
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+static volatile __data uint16_t ao_tick_count;
+
+uint16_t ao_time(void)
+{
+ uint16_t v;
+ ao_arch_critical(
+ v = ao_tick_count;
+ );
+ return v;
+}
+
+static __xdata uint8_t ao_forever;
+
+void
+ao_delay(uint16_t ticks)
+{
+ ao_alarm(ticks);
+ ao_sleep(&ao_forever);
+}
+
+#define T1_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */
+#define T1_SAMPLE_TIME 30000 /* 3e6/30000 = 100 */
+
+#if HAS_ADC
+volatile __data uint8_t ao_adc_interval = 1;
+volatile __data uint8_t ao_adc_count;
+#endif
+
+void
+ao_debug_out(char c);
+
+ISR(TIMER1_COMPA_vect)
+{
+ ++ao_tick_count;
+#if HAS_ADC
+ if (++ao_adc_count == ao_adc_interval) {
+ ao_adc_count = 0;
+ ao_adc_poll();
+ }
+#endif
+}
+
+#if HAS_ADC
+void
+ao_timer_set_adc_interval(uint8_t interval) __critical
+{
+ ao_adc_interval = interval;
+ ao_adc_count = 0;
+}
+#endif
+
+void
+ao_timer_init(void)
+{
+ TCCR1A = ((0 << WGM11) | /* CTC mode, OCR1A */
+ (0 << WGM10)); /* CTC mode, OCR1A */
+ TCCR1B = ((0 << ICNC1) | /* no input capture noise canceler */
+ (0 << ICES1) | /* input capture on falling edge (don't care) */
+ (0 << WGM13) | /* CTC mode, OCR1A */
+ (1 << WGM12) | /* CTC mode, OCR1A */
+ (3 << CS10)); /* clk/64 from prescaler */
+
+#if TEENSY
+ OCR1A = 2500; /* 16MHz clock */
+#else
+ OCR1A = 1250; /* 8MHz clock */
+#endif
+
+ TIMSK1 = (1 << OCIE1A); /* Interrupt on compare match */
+}
diff --git a/src/ao_usb.h b/src/avr/ao_usb.h
index 6633dafc..6633dafc 100644
--- a/src/ao_usb.h
+++ b/src/avr/ao_usb.h
diff --git a/src/avr/ao_usb_avr.c b/src/avr/ao_usb_avr.c
new file mode 100644
index 00000000..74bdea23
--- /dev/null
+++ b/src/avr/ao_usb_avr.c
@@ -0,0 +1,688 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_usb.h"
+
+#define USB_DEBUG 0
+
+#if USB_DEBUG
+#define debug(format, args...) printf(format, ## args)
+#else
+#define debug(format, args...)
+#endif
+
+struct ao_task __xdata ao_usb_task;
+
+struct ao_usb_setup {
+ uint8_t dir_type_recip;
+ uint8_t request;
+ uint16_t value;
+ uint16_t index;
+ uint16_t length;
+} __xdata ao_usb_setup;
+
+static __xdata uint8_t ao_usb_ep0_state;
+static const uint8_t * __xdata ao_usb_ep0_in_data;
+static __xdata uint8_t ao_usb_ep0_in_len;
+static __xdata uint8_t ao_usb_ep0_in_pending;
+static __xdata uint8_t ao_usb_addr_pending;
+static __xdata uint8_t ao_usb_ep0_in_buf[2];
+static __xdata uint8_t ao_usb_ep0_out_len;
+static __xdata uint8_t *__xdata ao_usb_ep0_out_data;
+
+static __xdata uint8_t ao_usb_in_flushed;
+static __xdata uint8_t ao_usb_running;
+static __xdata uint8_t ao_usb_configuration;
+static __xdata uint8_t ueienx_0;
+
+void
+ao_usb_set_address(uint8_t address)
+{
+ UDADDR = (0 << ADDEN) | address;
+ ao_usb_addr_pending = 1;
+}
+
+#define EP_SIZE(s) ((s) == 64 ? 0x30 : \
+ ((s) == 32 ? 0x20 : \
+ ((s) == 16 ? 0x10 : \
+ 0x00)))
+
+static void
+ao_usb_dump_ep(uint8_t ep)
+{
+ UENUM = ep;
+ debug ("EP %d: UECONX %02x UECFG0X %02x UECFG1X %02x UEIENX %02x UESTA0X %02x UESTA1X %02X\n",
+ ep, UECONX, UECFG0X, UECFG1X, UEIENX, UESTA0X, UESTA1X);
+}
+
+static void
+ao_usb_set_ep0(void)
+{
+ debug ("set_ep0\n");
+ /* Set the CONTROL max packet size, single buffered */
+ UENUM = 0;
+ UECONX = (1 << EPEN); /* Enable */
+
+ UECFG0X = ((0 << EPTYPE0) | /* Control */
+ (0 << EPDIR)); /* Out (ish) */
+
+ UECFG1X = (EP_SIZE(AO_USB_CONTROL_SIZE) | /* Size */
+ (0 << EPBK0) | /* Single bank */
+ (1 << ALLOC));
+
+ ueienx_0 = ((1 << RXSTPE) | /* Enable SETUP interrupt */
+ (1 << RXOUTE)); /* Enable OUT interrupt */
+
+// ao_usb_dump_ep(0);
+ ao_usb_addr_pending = 0;
+}
+
+static void
+ao_usb_set_configuration(void)
+{
+ /* Set the IN max packet size, double buffered */
+ UENUM = AO_USB_IN_EP;
+ UECONX = (1 << EPEN); /* Enable */
+
+ UECFG0X = ((2 << EPTYPE0) | /* Bulk */
+ (1 << EPDIR)); /* In */
+
+ UECFG1X = (EP_SIZE(AO_USB_IN_SIZE) | /* Size */
+ (1 << EPBK0) | /* Double bank */
+ (1 << ALLOC)); /* Allocate */
+
+#if 0
+ UEIENX = ((1 << TXINE)); /* Enable IN complete interrupt */
+#endif
+
+ ao_usb_dump_ep(AO_USB_IN_EP);
+
+ /* Set the OUT max packet size, double buffered */
+ UENUM = AO_USB_OUT_EP;
+ UECONX |= (1 << EPEN); /* Enable */
+
+ UECFG0X = ((2 << EPTYPE0) | /* Bulk */
+ (0 << EPDIR)); /* Out */
+
+ UECFG1X = (EP_SIZE(AO_USB_OUT_SIZE) | /* Size */
+ (1 << EPBK0) | /* Double bank */
+ (1 << ALLOC)); /* Allocate */
+
+ UEIENX = ((1 << RXOUTE)); /* Enable OUT complete interrupt */
+
+ ao_usb_dump_ep(AO_USB_OUT_EP);
+ ao_usb_running = 1;
+}
+
+ISR(USB_GEN_vect)
+{
+ ao_wakeup(&ao_usb_task);
+}
+
+
+__xdata static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8};
+
+/* Walk through the list of descriptors and find a match
+ */
+static void
+ao_usb_get_descriptor(uint16_t value)
+{
+ const uint8_t *__xdata descriptor;
+ __xdata uint8_t type = value >> 8;
+ __xdata uint8_t index = value;
+
+ descriptor = ao_usb_descriptors;
+ while (descriptor[0] != 0) {
+ if (descriptor[1] == type && index-- == 0) {
+ if (type == AO_USB_DESC_CONFIGURATION)
+ ao_usb_ep0_in_len = descriptor[2];
+ else
+ ao_usb_ep0_in_len = descriptor[0];
+ ao_usb_ep0_in_data = descriptor;
+ break;
+ }
+ descriptor += descriptor[0];
+ }
+}
+
+static void
+ao_usb_ep0_set_in_pending(uint8_t in_pending)
+{
+ ao_usb_ep0_in_pending = in_pending;
+
+ if (in_pending)
+ ueienx_0 = ((1 << RXSTPE) | (1 << RXOUTE) | (1 << TXINE)); /* Enable IN interrupt */
+}
+
+/* Send an IN data packet */
+static void
+ao_usb_ep0_flush(void)
+{
+ __xdata uint8_t this_len;
+
+ cli();
+ UENUM = 0;
+ if (!(UEINTX & (1 << TXINI))) {
+ debug("EP0 not accepting IN data\n");
+ ao_usb_ep0_set_in_pending(1);
+ } else {
+ this_len = ao_usb_ep0_in_len;
+ if (this_len > AO_USB_CONTROL_SIZE)
+ this_len = AO_USB_CONTROL_SIZE;
+
+ ao_usb_ep0_in_len -= this_len;
+
+ /* Set IN interrupt enable */
+ if (ao_usb_ep0_in_len == 0 && this_len != AO_USB_CONTROL_SIZE)
+ ao_usb_ep0_set_in_pending(0);
+ else
+ ao_usb_ep0_set_in_pending(1);
+
+ debug ("Flush EP0 len %d:", this_len);
+ while (this_len--) {
+ uint8_t c = *ao_usb_ep0_in_data++;
+ debug(" %02x", c);
+ UEDATX = c;
+ }
+ debug ("\n");
+
+ /* Clear the TXINI bit to send the packet */
+ UEINTX &= ~(1 << TXINI);
+ }
+ sei();
+}
+
+/* Read data from the ep0 OUT fifo */
+static void
+ao_usb_ep0_fill(uint8_t len, uint8_t ack)
+{
+ if (len > ao_usb_ep0_out_len)
+ len = ao_usb_ep0_out_len;
+ ao_usb_ep0_out_len -= len;
+
+// debug ("EP0 UEINTX %02x UEBCLX %d UEBCHX %d\n",
+// UEINTX, UEBCLX, UEBCHX);
+ /* Pull all of the data out of the packet */
+ debug ("Fill EP0 len %d:", len);
+ UENUM = 0;
+ while (len--) {
+ uint8_t c = UEDATX;
+ *ao_usb_ep0_out_data++ = c;
+ debug (" %02x", c);
+ }
+ debug ("\n");
+
+ /* ACK the packet */
+ UEINTX &= ~ack;
+}
+
+void
+ao_usb_ep0_queue_byte(uint8_t a)
+{
+ ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a;
+}
+
+static void
+ao_usb_ep0_setup(void)
+{
+ /* Pull the setup packet out of the fifo */
+ ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_setup;
+ ao_usb_ep0_out_len = 8;
+ ao_usb_ep0_fill(8, (1 << RXSTPI) | (1 << RXOUTI) | (1 << TXINI));
+ if (ao_usb_ep0_out_len != 0) {
+ debug ("invalid setup packet length\n");
+ return;
+ }
+
+ /* Figure out how to ACK the setup packet */
+ if (ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) {
+ if (ao_usb_setup.length)
+ ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
+ else
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ } else {
+ if (ao_usb_setup.length)
+ ao_usb_ep0_state = AO_USB_EP0_DATA_OUT;
+ else
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ }
+/*
+ UENUM = 0;
+ if (ao_usb_ep0_state == AO_USB_EP0_IDLE)
+ USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END;
+ else
+ USBCS0 = USBCS0_CLR_OUTPKT_RDY;
+*/
+
+ ao_usb_ep0_in_data = ao_usb_ep0_in_buf;
+ ao_usb_ep0_in_len = 0;
+ switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) {
+ case AO_USB_TYPE_STANDARD:
+ debug ("Standard setup packet\n");
+ switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) {
+ case AO_USB_RECIP_DEVICE:
+ debug ("Device setup packet\n");
+ switch(ao_usb_setup.request) {
+ case AO_USB_REQ_GET_STATUS:
+ debug ("get status\n");
+ ao_usb_ep0_queue_byte(0);
+ ao_usb_ep0_queue_byte(0);
+ break;
+ case AO_USB_REQ_SET_ADDRESS:
+ debug ("set address %d\n", ao_usb_setup.value);
+ ao_usb_set_address(ao_usb_setup.value);
+ break;
+ case AO_USB_REQ_GET_DESCRIPTOR:
+ debug ("get descriptor %d\n", ao_usb_setup.value);
+ ao_usb_get_descriptor(ao_usb_setup.value);
+ break;
+ case AO_USB_REQ_GET_CONFIGURATION:
+ debug ("get configuration %d\n", ao_usb_configuration);
+ ao_usb_ep0_queue_byte(ao_usb_configuration);
+ break;
+ case AO_USB_REQ_SET_CONFIGURATION:
+ ao_usb_configuration = ao_usb_setup.value;
+ debug ("set configuration %d\n", ao_usb_configuration);
+ ao_usb_set_configuration();
+ break;
+ }
+ break;
+ case AO_USB_RECIP_INTERFACE:
+#ifndef AVR
+ #pragma disable_warning 110
+#endif
+ debug ("Interface setup packet\n");
+ switch(ao_usb_setup.request) {
+ case AO_USB_REQ_GET_STATUS:
+ ao_usb_ep0_queue_byte(0);
+ ao_usb_ep0_queue_byte(0);
+ break;
+ case AO_USB_REQ_GET_INTERFACE:
+ ao_usb_ep0_queue_byte(0);
+ break;
+ case AO_USB_REQ_SET_INTERFACE:
+ break;
+ }
+ break;
+ case AO_USB_RECIP_ENDPOINT:
+ debug ("Endpoint setup packet\n");
+ switch(ao_usb_setup.request) {
+ case AO_USB_REQ_GET_STATUS:
+ ao_usb_ep0_queue_byte(0);
+ ao_usb_ep0_queue_byte(0);
+ break;
+ }
+ break;
+ }
+ break;
+ case AO_USB_TYPE_CLASS:
+ debug ("Class setup packet\n");
+ switch (ao_usb_setup.request) {
+ case SET_LINE_CODING:
+ debug ("set line coding\n");
+ ao_usb_ep0_out_len = 7;
+ ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding;
+ break;
+ case GET_LINE_CODING:
+ debug ("get line coding\n");
+ ao_usb_ep0_in_len = 7;
+ ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding;
+ break;
+ case SET_CONTROL_LINE_STATE:
+ break;
+ }
+ break;
+ }
+ if (ao_usb_ep0_state != AO_USB_EP0_DATA_OUT) {
+ if (ao_usb_setup.length < ao_usb_ep0_in_len)
+ ao_usb_ep0_in_len = ao_usb_setup.length;
+ debug ("Start ep0 in delivery %d\n", ao_usb_ep0_in_len);
+ ao_usb_ep0_set_in_pending(1);
+ }
+}
+
+/* End point 0 receives all of the control messages. */
+static void
+ao_usb_ep0(void)
+{
+ uint8_t intx, udint;
+
+ debug ("usb task started\n");
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ for (;;) {
+ cli();
+ for (;;) {
+ udint = UDINT;
+ UDINT = 0;
+// debug ("UDINT %02x\n", udint);
+ if (udint & (1 << EORSTI)) {
+ ao_usb_configuration = 0;
+ ao_usb_set_ep0();
+ }
+ UENUM = 0;
+ intx = UEINTX;
+// debug ("UEINTX %02x\n", intx);
+ if (intx & ((1 << RXSTPI) | (1 << RXOUTI)))
+ break;
+ if ((intx & (1 << TXINI))) {
+ if (ao_usb_ep0_in_pending)
+ break;
+ else
+ {
+ if (ao_usb_addr_pending) {
+ UDADDR |= (1 << ADDEN);
+ ao_usb_addr_pending = 0;
+ }
+ ueienx_0 = ((1 << RXSTPE) | (1 << RXOUTE)); /* Disable IN interrupt */
+ }
+ }
+// debug ("usb task sleeping...\n");
+ UENUM = 0;
+ UEIENX = ueienx_0;
+ ao_sleep(&ao_usb_task);
+ }
+ sei();
+// debug ("UEINTX for ep0 is %02x\n", intx);
+ if (intx & (1 << RXSTPI)) {
+ ao_usb_ep0_setup();
+ }
+ if (intx & (1 << RXOUTI)) {
+ ao_usb_ep0_fill(UEBCLX, (1 << RXOUTI));
+ ao_usb_ep0_set_in_pending(1);
+ }
+ if (intx & (1 << TXINI) && ao_usb_ep0_in_pending) {
+ debug ("continue sending ep0 IN data\n");
+ ao_usb_ep0_flush();
+ }
+ }
+}
+
+/* Wait for a free IN buffer */
+static void
+ao_usb_in_wait(void)
+{
+ for (;;) {
+ /* Check if the current buffer is writable */
+ UENUM = AO_USB_IN_EP;
+ if (UEINTX & (1 << RWAL))
+ break;
+
+ cli();
+ /* Wait for an IN buffer to be ready */
+ for (;;) {
+ UENUM = AO_USB_IN_EP;
+ if ((UEINTX & (1 << TXINI)))
+ break;
+ UEIENX = (1 << TXINE);
+ ao_sleep(&ao_usb_in_flushed);
+ }
+ /* Ack the interrupt */
+ UEINTX &= ~(1 << TXINI);
+ sei();
+ }
+}
+
+/* Queue the current IN buffer for transmission */
+static void
+ao_usb_in_send(void)
+{
+ UENUM = AO_USB_IN_EP;
+ UEINTX &= ~(1 << FIFOCON);
+}
+
+void
+ao_usb_flush(void) __critical
+{
+ if (!ao_usb_running)
+ return;
+
+ /* Anytime we've sent a character since
+ * the last time we flushed, we'll need
+ * to send a packet -- the only other time
+ * we would send a packet is when that
+ * packet was full, in which case we now
+ * want to send an empty packet
+ */
+ if (!ao_usb_in_flushed) {
+ ao_usb_in_flushed = 1;
+ ao_usb_in_wait();
+ ao_usb_in_send();
+ }
+}
+
+void
+ao_usb_putchar(char c) __critical __reentrant
+{
+ if (!ao_usb_running)
+ return;
+
+ ao_usb_in_wait();
+
+ /* Queue a byte */
+ UENUM = AO_USB_IN_EP;
+ UEDATX = c;
+
+ /* Send the packet when full */
+ if ((UEINTX & (1 << RWAL)) == 0)
+ ao_usb_in_send();
+ ao_usb_in_flushed = 0;
+}
+
+static char
+_ao_usb_pollchar(void)
+{
+ char c;
+ uint8_t intx;
+
+ if (!ao_usb_running)
+ return AO_READ_AGAIN;
+
+ for (;;) {
+ UENUM = AO_USB_OUT_EP;
+ intx = UEINTX;
+ debug("usb_pollchar UEINTX %02d\n", intx);
+ if (intx & (1 << RWAL))
+ break;
+
+ if (intx & (1 << FIFOCON)) {
+ /* Ack the last packet */
+ UEINTX = (uint8_t) ~(1 << FIFOCON);
+ }
+
+ /* Check to see if a packet has arrived */
+ if ((intx & (1 << RXOUTI)) == 0) {
+ UENUM = AO_USB_OUT_EP;
+ UEIENX = (1 << RXOUTE);
+ return AO_READ_AGAIN;
+ }
+
+ /* Ack the interrupt */
+ UEINTX = ~(1 << RXOUTI);
+ }
+
+ /* Pull a character out of the fifo */
+ c = UEDATX;
+ return c;
+}
+
+char
+ao_usb_pollchar(void)
+{
+ char c;
+ cli();
+ c = _ao_usb_pollchar();
+ sei();
+ return c;
+}
+
+char
+ao_usb_getchar(void) __critical
+{
+ char c;
+
+ cli();
+ while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
+ ao_sleep(&ao_stdin_ready);
+ sei();
+ return c;
+}
+
+uint16_t control_count;
+uint16_t in_count;
+uint16_t out_count;
+
+/* Endpoint interrupt */
+ISR(USB_COM_vect)
+{
+ uint8_t old_num = UENUM;
+ uint8_t i = UEINT;
+
+#ifdef AO_LED_RED
+ ao_led_toggle(AO_LED_RED);
+#endif
+ UEINT = 0;
+ if (i & (1 << 0)) {
+ UENUM = 0;
+ UEIENX = 0;
+ ao_wakeup(&ao_usb_task);
+ ++control_count;
+ }
+ if (i & (1 << AO_USB_IN_EP)) {
+ UENUM = AO_USB_IN_EP;
+ UEIENX = 0;
+ ao_wakeup(&ao_usb_in_flushed);
+ in_count++;
+ }
+ if (i & (1 << AO_USB_OUT_EP)) {
+ UENUM = AO_USB_OUT_EP;
+ UEIENX = 0;
+ ao_wakeup(&ao_stdin_ready);
+ ++out_count;
+ }
+ UENUM = old_num;
+}
+
+#if AVR_VCC_5V
+#define AO_PAD_REGULATOR_INIT (1 << UVREGE) /* Turn on pad regulator */
+#endif
+#if AVR_VCC_3V3
+/* TeleScience V0.1 has a hardware bug -- UVcc is hooked up, but UCap is not
+ * Make this work by running power through UVcc to the USB system
+ */
+#define AO_PAD_REGULATOR_INIT (1 << UVREGE) /* Turn off pad regulator */
+#endif
+
+#if AVR_CLOCK == 16000000UL
+#define AO_USB_PLL_INPUT_PRESCALER (1 << PINDIV) /* Divide 16MHz clock by 2 */
+#endif
+#if AVR_CLOCK == 8000000UL
+#define AO_USB_PLL_INPUT_PRESCALER 0 /* Don't divide clock */
+#endif
+
+void
+ao_usb_disable(void)
+{
+ /* Unplug from the bus */
+ UDCON = (1 << DETACH);
+
+ /* Disable the interface */
+ USBCON = 0;
+
+ /* Disable the PLL */
+ PLLCSR = 0;
+
+ /* Turn off the pad regulator */
+ UHWCON = 0;
+}
+
+#define AO_USB_CON ((1 << USBE) | /* USB enable */ \
+ (0 << RSTCPU) | /* do not reset CPU */ \
+ (0 << LSM) | /* Full speed mode */ \
+ (0 << RMWKUP)) /* no remote wake-up */ \
+
+void
+ao_usb_enable(void)
+{
+ /* Configure pad regulator */
+ UHWCON = AO_PAD_REGULATOR_INIT;
+
+ /* Enable USB device, but freeze the clocks until initialized */
+ USBCON = AO_USB_CON | (1 <<FRZCLK);
+
+ /* Enable PLL with appropriate divider */
+ PLLCSR = AO_USB_PLL_INPUT_PRESCALER | (1 << PLLE);
+
+ /* Wait for PLL to lock */
+ loop_until_bit_is_set(PLLCSR, (1 << PLOCK));
+
+ /* Enable USB, enable the VBUS pad */
+ USBCON = AO_USB_CON | (1 << OTGPADE);
+
+ /* Enable global interrupts */
+ UDIEN = (1 << EORSTE); /* End of reset interrupt */
+
+ ao_usb_configuration = 0;
+
+ debug ("ao_usb_enable\n");
+
+ debug ("UHWCON %02x USBCON %02x PLLCSR %02x UDIEN %02x\n",
+ UHWCON, USBCON, PLLCSR, UDIEN);
+ UDCON = (0 << DETACH); /* Clear the DETACH bit to plug into the bus */
+}
+
+#if USB_DEBUG
+struct ao_task __xdata ao_usb_echo_task;
+
+static void
+ao_usb_echo(void)
+{
+ char c;
+
+ for (;;) {
+ c = ao_usb_getchar();
+ ao_usb_putchar(c);
+ ao_usb_flush();
+ }
+}
+#endif
+
+static void
+ao_usb_irq(void)
+{
+ printf ("control: %d out: %d in: %d\n",
+ control_count, out_count, in_count);
+}
+
+__code struct ao_cmds ao_usb_cmds[] = {
+ { ao_usb_irq, "i\0Show USB interrupt counts" },
+ { 0, NULL }
+};
+
+void
+ao_usb_init(void)
+{
+ ao_usb_enable();
+
+ debug ("ao_usb_init\n");
+ ao_add_task(&ao_usb_task, ao_usb_ep0, "usb");
+#if USB_DEBUG
+ ao_add_task(&ao_usb_echo_task, ao_usb_echo, "usb echo");
+#endif
+ ao_cmd_register(&ao_usb_cmds[0]);
+ ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
+}
diff --git a/src/cc1111/Makefile.cc1111 b/src/cc1111/Makefile.cc1111
new file mode 100644
index 00000000..8de4a9b2
--- /dev/null
+++ b/src/cc1111/Makefile.cc1111
@@ -0,0 +1,27 @@
+CC=sdcc
+
+CFLAGS=--model-small --debug --opt-code-speed -DCODESIZE=$(CODESIZE)
+
+CFLAGS += $(PRODUCT_DEF) -I. -I.. -I../core -I../cc1111 -I../driver -I../product
+
+CODESIZE ?= 0x8000
+
+LDFLAGS=--out-fmt-ihx --code-loc 0x0000 --code-size $(CODESIZE) \
+ --xram-loc 0xf000 --xram-size 0xda2 --iram-size 0xff
+
+REL=$(SRC:.c=.rel) ao_product.rel
+ADB=$(REL:.rel=.adb)
+ASM=$(REL:.rel=.asm)
+LNK=$(REL:.rel=.lnk)
+LST=$(REL:.rel=.lst)
+RST=$(REL:.rel=.rst)
+SYM=$(REL:.rel=.sym)
+
+PCDB=$(PROG:.ihx=.cdb)
+PLNK=$(PROG:.ihx=.lnk)
+PMAP=$(PROG:.ihx=.map)
+PMEM=$(PROG:.ihx=.mem)
+PAOM=$(PROG:.ihx=)
+
+%.rel : %.c $(INC)
+ $(call quiet,CC,$(PRODUCT_DEF)) $(CFLAGS) -c -o$@ $<
diff --git a/src/_bp.c b/src/cc1111/_bp.c
index 6bf135bc..6bf135bc 100644
--- a/src/_bp.c
+++ b/src/cc1111/_bp.c
diff --git a/src/ao_adc.c b/src/cc1111/ao_adc.c
index 786dfd11..6aa6e018 100644
--- a/src/ao_adc.c
+++ b/src/cc1111/ao_adc.c
@@ -41,7 +41,11 @@ ao_adc_poll(void)
void
ao_adc_get(__xdata struct ao_adc *packet)
{
+#if HAS_FLIGHT
uint8_t i = ao_adc_ring_prev(ao_sample_adc);
+#else
+ uint8_t i = ao_adc_ring_prev(ao_adc_head);
+#endif
memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc));
}
diff --git a/src/cc1111/ao_arch.h b/src/cc1111/ao_arch.h
new file mode 100644
index 00000000..8a41791f
--- /dev/null
+++ b/src/cc1111/ao_arch.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright © 2011 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.
+ */
+
+/*
+ * CC1111 definitions and code fragments for AltOS
+ */
+
+#ifndef _AO_ARCH_H_
+#define _AO_ARCH_H_
+
+#include "cc1111.h"
+
+/* Convert a __data pointer into an __xdata pointer */
+#define DATA_TO_XDATA(a) ((void __xdata *) ((uint8_t) (a) | 0xff00))
+
+/* Stack runs from above the allocated __data space to 0xfe, which avoids
+ * writing to 0xff as that triggers the stack overflow indicator
+ */
+#define AO_STACK_START 0x90
+#define AO_STACK_END 0xfe
+#define AO_STACK_SIZE (AO_STACK_END - AO_STACK_START + 1)
+
+#define ao_arch_reboot() do { \
+ WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_64; \
+ ao_delay(AO_SEC_TO_TICKS(2)); \
+ } while (0)
+
+#define ao_arch_nop() _asm nop _endasm
+#define ao_arch_interrupt(n) __interrupt n
+
+#define ao_arch_naked_declare __naked
+#define ao_arch_naked_define __naked
+
+/* CC1111-specific drivers */
+
+/*
+ * ao_romconfig.c
+ */
+
+#define AO_ROMCONFIG_VERSION 2
+
+extern __code __at (0x00a0) uint16_t ao_romconfig_version;
+extern __code __at (0x00a2) uint16_t ao_romconfig_check;
+extern __code __at (0x00a4) uint16_t ao_serial_number;
+extern __code __at (0x00a6) uint32_t ao_radio_cal;
+
+#ifndef HAS_USB
+#error Please define HAS_USB
+#endif
+
+#define ao_arch_task_members\
+ uint8_t stack_count; /* amount of saved stack */
+
+/* Initialize stack */
+#define ao_arch_init_stack(task, start) { \
+ uint8_t __xdata *stack = task->stack; \
+ uint8_t t; \
+ *stack++ = ((uint16_t) start); /* 0 */ \
+ *stack++ = ((uint16_t) start) >> 8; /* 1 */ \
+ \
+ /* and the stuff saved by ao_switch */ \
+ *stack++ = 0; /* 2 acc */ \
+ *stack++ = 0x80; /* 3 IE */ \
+ \
+ /* 4 DPL \
+ * 5 DPH \
+ * 6 B \
+ * 7 R2 \
+ * 8 R3 \
+ * 9 R4 \
+ * 10 R5 \
+ * 11 R6 \
+ * 12 R7 \
+ * 13 R0 \
+ * 14 R1 \
+ * 15 PSW \
+ * 16 BP \
+ */ \
+ for (t = 0; t < 13; t++) \
+ *stack++ = 0; \
+ task->stack_count = 17; \
+ }
+
+
+
+/* Save current context */
+
+#define ao_arch_save_regs() \
+ _asm \
+ /* Push ACC first, as when restoring the context it must be restored \
+ * last (it is used to set the IE register). */ \
+ push ACC \
+ /* Store the IE register then enable interrupts. */ \
+ push _IEN0 \
+ setb _EA \
+ push DPL \
+ push DPH \
+ push b \
+ push ar2 \
+ push ar3 \
+ push ar4 \
+ push ar5 \
+ push ar6 \
+ push ar7 \
+ push ar0 \
+ push ar1 \
+ push PSW \
+ _endasm; \
+ PSW = 0; \
+ _asm \
+ push _bp \
+ _endasm
+
+#define ao_arch_save_stack() { \
+ uint8_t stack_len; \
+ __data uint8_t *stack_ptr; \
+ __xdata uint8_t *save_ptr; \
+ /* Save the current stack */ \
+ stack_len = SP - (AO_STACK_START - 1); \
+ ao_cur_task->stack_count = stack_len; \
+ stack_ptr = (uint8_t __data *) AO_STACK_START; \
+ save_ptr = (uint8_t __xdata *) ao_cur_task->stack; \
+ do \
+ *save_ptr++ = *stack_ptr++; \
+ while (--stack_len); \
+ }
+
+#define ao_arch_isr_stack() \
+ /* Empty the stack; might as well let interrupts have the whole thing */ \
+ (SP = AO_STACK_START - 1)
+
+#define ao_arch_cpu_idle() (PCON = PCON_IDLE)
+
+#define ao_arch_restore_stack() { \
+ uint8_t stack_len; \
+ __data uint8_t *stack_ptr; \
+ __xdata uint8_t *save_ptr; \
+ \
+ /* Restore the old stack */ \
+ stack_len = ao_cur_task->stack_count; \
+ SP = AO_STACK_START - 1 + stack_len; \
+ \
+ stack_ptr = (uint8_t __data *) AO_STACK_START; \
+ save_ptr = (uint8_t __xdata *) ao_cur_task->stack; \
+ do \
+ *stack_ptr++ = *save_ptr++; \
+ while (--stack_len); \
+ \
+ _asm \
+ pop _bp \
+ pop PSW \
+ pop ar1 \
+ pop ar0 \
+ pop ar7 \
+ pop ar6 \
+ pop ar5 \
+ pop ar4 \
+ pop ar3 \
+ pop ar2 \
+ pop b \
+ pop DPH \
+ pop DPL \
+ /* The next byte of the stack is the IE register. Only the global \
+ enable bit forms part of the task context. Pop off the IE then set \
+ the global enable bit to match that of the stored IE register. */ \
+ pop ACC \
+ JB ACC.7,0098$ \
+ CLR _EA \
+ LJMP 0099$ \
+ 0098$: \
+ SETB _EA \
+ 0099$: \
+ /* Finally pop off the ACC, which was the first register saved. */ \
+ pop ACC \
+ ret \
+ _endasm; \
+}
+
+#define ao_arch_critical(b) __critical { b }
+
+struct ao_adc {
+ uint16_t tick; /* tick when the sample was read */
+ 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 */
+};
+
+#define AO_ADC_RING 32
+
+#endif /* _AO_ARCH_H_ */
diff --git a/src/ao_beep.c b/src/cc1111/ao_beep.c
index 3642f4c6..3642f4c6 100644
--- a/src/ao_beep.c
+++ b/src/cc1111/ao_beep.c
diff --git a/src/ao_dbg.c b/src/cc1111/ao_dbg.c
index d4c9567f..d4c9567f 100644
--- a/src/ao_dbg.c
+++ b/src/cc1111/ao_dbg.c
diff --git a/src/ao_dma.c b/src/cc1111/ao_dma.c
index 6052964a..6052964a 100644
--- a/src/ao_dma.c
+++ b/src/cc1111/ao_dma.c
diff --git a/src/ao_ignite.c b/src/cc1111/ao_ignite.c
index 5238beb4..289263ab 100644
--- a/src/ao_ignite.c
+++ b/src/cc1111/ao_ignite.c
@@ -17,34 +17,6 @@
#include "ao.h"
-#if IGNITE_ON_P2
-#define AO_IGNITER_DROGUE P2_3
-#define AO_IGNITER_MAIN P2_4
-#define AO_IGNITER_DIR P2DIR
-#define AO_IGNITER_DROGUE_BIT (1 << 3)
-#define AO_IGNITER_MAIN_BIT (1 << 4)
-#endif
-
-#if IGNITE_ON_P0
-#define AO_IGNITER_DROGUE P0_5
-#define AO_IGNITER_MAIN P0_4
-#define AO_IGNITER_DIR P0DIR
-#define AO_IGNITER_DROGUE_BIT (1 << 5)
-#define AO_IGNITER_MAIN_BIT (1 << 4)
-#endif
-
-/* test these values with real igniters */
-#define AO_IGNITER_OPEN 1000
-#define AO_IGNITER_CLOSED 7000
-#define AO_IGNITER_FIRE_TIME AO_MS_TO_TICKS(50)
-#define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000)
-
-struct ao_ignition {
- uint8_t request;
- uint8_t fired;
- uint8_t firing;
-};
-
__xdata struct ao_ignition ao_ignition[2];
void
diff --git a/src/ao_intflash.c b/src/cc1111/ao_intflash.c
index d76d954e..d76d954e 100644
--- a/src/ao_intflash.c
+++ b/src/cc1111/ao_intflash.c
diff --git a/src/cc1111/ao_launch.c b/src/cc1111/ao_launch.c
new file mode 100644
index 00000000..a593d0b2
--- /dev/null
+++ b/src/cc1111/ao_launch.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+__xdata uint16_t ao_launch_ignite;
+
+#if 0
+#define PRINTD(...) printf(__VA_ARGS__)
+#else
+#define PRINTD(...)
+#endif
+
+static void
+ao_launch_run(void)
+{
+ for (;;) {
+ while (!ao_launch_ignite)
+ ao_sleep(&ao_launch_ignite);
+ ao_ignition[ao_igniter_drogue].firing = 1;
+ ao_ignition[ao_igniter_main].firing = 1;
+ AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT;
+ AO_IGNITER_DROGUE = 1;
+ while (ao_launch_ignite) {
+ ao_launch_ignite = 0;
+ ao_delay(AO_MS_TO_TICKS(500));
+ }
+ AO_IGNITER_DROGUE = 0;
+ ao_ignition[ao_igniter_drogue].firing = 0;
+ ao_ignition[ao_igniter_main].firing = 0;
+ }
+}
+
+static void
+ao_launch_status(void)
+{
+ uint8_t i;
+ for (;;) {
+ ao_delay(AO_SEC_TO_TICKS(1));
+ if (ao_igniter_status(ao_igniter_drogue) == ao_igniter_ready) {
+ if (ao_igniter_status(ao_igniter_main) == ao_igniter_ready) {
+ for (i = 0; i < 5; i++) {
+ ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(50));
+ ao_delay(AO_MS_TO_TICKS(100));
+ }
+ } else {
+ ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
+ }
+ }
+ }
+}
+
+static __pdata uint8_t ao_launch_armed;
+static __pdata uint16_t ao_launch_arm_time;
+
+static void
+ao_launch(void)
+{
+ static __xdata struct ao_launch_command command;
+ static __xdata struct ao_launch_query query;
+ int16_t time_difference;
+
+ ao_led_off(AO_LED_RED);
+ ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
+ for (;;) {
+ flush();
+ if (ao_radio_cmac_recv(&command, sizeof (command), 0) != AO_RADIO_CMAC_OK)
+ continue;
+
+ PRINTD ("tick %d serial %d cmd %d channel %d\n",
+ command.tick, command.serial, command.cmd, command.channel);
+
+ switch (command.cmd) {
+ case AO_LAUNCH_QUERY:
+ if (command.serial != ao_serial_number) {
+ PRINTD ("serial number mismatch\n");
+ break;
+ }
+
+ if (command.channel == 0) {
+ query.valid = 1;
+ query.arm_status = ao_igniter_status(ao_igniter_drogue);
+ query.igniter_status = ao_igniter_status(ao_igniter_main);
+ } else {
+ query.valid = 0;
+ }
+ query.tick = ao_time();
+ query.serial = ao_serial_number;
+ query.channel = command.channel;
+ PRINTD ("query tick %d serial %d channel %d valid %d arm %d igniter %d\n",
+ query.tick, query.serial, query.channel, query.valid, query.arm_status,
+ query.igniter_status);
+ ao_radio_cmac_send(&query, sizeof (query));
+ break;
+ case AO_LAUNCH_ARM:
+ if (command.serial != ao_serial_number) {
+ PRINTD ("serial number mismatch\n");
+ break;
+ }
+
+ if (command.channel != 0)
+ break;
+ time_difference = command.tick - ao_time();
+ PRINTD ("arm tick %d local tick %d\n", command.tick, ao_time());
+ if (time_difference < 0)
+ time_difference = -time_difference;
+ if (time_difference > 10) {
+ PRINTD ("time difference too large %d\n", time_difference);
+ break;
+ }
+ PRINTD ("armed\n");
+ ao_launch_armed = 1;
+ ao_launch_arm_time = ao_time();
+ break;
+ case AO_LAUNCH_FIRE:
+ if (!ao_launch_armed) {
+ PRINTD ("not armed\n");
+ break;
+ }
+ if ((uint16_t) (ao_time() - ao_launch_arm_time) > AO_SEC_TO_TICKS(20)) {
+ PRINTD ("late launch arm_time %d time %d\n",
+ ao_launch_arm_time, ao_time());
+ break;
+ }
+ time_difference = command.tick - ao_time();
+ if (time_difference < 0)
+ time_difference = -time_difference;
+ if (time_difference > 10) {
+ PRINTD ("time different too large %d\n", time_difference);
+ break;
+ }
+ PRINTD ("ignite\n");
+ ao_launch_ignite = 1;
+ ao_wakeup(&ao_launch_ignite);
+ break;
+ }
+ }
+}
+
+void
+ao_launch_test(void)
+{
+ switch (ao_igniter_status(ao_igniter_drogue)) {
+ case ao_igniter_ready:
+ case ao_igniter_active:
+ printf ("Armed: ");
+ switch (ao_igniter_status(ao_igniter_main)) {
+ default:
+ printf("unknown status\n");
+ break;
+ case ao_igniter_ready:
+ printf("igniter good\n");
+ break;
+ case ao_igniter_open:
+ printf("igniter bad\n");
+ break;
+ }
+ break;
+ default:
+ printf("Disarmed\n");
+ }
+}
+
+void
+ao_launch_manual(void)
+{
+ ao_cmd_white();
+ if (!ao_match_word("DoIt"))
+ return;
+ ao_cmd_white();
+ ao_launch_ignite = 1;
+ ao_wakeup(&ao_launch_ignite);
+}
+
+static __xdata struct ao_task ao_launch_task;
+static __xdata struct ao_task ao_launch_ignite_task;
+static __xdata struct ao_task ao_launch_status_task;
+
+__code struct ao_cmds ao_launch_cmds[] = {
+ { ao_launch_test, "t\0Test launch continuity" },
+ { ao_launch_manual, "i <key>\0Fire igniter. <key> is doit with D&I" },
+ { 0, NULL }
+};
+
+void
+ao_launch_init(void)
+{
+ AO_IGNITER_DROGUE = 0;
+ AO_IGNITER_MAIN = 0;
+ AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT;
+ ao_cmd_register(&ao_launch_cmds[0]);
+ ao_add_task(&ao_launch_task, ao_launch, "launch listener");
+ ao_add_task(&ao_launch_ignite_task, ao_launch_run, "launch igniter");
+ ao_add_task(&ao_launch_status_task, ao_launch_status, "launch status");
+}
diff --git a/src/ao_led.c b/src/cc1111/ao_led.c
index 5beed58d..5beed58d 100644
--- a/src/ao_led.c
+++ b/src/cc1111/ao_led.c
diff --git a/src/ao_packet.c b/src/cc1111/ao_packet.c
index f627e02b..f627e02b 100644
--- a/src/ao_packet.c
+++ b/src/cc1111/ao_packet.c
diff --git a/src/ao_packet_master.c b/src/cc1111/ao_packet_master.c
index b0fdf5a8..0d0be30e 100644
--- a/src/ao_packet_master.c
+++ b/src/cc1111/ao_packet_master.c
@@ -80,13 +80,16 @@ ao_packet_master(void)
ao_packet_master_time = ao_time();
ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT;
while (ao_packet_enable) {
+ uint8_t r;
memcpy(ao_tx_packet.callsign, ao_config.callsign, AO_MAX_CALLSIGN);
ao_packet_send();
if (ao_tx_packet.len)
ao_packet_master_busy();
ao_packet_master_check_busy();
ao_alarm(ao_packet_master_delay);
- if (ao_packet_recv()) {
+ r = ao_packet_recv();
+ ao_clear_alarm();
+ if (r) {
/* if we can transmit data, do so */
if (ao_packet_tx_used && ao_tx_packet.len == 0)
continue;
@@ -95,6 +98,7 @@ ao_packet_master(void)
ao_packet_master_sleeping = 1;
ao_alarm(ao_packet_master_delay);
ao_sleep(&ao_packet_master_sleeping);
+ ao_clear_alarm();
ao_packet_master_sleeping = 0;
}
}
diff --git a/src/ao_packet_slave.c b/src/cc1111/ao_packet_slave.c
index d7cafa68..d7cafa68 100644
--- a/src/ao_packet_slave.c
+++ b/src/cc1111/ao_packet_slave.c
diff --git a/src/ao_pins.h b/src/cc1111/ao_pins.h
index e1f5459f..723f1500 100644
--- a/src/ao_pins.h
+++ b/src/cc1111/ao_pins.h
@@ -27,6 +27,7 @@
#define HAS_ADC 1
#define USE_SERIAL_STDIN 0
#define HAS_EEPROM 1
+ #define HAS_LOG 1
#define USE_INTERNAL_FLASH 0
#define HAS_DBG 1
#define DBG_ON_P1 1
@@ -59,6 +60,7 @@
#define USE_SERIAL_STDIN 0
#define HAS_ADC 1
#define HAS_EEPROM 1
+ #define HAS_LOG 1
#define USE_INTERNAL_FLASH 0
#define HAS_DBG 1
#define DBG_ON_P1 1
@@ -95,6 +97,7 @@
#define HAS_ADC 0
#define HAS_DBG 1
#define HAS_EEPROM 0
+ #define HAS_LOG 0
#define DBG_ON_P1 1
#define DBG_ON_P0 0
#define IGNITE_ON_P2 0
@@ -108,6 +111,8 @@
#define SPI_CS_ON_P0 0
#define HAS_IGNITE 0
#define HAS_MONITOR 1
+ #define HAS_RSSI 1
+ #define HAS_AES 1
#endif
#if defined(TELEMINI_V_1_0)
@@ -119,6 +124,7 @@
#define USE_SERIAL_STDIN 0
#define HAS_ADC 1
#define HAS_EEPROM 1
+ #define HAS_LOG 1
#define USE_INTERNAL_FLASH 1
#define HAS_DBG 0
#define IGNITE_ON_P2 0
@@ -145,6 +151,7 @@
#define USE_SERIAL_STDIN 0
#define HAS_ADC 1
#define HAS_EEPROM 1
+ #define HAS_LOG 1
#define USE_INTERNAL_FLASH 1
#define HAS_DBG 0
#define IGNITE_ON_P2 0
@@ -171,6 +178,7 @@
#define HAS_ADC 1
#define HAS_DBG 0
#define HAS_EEPROM 1
+ #define HAS_LOG 1
#define USE_INTERNAL_FLASH 0
#define DBG_ON_P1 0
#define DBG_ON_P0 1
@@ -199,6 +207,7 @@
#define HAS_ADC 0
#define HAS_DBG 0
#define HAS_EEPROM 0
+ #define HAS_LOG 0
#define DBG_ON_P1 0
#define DBG_ON_P0 1
#define IGNITE_ON_P2 0
@@ -212,6 +221,8 @@
#define SPI_CS_ON_P0 1
#define HAS_IGNITE 0
#define HAS_MONITOR 1
+ #define HAS_RSSI 1
+ #define HAS_AES 1
#endif
#if defined(TIDONGLE)
@@ -223,6 +234,7 @@
#define HAS_ADC 0
#define HAS_DBG 1
#define HAS_EEPROM 0
+ #define HAS_LOG 0
#define DBG_ON_P1 0
#define DBG_ON_P0 1
#define IGNITE_ON_P2 0
@@ -235,6 +247,8 @@
#define SPI_CS_ON_P0 1
#define HAS_IGNITE 0
#define HAS_MONITOR 1
+ #define HAS_RSSI 1
+ #define HAS_AES 1
#endif
#if defined(TELEBT_V_0_0)
@@ -246,6 +260,7 @@
#define HAS_ADC 0
#define HAS_DBG 1
#define HAS_EEPROM 0
+ #define HAS_LOG 0
#define HAS_BTM 1
#define DBG_ON_P1 0
#define DBG_ON_P0 1
@@ -259,11 +274,14 @@
#define SPI_CS_ON_P1 1
#define SPI_CS_ON_P0 0
#define HAS_IGNITE 0
+ #define HAS_IGNITE_REPORT 1
#define BT_LINK_ON_P2 1
#define BT_LINK_ON_P1 0
#define BT_LINK_PIN_INDEX 7
#define BT_LINK_PIN P2_1
#define HAS_MONITOR 1
+ #define HAS_RSSI 0
+ #define HAS_AES 1
#endif
#if defined(TELEBT_V_0_1)
@@ -278,6 +296,7 @@
#define HAS_ADC 0
#define HAS_DBG 1
#define HAS_EEPROM 1
+ #define HAS_LOG 1
#define USE_INTERNAL_FLASH 0
#define HAS_BTM 1
#define DBG_ON_P1 1
@@ -295,11 +314,45 @@
#define M25_MAX_CHIPS 1
#define HAS_ACCEL 0
#define HAS_IGNITE 0
+ #define HAS_IGNITE_REPORT 1
#define BT_LINK_ON_P2 0
#define BT_LINK_ON_P1 1
#define BT_LINK_PIN_INDEX 7
#define BT_LINK_PIN P1_7
#define HAS_MONITOR 1
+ #define HAS_RSSI 0
+ #define HAS_AES 1
+#endif
+
+#if defined(TELELAUNCH_V_0_1)
+ #define HAS_FLIGHT 0
+ #define HAS_USB 1
+ #define HAS_BEEP 1
+ #define HAS_GPS 0
+ #define HAS_SERIAL_1 1
+ #define USE_SERIAL_STDIN 0
+ #define HAS_ADC 1
+ #define HAS_DBG 0
+ #define HAS_EEPROM 1
+ #define HAS_LOG 0
+ #define USE_INTERNAL_FLASH 1
+ #define DBG_ON_P1 0
+ #define DBG_ON_P0 1
+ #define IGNITE_ON_P2 1
+ #define IGNITE_ON_P0 0
+ #define PACKET_HAS_MASTER 0
+ #define PACKET_HAS_SLAVE 0
+ #define AO_LED_RED 2
+ #define AO_LED_GREEN 1
+ #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN)
+ #define HAS_EXTERNAL_TEMP 1
+ #define HAS_ACCEL_REF 0
+ #define SPI_CS_ON_P1 1
+ #define SPI_CS_ON_P0 0
+ #define HAS_ACCEL 0
+ #define HAS_IGNITE 1
+ #define HAS_MONITOR 0
+ #define HAS_AES 1
#endif
#if DBG_ON_P1
@@ -380,6 +433,10 @@
#error Please define HAS_EEPROM
#endif
+#ifndef HAS_LOG
+#error Please define HAS_LOG
+#endif
+
#if HAS_EEPROM
#ifndef USE_INTERNAL_FLASH
#error Please define USE_INTERNAL_FLASH
@@ -394,6 +451,10 @@
#error Please define HAS_IGNITE
#endif
+#if HAS_IGNITE
+#define HAS_IGNITE_REPORT 1
+#endif
+
#ifndef PACKET_HAS_MASTER
#error Please define PACKET_HAS_MASTER
#endif
@@ -405,4 +466,49 @@
#ifndef HAS_MONITOR
#error Please define HAS_MONITOR
#endif
+
+#if HAS_MONITOR
+#ifndef HAS_RSSI
+#error Please define HAS_RSSI
+#endif
+#endif
+
+#ifndef HAS_ADC
+#error Please define HAS_ADC
+#endif
+
+#if HAS_ADC
+
+#if HAS_ACCEL
+#ifndef HAS_ACCEL_REF
+#error Please define HAS_ACCEL_REF
+#endif
+#else
+#define HAS_ACCEL_REF 0
+#endif
+
+#endif /* HAS_ADC */
+
+#if IGNITE_ON_P2
+#define AO_IGNITER_DROGUE P2_3
+#define AO_IGNITER_MAIN P2_4
+#define AO_IGNITER_DIR P2DIR
+#define AO_IGNITER_DROGUE_BIT (1 << 3)
+#define AO_IGNITER_MAIN_BIT (1 << 4)
+#endif
+
+#if IGNITE_ON_P0
+#define AO_IGNITER_DROGUE P0_5
+#define AO_IGNITER_MAIN P0_4
+#define AO_IGNITER_DIR P0DIR
+#define AO_IGNITER_DROGUE_BIT (1 << 5)
+#define AO_IGNITER_MAIN_BIT (1 << 4)
+#endif
+
+/* test these values with real igniters */
+#define AO_IGNITER_OPEN 1000
+#define AO_IGNITER_CLOSED 7000
+#define AO_IGNITER_FIRE_TIME AO_MS_TO_TICKS(50)
+#define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000)
+
#endif /* _AO_PINS_H_ */
diff --git a/src/ao_radio.c b/src/cc1111/ao_radio.c
index 00816b33..75f241d4 100644
--- a/src/ao_radio.c
+++ b/src/cc1111/ao_radio.c
@@ -367,21 +367,9 @@ ao_radio_recv_abort(void)
__xdata ao_radio_rdf_value = 0x55;
void
-ao_radio_rdf(int ms)
+ao_radio_rdf(uint8_t pkt_len)
{
uint8_t i;
- uint8_t pkt_len;
-
- /*
- * Compute the packet length as follows:
- *
- * 2000 bps (for a 1kHz tone)
- * so, for 'ms' milliseconds, we need
- * 2 * ms bits, or ms / 4 bytes
- */
- if (ms > (255 * 4))
- ms = 255 * 4;
- pkt_len = ms >> 2;
ao_radio_abort = 0;
ao_radio_get(pkt_len);
diff --git a/src/ao_reboot.c b/src/cc1111/ao_reboot.c
index 8c47b893..8c47b893 100644
--- a/src/ao_reboot.c
+++ b/src/cc1111/ao_reboot.c
diff --git a/src/ao_romconfig.c b/src/cc1111/ao_romconfig.c
index f3fe61b1..f3fe61b1 100644
--- a/src/ao_romconfig.c
+++ b/src/cc1111/ao_romconfig.c
diff --git a/src/ao_serial.c b/src/cc1111/ao_serial.c
index 82370c64..82370c64 100644
--- a/src/ao_serial.c
+++ b/src/cc1111/ao_serial.c
diff --git a/src/ao_spi.c b/src/cc1111/ao_spi.c
index fbe613c7..fbe613c7 100644
--- a/src/ao_spi.c
+++ b/src/cc1111/ao_spi.c
diff --git a/src/ao_timer.c b/src/cc1111/ao_timer.c
index c977fbc8..aadee71e 100644
--- a/src/ao_timer.c
+++ b/src/cc1111/ao_timer.c
@@ -31,6 +31,7 @@ ao_delay(uint16_t ticks)
{
ao_alarm(ticks);
ao_sleep(&ao_forever);
+ ao_clear_alarm();
}
#define T1_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */
diff --git a/src/ao_usb.c b/src/cc1111/ao_usb.c
index 08cb7390..08cb7390 100644
--- a/src/ao_usb.c
+++ b/src/cc1111/ao_usb.c
diff --git a/src/cc1111/ao_usb.h b/src/cc1111/ao_usb.h
new file mode 100644
index 00000000..6633dafc
--- /dev/null
+++ b/src/cc1111/ao_usb.h
@@ -0,0 +1,100 @@
+/*
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_USB_H_
+#define _AO_USB_H_
+
+#define AO_USB_SETUP_DIR_MASK (0x01 << 7)
+#define AO_USB_SETUP_TYPE_MASK (0x03 << 5)
+#define AO_USB_SETUP_RECIP_MASK (0x1f)
+
+#define AO_USB_DIR_OUT 0
+#define AO_USB_DIR_IN (1 << 7)
+
+#define AO_USB_TYPE_STANDARD 0
+#define AO_USB_TYPE_CLASS (1 << 5)
+#define AO_USB_TYPE_VENDOR (2 << 5)
+#define AO_USB_TYPE_RESERVED (3 << 5)
+
+#define AO_USB_RECIP_DEVICE 0
+#define AO_USB_RECIP_INTERFACE 1
+#define AO_USB_RECIP_ENDPOINT 2
+#define AO_USB_RECIP_OTHER 3
+
+/* standard requests */
+#define AO_USB_REQ_GET_STATUS 0x00
+#define AO_USB_REQ_CLEAR_FEATURE 0x01
+#define AO_USB_REQ_SET_FEATURE 0x03
+#define AO_USB_REQ_SET_ADDRESS 0x05
+#define AO_USB_REQ_GET_DESCRIPTOR 0x06
+#define AO_USB_REQ_SET_DESCRIPTOR 0x07
+#define AO_USB_REQ_GET_CONFIGURATION 0x08
+#define AO_USB_REQ_SET_CONFIGURATION 0x09
+#define AO_USB_REQ_GET_INTERFACE 0x0A
+#define AO_USB_REQ_SET_INTERFACE 0x0B
+#define AO_USB_REQ_SYNCH_FRAME 0x0C
+
+#define AO_USB_DESC_DEVICE 1
+#define AO_USB_DESC_CONFIGURATION 2
+#define AO_USB_DESC_STRING 3
+#define AO_USB_DESC_INTERFACE 4
+#define AO_USB_DESC_ENDPOINT 5
+#define AO_USB_DESC_DEVICE_QUALIFIER 6
+#define AO_USB_DESC_OTHER_SPEED 7
+#define AO_USB_DESC_INTERFACE_POWER 8
+
+#define AO_USB_GET_DESC_TYPE(x) (((x)>>8)&0xFF)
+#define AO_USB_GET_DESC_INDEX(x) ((x)&0xFF)
+
+#define AO_USB_CONTROL_EP 0
+#define AO_USB_INT_EP 1
+#define AO_USB_OUT_EP 4
+#define AO_USB_IN_EP 5
+#define AO_USB_CONTROL_SIZE 32
+/*
+ * Double buffer IN and OUT EPs, so each
+ * gets half of the available space
+ *
+ * Ah, but USB bulk packets can only come in 8, 16, 32 and 64
+ * byte sizes, so we'll use 64 for everything
+ */
+#define AO_USB_IN_SIZE 64
+#define AO_USB_OUT_SIZE 64
+
+#define AO_USB_EP0_IDLE 0
+#define AO_USB_EP0_DATA_IN 1
+#define AO_USB_EP0_DATA_OUT 2
+
+#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8))
+
+/* CDC definitions */
+#define CS_INTERFACE 0x24
+#define CS_ENDPOINT 0x25
+
+#define SET_LINE_CODING 0x20
+#define GET_LINE_CODING 0x21
+#define SET_CONTROL_LINE_STATE 0x22
+
+/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */
+struct ao_usb_line_coding {
+ uint32_t rate;
+ uint8_t char_format;
+ uint8_t parity;
+ uint8_t data_bits;
+} ;
+
+#endif /* _AO_USB_H_ */
diff --git a/src/cc1111.h b/src/cc1111/cc1111.h
index e52aa79f..11ea8bbb 100644
--- a/src/cc1111.h
+++ b/src/cc1111/cc1111.h
@@ -768,7 +768,7 @@ struct cc_dma_channel {
# define DMA_CFG0_TRIGGER_ADC_CH7 28
# define DMA_CFG0_TRIGGER_I2STX 28
# define DMA_CFG0_TRIGGER_ENC_DW 29
-# define DMA_CFG0_TRIGGER_DNC_UP 30
+# define DMA_CFG0_TRIGGER_ENC_UP 30
# define DMA_CFG1_SRCINC_MASK (3 << 6)
# define DMA_CFG1_SRCINC_0 (0 << 6)
@@ -1303,4 +1303,26 @@ __xdata __at (0xdf3c) uint8_t RF_PKTSTATUS;
__xdata __at (0xdf3d) uint8_t RF_VCO_VC_DAC;
#define RF_VCO_VC_DAC_OFF 0x3d
+/* AES engine */
+
+__sfr at 0xB1 ENCDI;
+__sfr at 0xB2 ENCDO;
+__xdata at (0xDFB1) volatile uint8_t ENCDIXADDR;
+__xdata at (0xDFB2) volatile uint8_t ENCDOXADDR;
+
+__sfr at 0xB3 ENCCCS;
+
+#define ENCCCS_MODE_CBC (0 << 4)
+#define ENCCCS_MODE_CFB (1 << 4)
+#define ENCCCS_MODE_OFB (2 << 4)
+#define ENCCCS_MODE_CTR (3 << 4)
+#define ENCCCS_MODE_ECB (4 << 4)
+#define ENCCCS_MODE_CBC_MAC (5 << 4)
+#define ENCCCS_RDY (1 << 3)
+#define ENCCCS_CMD_ENCRYPT (0 << 1)
+#define ENCCCS_CMD_DECRYPT (1 << 1)
+#define ENCCCS_CMD_LOAD_KEY (2 << 1)
+#define ENCCCS_CMD_LOAD_IV (3 << 1)
+#define ENCCCS_START (1 << 0)
+
#endif
diff --git a/src/altitude.h b/src/core/altitude.h
index a278bbc6..a278bbc6 100644
--- a/src/altitude.h
+++ b/src/core/altitude.h
diff --git a/src/ao.h b/src/core/ao.h
index 8ac9ac3d..04610fea 100644
--- a/src/ao.h
+++ b/src/core/ao.h
@@ -22,27 +22,22 @@
#include <stdio.h>
#include <string.h>
#include <stddef.h>
-#include "cc1111.h"
#include "ao_pins.h"
+#include <ao_arch.h>
#define TRUE 1
#define FALSE 0
/* Convert a __data pointer into an __xdata pointer */
-#define DATA_TO_XDATA(a) ((void __xdata *) ((uint8_t) (a) | 0xff00))
-
-/* Stack runs from above the allocated __data space to 0xfe, which avoids
- * writing to 0xff as that triggers the stack overflow indicator
- */
-#define AO_STACK_START 0x90
-#define AO_STACK_END 0xfe
-#define AO_STACK_SIZE (AO_STACK_END - AO_STACK_START + 1)
+#ifndef DATA_TO_XDATA
+#define DATA_TO_XDATA(a) (a)
+#endif
/* An AltOS task */
struct ao_task {
__xdata void *wchan; /* current wait channel (NULL if running) */
uint16_t alarm; /* abort ao_sleep time */
- uint8_t stack_count; /* amount of saved stack */
+ ao_arch_task_members /* any architecture-specific fields */
uint8_t task_id; /* unique id */
__code char *name; /* task name */
uint8_t stack[AO_STACK_SIZE]; /* saved stack */
@@ -73,9 +68,13 @@ ao_wakeup(__xdata void *wchan);
void
ao_alarm(uint16_t delay);
+/* Clear any pending alarm */
+void
+ao_clear_alarm(void);
+
/* Yield the processor to another task */
void
-ao_yield(void) __naked;
+ao_yield(void) ao_arch_naked_declare;
/* Add a task to the run queue */
void
@@ -136,7 +135,7 @@ ao_timer_set_adc_interval(uint8_t interval) __critical;
/* Timer interrupt */
void
-ao_timer_isr(void) __interrupt 9;
+ao_timer_isr(void) ao_arch_interrupt(9);
/* Initialize the timer */
void
@@ -149,35 +148,13 @@ ao_clock_init(void);
/*
* One set of samples read from the A/D converter or telemetry
*/
-struct ao_adc {
- uint16_t tick; /* tick when the sample was read */
- 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 */
-};
-
-#ifndef HAS_ADC
-#error Please define HAS_ADC
-#endif
#if HAS_ADC
-#if HAS_ACCEL
-#ifndef HAS_ACCEL_REF
-#error Please define HAS_ACCEL_REF
-#endif
-#else
-#define HAS_ACCEL_REF 0
-#endif
-
/*
* ao_adc.c
*/
-#define AO_ADC_RING 32
#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1))
#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1))
@@ -207,7 +184,7 @@ ao_adc_get(__xdata struct ao_adc *packet);
/* The A/D interrupt handler */
void
-ao_adc_isr(void) __interrupt 1;
+ao_adc_isr(void) ao_arch_interrupt(1);
/* Initialize the A/D converter */
void
@@ -299,25 +276,6 @@ void
ao_led_init(uint8_t enable);
/*
- * ao_romconfig.c
- */
-
-#define AO_ROMCONFIG_VERSION 2
-
-extern __code __at (0x00a0) uint16_t ao_romconfig_version;
-extern __code __at (0x00a2) uint16_t ao_romconfig_check;
-extern __code __at (0x00a4) uint16_t ao_serial_number;
-extern __code __at (0x00a6) uint32_t ao_radio_cal;
-
-#ifndef HAS_USB
-#error Please define HAS_USB
-#endif
-
-#if HAS_USB
-extern __code __at (0x00aa) uint8_t ao_usb_descriptors [];
-#endif
-
-/*
* ao_usb.c
*/
@@ -342,7 +300,7 @@ ao_usb_flush(void);
#if HAS_USB
/* USB interrupt handler */
void
-ao_usb_isr(void) __interrupt 6;
+ao_usb_isr(void) ao_arch_interrupt(6);
#endif
/* Enable the USB controller */
@@ -357,6 +315,10 @@ ao_usb_disable(void);
void
ao_usb_init(void);
+#if HAS_USB
+extern __code __at (0x00aa) uint8_t ao_usb_descriptors [];
+#endif
+
/*
* ao_cmd.c
*/
@@ -384,6 +346,12 @@ ao_cmd_put16(uint16_t v);
void
ao_cmd_white(void);
+int8_t
+ao_cmd_hexchar(char c);
+
+void
+ao_cmd_hexbyte(void);
+
void
ao_cmd_hex(void);
@@ -446,7 +414,7 @@ ao_dma_abort(uint8_t id);
/* DMA interrupt routine */
void
-ao_dma_isr(void) __interrupt 8;
+ao_dma_isr(void) ao_arch_interrupt(8);
/*
* ao_mutex.c
@@ -927,10 +895,10 @@ ao_dbg_init(void);
#endif
void
-ao_serial_rx1_isr(void) __interrupt 3;
+ao_serial_rx1_isr(void) ao_arch_interrupt(3);
void
-ao_serial_tx1_isr(void) __interrupt 14;
+ao_serial_tx1_isr(void) ao_arch_interrupt(14);
char
ao_serial_getchar(void) __critical;
@@ -1003,6 +971,27 @@ void
ao_spi_init(void);
/*
+ * ao_spi_slave.c
+ */
+
+uint8_t
+ao_spi_read(uint8_t *buf, uint8_t len);
+
+void
+ao_spi_write(uint8_t *buf, uint8_t len);
+
+void
+ao_spi_slave_init(void);
+
+/* This must be defined by the product; it will get called when chip
+ * select goes low, at which point it should use ao_spi_read and
+ * ao_spi_write to deal with the request
+ */
+
+void
+ao_spi_slave(void);
+
+/*
* ao_telemetry.c
*/
#define AO_MAX_CALLSIGN 8
@@ -1133,6 +1122,30 @@ struct ao_telemetry_companion {
/* 32 */
};
+/* #define AO_SEND_ALL_BARO */
+
+#define AO_TELEMETRY_BARO 0x80
+
+/*
+ * This packet allows the full sampling rate baro
+ * data to be captured over the RF link so that the
+ * flight software can be tested using 'real' data.
+ *
+ * Along with this telemetry packet, the flight
+ * code is modified to send full-rate telemetry all the time
+ * and never send an RDF tone; this ensure that the full radio
+ * link is available.
+ */
+struct ao_telemetry_baro {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+ uint8_t samples; /* 5 number samples */
+
+ int16_t baro[12]; /* 6 samples */
+ /* 32 */
+};
+
union ao_telemetry_all {
struct ao_telemetry_generic generic;
struct ao_telemetry_sensor sensor;
@@ -1140,6 +1153,7 @@ union ao_telemetry_all {
struct ao_telemetry_location location;
struct ao_telemetry_satellite satellite;
struct ao_telemetry_companion companion;
+ struct ao_telemetry_baro baro;
};
/*
@@ -1251,14 +1265,6 @@ struct ao_telemetry_tiny {
char callsign[AO_MAX_CALLSIGN];
};
-/*
- * ao_radio_recv tacks on rssi and status bytes
- */
-
-struct ao_telemetry_raw_recv {
- uint8_t packet[AO_MAX_TELEMETRY + 2];
-};
-
struct ao_telemetry_orig_recv {
struct ao_telemetry_orig telemetry_orig;
int8_t rssi;
@@ -1271,11 +1277,25 @@ struct ao_telemetry_tiny_recv {
uint8_t status;
};
+/*
+ * ao_radio_recv tacks on rssi and status bytes
+ */
+
+struct ao_telemetry_raw_recv {
+ uint8_t packet[AO_MAX_TELEMETRY + 2];
+};
+
/* Set delay between telemetry reports (0 to disable) */
+#ifdef AO_SEND_ALL_BARO
+#define AO_TELEMETRY_INTERVAL_PAD AO_MS_TO_TICKS(100)
+#define AO_TELEMETRY_INTERVAL_FLIGHT AO_MS_TO_TICKS(100)
+#define AO_TELEMETRY_INTERVAL_RECOVER AO_MS_TO_TICKS(100)
+#else
#define AO_TELEMETRY_INTERVAL_PAD AO_MS_TO_TICKS(1000)
#define AO_TELEMETRY_INTERVAL_FLIGHT AO_MS_TO_TICKS(100)
#define AO_TELEMETRY_INTERVAL_RECOVER AO_MS_TO_TICKS(1000)
+#endif
void
ao_telemetry_set_interval(uint16_t interval);
@@ -1302,7 +1322,7 @@ extern __xdata uint8_t ao_radio_done;
extern __xdata uint8_t ao_radio_mutex;
void
-ao_radio_general_isr(void) __interrupt 16;
+ao_radio_general_isr(void) ao_arch_interrupt(16);
void
ao_radio_get(uint8_t len);
@@ -1321,8 +1341,18 @@ ao_radio_recv(__xdata void *data, uint8_t size) __reentrant;
void
ao_radio_recv_abort(void);
+/*
+ * Compute the packet length as follows:
+ *
+ * 2000 bps (for a 1kHz tone)
+ * so, for 'ms' milliseconds, we need
+ * 2 * ms bits, or ms / 4 bytes
+ */
+
+#define AO_MS_TO_RDF_LEN(ms) ((ms) > 255 * 4 ? 255 : ((ms) >> 2))
+
void
-ao_radio_rdf(int ms);
+ao_radio_rdf(uint8_t pkt_len);
void
ao_radio_rdf_abort(void);
@@ -1339,6 +1369,21 @@ ao_radio_init(void);
extern const char const * const ao_state_names[];
+#define AO_MONITOR_RING 8
+
+union ao_monitor {
+ struct ao_telemetry_raw_recv raw;
+ struct ao_telemetry_orig_recv orig;
+ struct ao_telemetry_tiny_recv tiny;
+};
+
+extern __xdata union ao_monitor ao_monitor_ring[AO_MONITOR_RING];
+
+#define ao_monitor_ring_next(n) (((n) + 1) & (AO_MONITOR_RING - 1))
+
+extern __data uint8_t ao_monitoring;
+extern __data uint8_t ao_monitor_head;
+
void
ao_monitor(void);
@@ -1401,9 +1446,19 @@ enum ao_igniter_status {
ao_igniter_open, /* open circuit detected */
};
+struct ao_ignition {
+ uint8_t request;
+ uint8_t fired;
+ uint8_t firing;
+};
+
+extern __xdata struct ao_ignition ao_ignition[2];
+
enum ao_igniter_status
ao_igniter_status(enum ao_igniter igniter);
+extern __pdata uint8_t ao_igniter_present;
+
void
ao_ignite_set_pins(void);
@@ -1415,7 +1470,8 @@ ao_igniter_init(void);
*/
#define AO_CONFIG_MAJOR 1
-#define AO_CONFIG_MINOR 8
+#define AO_CONFIG_MINOR 9
+#define AO_AES_LEN 16
struct ao_config {
uint8_t major;
@@ -1432,6 +1488,7 @@ struct ao_config {
uint8_t pad_orientation; /* minor version 6 */
uint32_t radio_setting; /* minor version 7 */
uint8_t radio_enable; /* minor version 8 */
+ uint8_t aes_key[AO_AES_LEN]; /* minor version 9 */
};
#define AO_IGNITE_MODE_DUAL 0
@@ -1600,11 +1657,164 @@ struct ao_companion_setup {
};
extern __pdata uint8_t ao_companion_running;
-extern __xdata struct ao_companion_setup ao_companion_setup;
extern __xdata uint8_t ao_companion_mutex;
+extern __xdata struct ao_companion_command ao_companion_command;
+extern __xdata struct ao_companion_setup ao_companion_setup;
extern __xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS];
void
ao_companion_init(void);
+/* ao_lcd.c */
+
+void
+ao_lcd_init(void);
+
+/* ao_aes.c */
+
+__xdata uint8_t ao_aes_mutex;
+
+/* AES keys and blocks are 128 bits */
+
+enum ao_aes_mode {
+ ao_aes_mode_cbc_mac
+};
+
+#if HAS_AES
+void
+ao_aes_isr(void) __interrupt 4;
+#endif
+
+void
+ao_aes_set_mode(enum ao_aes_mode mode);
+
+void
+ao_aes_set_key(__xdata uint8_t *in);
+
+void
+ao_aes_zero_iv(void);
+
+void
+ao_aes_run(__xdata uint8_t *in,
+ __xdata uint8_t *out);
+
+void
+ao_aes_init(void);
+
+/* ao_radio_cmac.c */
+
+int8_t
+ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant;
+
+#define AO_RADIO_CMAC_OK 0
+#define AO_RADIO_CMAC_LEN_ERROR -1
+#define AO_RADIO_CMAC_CRC_ERROR -2
+#define AO_RADIO_CMAC_MAC_ERROR -3
+#define AO_RADIO_CMAC_TIMEOUT -4
+
+int8_t
+ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant;
+
+void
+ao_radio_cmac_init(void);
+
+/* ao_launch.c */
+
+struct ao_launch_command {
+ uint16_t tick;
+ uint16_t serial;
+ uint8_t cmd;
+ uint8_t channel;
+ uint16_t unused;
+};
+
+#define AO_LAUNCH_QUERY 1
+
+struct ao_launch_query {
+ uint16_t tick;
+ uint16_t serial;
+ uint8_t channel;
+ uint8_t valid;
+ uint8_t arm_status;
+ uint8_t igniter_status;
+};
+
+#define AO_LAUNCH_ARM 2
+#define AO_LAUNCH_FIRE 3
+
+void
+ao_launch_init(void);
+
+/*
+ * ao_log_single.c
+ */
+
+#define AO_LOG_TELESCIENCE_START ((uint8_t) 's')
+#define AO_LOG_TELESCIENCE_DATA ((uint8_t) 'd')
+
+#define AO_LOG_TELESCIENCE_NUM_ADC 12
+
+struct ao_log_telescience {
+ uint8_t type;
+ uint8_t csum;
+ uint16_t tick;
+ uint16_t tm_tick;
+ uint8_t tm_state;
+ uint8_t unused;
+ uint16_t adc[AO_LOG_TELESCIENCE_NUM_ADC];
+};
+
+#define AO_LOG_SINGLE_SIZE 32
+
+union ao_log_single {
+ struct ao_log_telescience telescience;
+ union ao_telemetry_all telemetry;
+ uint8_t bytes[AO_LOG_SINGLE_SIZE];
+};
+
+extern __xdata union ao_log_single ao_log_single_write_data;
+extern __xdata union ao_log_single ao_log_single_read_data;
+
+void
+ao_log_single_extra_query(void);
+
+void
+ao_log_single_list(void);
+
+void
+ao_log_single_main(void);
+
+uint8_t
+ao_log_single_write(void);
+
+uint8_t
+ao_log_single_read(uint32_t pos);
+
+void
+ao_log_single_start(void);
+
+void
+ao_log_single_stop(void);
+
+void
+ao_log_single_restart(void);
+
+void
+ao_log_single_set(void);
+
+void
+ao_log_single_delete(void);
+
+void
+ao_log_single_init(void);
+
+void
+ao_log_single(void);
+
+/*
+ * ao_pyro_slave.c
+ */
+
+#define AO_TELEPYRO_NUM_ADC 9
+
#endif /* _AO_H_ */
diff --git a/src/ao_cmd.c b/src/core/ao_cmd.c
index 8037195a..2b64b8ca 100644
--- a/src/ao_cmd.c
+++ b/src/core/ao_cmd.c
@@ -22,7 +22,7 @@ __pdata uint32_t ao_cmd_lex_u32;
__pdata char ao_cmd_lex_c;
__pdata enum ao_cmd_status ao_cmd_status;
-#define CMD_LEN 32
+#define CMD_LEN 48
static __xdata char cmd_line[CMD_LEN];
static __pdata uint8_t cmd_len;
@@ -32,7 +32,7 @@ static void
put_string(__code char *s)
{
char c;
- while (c = *s++)
+ while ((c = *s++))
putchar(c);
}
@@ -128,22 +128,48 @@ ao_cmd_white(void)
ao_cmd_lex();
}
+int8_t
+ao_cmd_hexchar(char c)
+{
+ 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);
+ return -1;
+}
+
+void
+ao_cmd_hexbyte(void)
+{
+ uint8_t i;
+ int8_t n;
+
+ ao_cmd_lex_i = 0;
+ ao_cmd_white();
+ for (i = 0; i < 2; i++) {
+ n = ao_cmd_hexchar(ao_cmd_lex_c);
+ if (n < 0) {
+ ao_cmd_status = ao_cmd_syntax_error;
+ break;
+ }
+ ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n;
+ ao_cmd_lex();
+ }
+}
+
void
ao_cmd_hex(void)
{
__pdata uint8_t r = ao_cmd_lex_error;
- uint8_t n;
+ int8_t n;
ao_cmd_lex_i = 0;
ao_cmd_white();
for(;;) {
- if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
- n = (ao_cmd_lex_c - '0');
- else if ('a' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'f')
- n = (ao_cmd_lex_c - 'a' + 10);
- else if ('A' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'F')
- n = (ao_cmd_lex_c - 'A' + 10);
- else
+ n = ao_cmd_hexchar(ao_cmd_lex_c);
+ if (n < 0)
break;
ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n;
r = ao_cmd_success;
@@ -188,13 +214,6 @@ ao_match_word(__code char *word)
}
static void
-eol(void)
-{
- while (ao_cmd_lex_c != '\n')
- ao_cmd_lex();
-}
-
-static void
echo(void)
{
ao_cmd_hex();
@@ -208,15 +227,13 @@ ao_reboot(void)
ao_cmd_white();
if (!ao_match_word("eboot"))
return;
-
/* Delay waiting for the packet master to be turned off
* so that we don't end up back in idle mode because we
* received a packet after boot.
*/
flush();
ao_delay(AO_SEC_TO_TICKS(1));
- WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_64;
- ao_delay(AO_SEC_TO_TICKS(2));
+ ao_arch_reboot();
ao_panic(AO_PANIC_REBOOT);
}
@@ -226,7 +243,7 @@ version(void)
printf("manufacturer %s\n", ao_manufacturer);
printf("product %s\n", ao_product);
printf("serial-number %u\n", ao_serial_number);
-#if HAS_EEPROM
+#if HAS_LOG
printf("log-format %u\n", ao_log_format);
#endif
printf("software-version %s\n", ao_version);
@@ -261,6 +278,7 @@ report(void)
case ao_cmd_syntax_error:
puts("Syntax error");
ao_cmd_status = 0;
+ default:
break;
}
}
diff --git a/src/ao_config.c b/src/core/ao_config.c
index 0c10e608..a653bed2 100644
--- a/src/ao_config.c
+++ b/src/core/ao_config.c
@@ -47,7 +47,9 @@ _ao_config_put(void)
ao_storage_setup();
ao_storage_erase(ao_storage_config);
ao_storage_write(ao_storage_config, &ao_config, sizeof (ao_config));
+#if HAS_FLIGHT
ao_log_write_erase(0);
+#endif
ao_storage_flush();
}
@@ -72,11 +74,14 @@ _ao_config_get(void)
if (ao_config.major != AO_CONFIG_MAJOR) {
ao_config.major = AO_CONFIG_MAJOR;
ao_config.minor = 0;
+
+ /* Version 0 stuff */
ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY;
ao_config.radio_channel = AO_CONFIG_DEFAULT_RADIO_CHANNEL;
memset(&ao_config.callsign, '\0', sizeof (ao_config.callsign));
memcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN,
sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1);
+ ao_config_dirty = 1;
}
if (ao_config.minor < AO_CONFIG_MINOR) {
/* Fixups for minor version 1 */
@@ -102,6 +107,8 @@ _ao_config_get(void)
ao_config.radio_setting = ao_config.radio_cal;
if (ao_config.minor < 8)
ao_config.radio_enable = TRUE;
+ if (ao_config.minor < 9)
+ memset(&ao_config.aes_key, 0, AO_AES_LEN);
ao_config.minor = AO_CONFIG_MINOR;
ao_config_dirty = 1;
}
@@ -301,7 +308,7 @@ ao_config_radio_cal_set(void) __reentrant
_ao_config_edit_finish();
}
-#if HAS_EEPROM
+#if HAS_LOG
void
ao_config_log_show(void) __reentrant
{
@@ -329,7 +336,7 @@ ao_config_log_set(void) __reentrant
_ao_config_edit_finish();
}
}
-#endif /* HAS_EEPROM */
+#endif /* HAS_LOG */
#if HAS_IGNITE
void
@@ -412,6 +419,33 @@ ao_config_radio_enable_set(void) __reentrant
_ao_config_edit_finish();
}
+#if HAS_AES
+void
+ao_config_key_show(void) __reentrant
+{
+ uint8_t i;
+ printf("AES key: ");
+ for (i = 0; i < AO_AES_LEN; i++)
+ printf ("%02x", ao_config.aes_key[i]);
+ printf("\n");
+}
+
+void
+ao_config_key_set(void) __reentrant
+{
+ uint8_t i;
+
+ _ao_config_edit_start();
+ for (i = 0; i < AO_AES_LEN; i++) {
+ ao_cmd_hexbyte();
+ if (ao_cmd_status != ao_cmd_success)
+ break;
+ ao_config.aes_key[i] = ao_cmd_lex_i;
+ }
+ _ao_config_edit_finish();
+}
+#endif
+
struct ao_config_var {
__code char *str;
void (*set)(void) __reentrant;
@@ -448,7 +482,7 @@ __code struct ao_config_var ao_config_vars[] = {
#endif /* HAS_ACCEL */
{ "f <cal>\0Radio calib (cal = rf/(xtal/2^16))",
ao_config_radio_cal_set, ao_config_radio_cal_show },
-#if HAS_EEPROM
+#if HAS_LOG
{ "l <size>\0Flight log size in kB",
ao_config_log_set, ao_config_log_show },
#endif
@@ -460,6 +494,10 @@ __code struct ao_config_var ao_config_vars[] = {
{ "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 },
+#endif
{ "s\0Show",
ao_config_show, 0 },
#if HAS_EEPROM
diff --git a/src/ao_convert.c b/src/core/ao_convert.c
index 0969f107..0969f107 100644
--- a/src/ao_convert.c
+++ b/src/core/ao_convert.c
diff --git a/src/ao_convert_test.c b/src/core/ao_convert_test.c
index e2c28b73..e2c28b73 100644
--- a/src/ao_convert_test.c
+++ b/src/core/ao_convert_test.c
diff --git a/src/ao_ee_fake.c b/src/core/ao_ee_fake.c
index b0c1d61e..b0c1d61e 100644
--- a/src/ao_ee_fake.c
+++ b/src/core/ao_ee_fake.c
diff --git a/src/ao_flight.c b/src/core/ao_flight.c
index 0a9cc046..433efeae 100644
--- a/src/ao_flight.c
+++ b/src/core/ao_flight.c
@@ -34,7 +34,7 @@
/* Main flight thread. */
__pdata enum ao_flight_state ao_flight_state; /* current flight state */
-__pdata uint16_t ao_launch_tick; /* time of launch detect */
+__pdata uint16_t ao_boost_tick; /* time of launch detect */
/*
* track min/max data over a long interval to detect
@@ -160,7 +160,7 @@ ao_flight(void)
)
{
ao_flight_state = ao_flight_boost;
- ao_launch_tick = ao_sample_tick;
+ ao_boost_tick = ao_sample_tick;
/* start logging data */
ao_log_start();
@@ -193,7 +193,7 @@ ao_flight(void)
* (15 seconds) has past.
*/
if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) ||
- (int16_t) (ao_sample_tick - ao_launch_tick) > BOOST_TICKS_MAX)
+ (int16_t) (ao_sample_tick - ao_boost_tick) > BOOST_TICKS_MAX)
{
#if HAS_ACCEL
ao_flight_state = ao_flight_fast;
@@ -214,7 +214,8 @@ ao_flight(void)
{
ao_flight_state = ao_flight_coast;
ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
- }
+ } else
+ goto check_re_boost;
break;
#endif
case ao_flight_coast:
@@ -246,6 +247,16 @@ ao_flight(void)
ao_flight_state = ao_flight_drogue;
ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
}
+#if HAS_ACCEL
+ else {
+ check_re_boost:
+ if (ao_accel > AO_MSS_TO_ACCEL(20)) {
+ ao_boost_tick = ao_sample_tick;
+ ao_flight_state = ao_flight_boost;
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+ }
+ }
+#endif
break;
case ao_flight_drogue:
diff --git a/src/ao_flight_nano.c b/src/core/ao_flight_nano.c
index 2e332b12..2e332b12 100644
--- a/src/ao_flight_nano.c
+++ b/src/core/ao_flight_nano.c
diff --git a/src/ao_gps_print.c b/src/core/ao_gps_print.c
index fcdedd30..fcdedd30 100644
--- a/src/ao_gps_print.c
+++ b/src/core/ao_gps_print.c
diff --git a/src/ao_gps_report.c b/src/core/ao_gps_report.c
index e57f8744..e57f8744 100644
--- a/src/ao_gps_report.c
+++ b/src/core/ao_gps_report.c
diff --git a/src/ao_host.h b/src/core/ao_host.h
index 65c25fe5..65c25fe5 100644
--- a/src/ao_host.h
+++ b/src/core/ao_host.h
diff --git a/src/ao_kalman.c b/src/core/ao_kalman.c
index ee01949e..ee01949e 100644
--- a/src/ao_kalman.c
+++ b/src/core/ao_kalman.c
diff --git a/src/ao_log.c b/src/core/ao_log.c
index 6d3ad535..6d3ad535 100644
--- a/src/ao_log.c
+++ b/src/core/ao_log.c
diff --git a/src/ao_log_big.c b/src/core/ao_log_big.c
index 74d94c4b..74d94c4b 100644
--- a/src/ao_log_big.c
+++ b/src/core/ao_log_big.c
diff --git a/src/core/ao_log_single.c b/src/core/ao_log_single.c
new file mode 100644
index 00000000..9e90bd82
--- /dev/null
+++ b/src/core/ao_log_single.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright © 2011 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.
+ */
+
+/*
+ * ao_log_single.c
+ *
+ * Stores a sequence of fixed-size (32 byte) chunks
+ * without splitting memory up into separate flights
+ */
+
+#include "ao.h"
+#include "ao_product.h"
+
+static __xdata struct ao_task ao_log_single_task;
+
+__xdata uint8_t ao_log_running;
+__xdata uint8_t ao_log_mutex;
+__pdata uint32_t ao_log_start_pos;
+__pdata uint32_t ao_log_end_pos;
+__pdata uint32_t ao_log_current_pos;
+
+__xdata union ao_log_single ao_log_single_write_data;
+__xdata union ao_log_single ao_log_single_read_data;
+
+uint8_t
+ao_log_single_write(void)
+{
+ uint8_t wrote = 0;
+
+ ao_mutex_get(&ao_log_mutex); {
+ if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+ ao_log_single_stop();
+ if (ao_log_running) {
+ wrote = 1;
+ ao_storage_write(ao_log_current_pos,
+ &ao_log_single_write_data,
+ AO_LOG_SINGLE_SIZE);
+ ao_log_current_pos += AO_LOG_SINGLE_SIZE;
+ }
+ } ao_mutex_put(&ao_log_mutex);
+ return wrote;
+}
+
+static uint8_t
+ao_log_single_valid(void)
+{
+ __xdata uint8_t *d = ao_log_single_read_data.bytes;
+ uint8_t i;
+ for (i = 0; i < AO_LOG_SINGLE_SIZE; i++)
+ if (*d++ != 0xff)
+ return 1;
+ return 0;
+}
+
+uint8_t
+ao_log_single_read(uint32_t pos)
+{
+ if (!ao_storage_read(pos, &ao_log_single_read_data, AO_LOG_SINGLE_SIZE))
+ return 0;
+ return ao_log_single_valid();
+}
+
+void
+ao_log_single_start(void)
+{
+ if (!ao_log_running) {
+ ao_log_running = 1;
+ ao_wakeup(&ao_log_running);
+ }
+}
+
+void
+ao_log_single_stop(void)
+{
+ if (ao_log_running) {
+ ao_log_running = 0;
+ }
+}
+
+void
+ao_log_single_restart(void)
+{
+ /* Find end of data */
+ ao_log_end_pos = ao_storage_config;
+ for (ao_log_current_pos = 0;
+ ao_log_current_pos < ao_storage_config;
+ ao_log_current_pos += ao_storage_block)
+ {
+ if (!ao_log_single_read(ao_log_current_pos))
+ break;
+ }
+ if (ao_log_current_pos > 0) {
+ ao_log_current_pos -= ao_storage_block;
+ for (; ao_log_current_pos < ao_storage_config;
+ ao_log_current_pos += sizeof (struct ao_log_telescience))
+ {
+ if (!ao_log_single_read(ao_log_current_pos))
+ break;
+ }
+ }
+}
+
+void
+ao_log_single_set(void)
+{
+ printf("Logging currently %s\n", ao_log_running ? "on" : "off");
+ ao_cmd_hex();
+ if (ao_cmd_status == ao_cmd_success) {
+ if (ao_cmd_lex_i) {
+ printf("Logging from %ld to %ld\n", ao_log_current_pos, ao_log_end_pos);
+ ao_log_single_start();
+ } else {
+ printf ("Log stopped at %ld\n", ao_log_current_pos);
+ ao_log_single_stop();
+ }
+ }
+ ao_cmd_status = ao_cmd_success;
+}
+
+void
+ao_log_single_delete(void)
+{
+ uint32_t pos;
+
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ if (ao_cmd_lex_i != 1) {
+ ao_cmd_status = ao_cmd_syntax_error;
+ printf("No such flight: %d\n", ao_cmd_lex_i);
+ return;
+ }
+ ao_log_single_stop();
+ for (pos = 0; pos < ao_storage_config; pos += ao_storage_block) {
+ if (!ao_log_single_read(pos))
+ break;
+ ao_storage_erase(pos);
+ }
+ ao_log_current_pos = ao_log_start_pos = 0;
+ if (pos == 0)
+ printf("No such flight: %d\n", ao_cmd_lex_i);
+ else
+ printf ("Erased\n");
+}
+
+uint8_t
+ao_log_full(void)
+{
+ return ao_log_current_pos >= ao_log_end_pos;
+}
+
+uint8_t
+ao_log_present(void)
+{
+ return ao_log_single_read(0);
+}
+
+static void
+ao_log_single_query(void)
+{
+ printf("Logging enabled: %d\n", ao_log_running);
+ printf("Log start: %ld\n", ao_log_start_pos);
+ printf("Log cur: %ld\n", ao_log_current_pos);
+ printf("Log end: %ld\n", ao_log_end_pos);
+ ao_log_single_extra_query();
+}
+
+const struct ao_cmds ao_log_single_cmds[] = {
+ { ao_log_single_set, "L <0 off, 1 on>\0Set logging mode" },
+ { ao_log_single_list, "l\0List stored flight logs" },
+ { ao_log_single_delete, "d 1\0Delete all stored flights" },
+ { ao_log_single_query, "q\0Query log status" },
+ { 0, NULL },
+};
+
+void
+ao_log_single_init(void)
+{
+ ao_log_running = 0;
+
+ ao_cmd_register(&ao_log_single_cmds[0]);
+
+ ao_add_task(&ao_log_single_task, ao_log_single, "log");
+}
diff --git a/src/core/ao_log_telem.c b/src/core/ao_log_telem.c
new file mode 100644
index 00000000..096ad919
--- /dev/null
+++ b/src/core/ao_log_telem.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEMETRY;
+
+static __data uint8_t ao_log_monitor_pos;
+__pdata enum ao_flight_state ao_flight_state;
+__pdata int16_t ao_max_height; /* max of ao_height */
+__pdata int16_t sense_d, sense_m;
+__pdata uint8_t ao_igniter_present;
+
+static void
+ao_log_telem_track() {
+ if (ao_monitoring == sizeof (union ao_telemetry_all)) {
+ switch (ao_log_single_write_data.telemetry.generic.type) {
+ case AO_TELEMETRY_SENSOR_TELEMETRUM:
+ case AO_TELEMETRY_SENSOR_TELEMINI:
+ /* fall through ... */
+ case AO_TELEMETRY_SENSOR_TELENANO:
+ if (ao_log_single_write_data.telemetry.generic.type == AO_TELEMETRY_SENSOR_TELENANO) {
+ ao_igniter_present = 0;
+ } else {
+ sense_d = ao_log_single_write_data.telemetry.sensor.sense_d;
+ sense_m = ao_log_single_write_data.telemetry.sensor.sense_m;
+ ao_igniter_present = 1;
+ }
+ if (ao_log_single_write_data.telemetry.sensor.height > ao_max_height) {
+ ao_max_height = ao_log_single_write_data.telemetry.sensor.height;
+ }
+ if (ao_log_single_write_data.telemetry.sensor.state != ao_flight_state) {
+ ao_flight_state = ao_log_single_write_data.telemetry.sensor.state;
+ if (ao_flight_state == ao_flight_pad)
+ ao_max_height = 0;
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+ }
+ }
+ }
+}
+
+enum ao_igniter_status
+ao_igniter_status(enum ao_igniter igniter)
+{
+ int16_t value;
+
+ switch (igniter) {
+ case ao_igniter_drogue:
+ value = sense_d;
+ break;
+ case ao_igniter_main:
+ value = sense_m;
+ break;
+ default:
+ value = 0;
+ break;
+ }
+ if (value < AO_IGNITER_OPEN)
+ return ao_igniter_open;
+ else if (value > AO_IGNITER_CLOSED)
+ return ao_igniter_ready;
+ else
+ return ao_igniter_unknown;
+}
+
+void
+ao_log_single(void)
+{
+ ao_storage_setup();
+
+ /* This can take a while, so let the rest
+ * of the system finish booting before we start
+ */
+ ao_delay(AO_SEC_TO_TICKS(2));
+
+ ao_log_running = 1;
+ ao_log_single_restart();
+ ao_flight_state = ao_flight_startup;
+ for (;;) {
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+
+ ao_log_monitor_pos = ao_monitor_head;
+ 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_log_single_write();
+ ao_log_monitor_pos = ao_monitor_ring_next(ao_log_monitor_pos);
+ ao_log_telem_track();
+ }
+ /* Wait for more telemetry data to arrive */
+ ao_sleep(DATA_TO_XDATA(&ao_monitor_head));
+ }
+ }
+}
+
+void
+ao_log_single_list(void)
+{
+ if (ao_log_current_pos != 0)
+ printf("flight 1 start %x end %x\n",
+ 0,
+ (uint16_t) ((ao_log_current_pos + 0xff) >> 8));
+ printf ("done\n");
+}
+
+void
+ao_log_single_extra_query(void)
+{
+}
diff --git a/src/core/ao_log_telescience.c b/src/core/ao_log_telescience.c
new file mode 100644
index 00000000..31eda381
--- /dev/null
+++ b/src/core/ao_log_telescience.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_product.h"
+
+static uint8_t ao_log_adc_pos;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_TELESCIENCE;
+
+static void
+ao_log_telescience_csum(void) __reentrant
+{
+ __xdata uint8_t *b = ao_log_single_write_data.bytes;
+ uint8_t sum = 0x5a;
+ uint8_t i;
+
+ ao_log_single_write_data.telescience.csum = 0;
+ for (i = 0; i < sizeof (struct ao_log_telescience); i++)
+ sum += *b++;
+ ao_log_single_write_data.telescience.csum = -sum;
+}
+
+void
+ao_log_single(void)
+{
+ ao_storage_setup();
+
+ /* This can take a while, so let the rest
+ * of the system finish booting before we start
+ */
+ ao_delay(AO_SEC_TO_TICKS(10));
+
+ ao_log_single_restart();
+ for (;;) {
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+
+ ao_log_start_pos = ao_log_current_pos;
+ ao_log_single_write_data.telescience.type = AO_LOG_TELESCIENCE_START;
+ ao_log_single_write_data.telescience.tick = ao_time();
+ ao_log_single_write_data.telescience.adc[0] = ao_companion_command.serial;
+ ao_log_single_write_data.telescience.adc[1] = ao_companion_command.flight;
+ ao_log_telescience_csum();
+ ao_log_single_write();
+ /* Write the whole contents of the ring to the log
+ * when starting up.
+ */
+ ao_log_adc_pos = ao_adc_ring_next(ao_adc_head);
+ ao_log_single_write_data.telescience.type = AO_LOG_TELESCIENCE_DATA;
+ while (ao_log_running) {
+ /* Write samples to EEPROM */
+ while (ao_log_adc_pos != ao_adc_head) {
+ ao_log_single_write_data.telescience.tick = ao_adc_ring[ao_log_adc_pos].tick;
+ memcpy(&ao_log_single_write_data.telescience.adc, (void *) ao_adc_ring[ao_log_adc_pos].adc,
+ AO_LOG_TELESCIENCE_NUM_ADC * sizeof (uint16_t));
+ ao_log_telescience_csum();
+ ao_log_single_write();
+ ao_log_adc_pos = ao_adc_ring_next(ao_log_adc_pos);
+ }
+ /* Wait for more ADC data to arrive */
+ ao_sleep((void *) &ao_adc_head);
+ }
+ memset(&ao_log_single_write_data.telescience.adc, '\0', sizeof (ao_log_single_write_data.telescience.adc));
+ }
+}
+
+void
+ao_log_single_list(void)
+{
+ uint32_t pos;
+ uint32_t start = 0;
+ uint8_t flight = 0;
+
+ for (pos = 0; ; pos += sizeof (struct ao_log_telescience)) {
+ if (pos >= ao_storage_config ||
+ !ao_log_single_read(pos) ||
+ ao_log_single_read_data.telescience.type == AO_LOG_TELESCIENCE_START)
+ {
+ if (pos != start) {
+ printf("flight %d start %x end %x\n",
+ flight,
+ (uint16_t) (start >> 8),
+ (uint16_t) ((pos + 0xff) >> 8)); flush();
+ }
+ if (ao_log_single_read_data.telescience.type != AO_LOG_TELESCIENCE_START)
+ break;
+ start = pos;
+ flight++;
+ }
+ }
+ printf ("done\n");
+}
+
+void
+ao_log_single_extra_query(void)
+{
+ printf("log data tick: %04x\n", ao_log_single_write_data.telescience.tick);
+ printf("TM data tick: %04x\n", ao_log_single_write_data.telescience.tm_tick);
+ printf("TM state: %d\n", ao_log_single_write_data.telescience.tm_state);
+ printf("TM serial: %d\n", ao_companion_command.serial);
+ printf("TM flight: %d\n", ao_companion_command.flight);
+}
diff --git a/src/ao_log_tiny.c b/src/core/ao_log_tiny.c
index d5a3b99f..d5a3b99f 100644
--- a/src/ao_log_tiny.c
+++ b/src/core/ao_log_tiny.c
diff --git a/src/ao_monitor.c b/src/core/ao_monitor.c
index 69eb58e8..56d7604d 100644
--- a/src/ao_monitor.c
+++ b/src/core/ao_monitor.c
@@ -22,18 +22,10 @@
#error Must define HAS_MONITOR to 1
#endif
-__xdata uint8_t ao_monitoring;
+__data uint8_t ao_monitoring;
__pdata uint8_t ao_monitor_led;
-#define AO_MONITOR_RING 8
-
-__xdata union ao_monitor {
- struct ao_telemetry_raw_recv raw;
- struct ao_telemetry_orig_recv orig;
- struct ao_telemetry_tiny_recv tiny;
-} ao_monitor_ring[AO_MONITOR_RING];
-
-#define ao_monitor_ring_next(n) (((n) + 1) & (AO_MONITOR_RING - 1))
+__xdata union ao_monitor ao_monitor_ring[AO_MONITOR_RING];
__data uint8_t ao_monitor_head;
@@ -45,7 +37,7 @@ ao_monitor_get(void)
for (;;) {
switch (ao_monitoring) {
case 0:
- ao_sleep(&ao_monitoring);
+ ao_sleep(DATA_TO_XDATA(&ao_monitoring));
continue;
case AO_MONITORING_ORIG:
size = sizeof (struct ao_telemetry_orig_recv);
@@ -63,7 +55,15 @@ ao_monitor_get(void)
continue;
ao_monitor_head = ao_monitor_ring_next(ao_monitor_head);
ao_wakeup(DATA_TO_XDATA(&ao_monitor_head));
- ao_led_toggle(ao_monitor_led);
+ }
+}
+
+void
+ao_monitor_blink(void)
+{
+ for (;;) {
+ ao_sleep(DATA_TO_XDATA(&ao_monitor_head));
+ ao_led_for(ao_monitor_led, AO_MS_TO_TICKS(100));
}
}
@@ -159,7 +159,9 @@ ao_monitor_put(void)
ao_gps_print(&recv_orig.telemetry_orig.gps);
ao_gps_tracking_print(&recv_orig.telemetry_orig.gps_tracking);
putchar('\n');
+#if HAS_RSSI
ao_rssi_set(rssi);
+#endif
} else {
printf("CRC INVALID RSSI %3d\n", rssi);
}
@@ -222,7 +224,9 @@ ao_monitor_put(void)
recv_tiny.telemetry_tiny.flight_vel,
recv_tiny.telemetry_tiny.flight_pres);
#endif
+#if HAS_RSSI
ao_rssi_set(rssi);
+#endif
} else {
printf("CRC INVALID RSSI %3d\n", rssi);
}
@@ -236,6 +240,12 @@ ao_monitor_put(void)
printf("%02x", byte);
}
printf("%02x\n", sum);
+#if HAS_RSSI
+ if (recv_raw.packet[ao_monitoring + 1] & PKT_APPEND_STATUS_1_CRC_OK) {
+ rssi = ((int16_t) recv_raw.packet[ao_monitoring] >> 1) - 74;
+ ao_rssi_set(rssi);
+ }
+#endif
break;
}
ao_usb_flush();
@@ -244,6 +254,7 @@ ao_monitor_put(void)
__xdata struct ao_task ao_monitor_get_task;
__xdata struct ao_task ao_monitor_put_task;
+__xdata struct ao_task ao_monitor_blink_task;
void
ao_set_monitor(uint8_t monitoring)
@@ -251,7 +262,7 @@ ao_set_monitor(uint8_t monitoring)
if (ao_monitoring)
ao_radio_recv_abort();
ao_monitoring = monitoring;
- ao_wakeup(&ao_monitoring);
+ ao_wakeup(DATA_TO_XDATA(&ao_monitoring));
}
static void
@@ -274,4 +285,6 @@ ao_monitor_init(uint8_t monitor_led, uint8_t monitoring) __reentrant
ao_cmd_register(&ao_monitor_cmds[0]);
ao_add_task(&ao_monitor_get_task, ao_monitor_get, "monitor_get");
ao_add_task(&ao_monitor_put_task, ao_monitor_put, "monitor_put");
+ if (ao_monitor_led)
+ ao_add_task(&ao_monitor_blink_task, ao_monitor_blink, "monitor_blink");
}
diff --git a/src/ao_mutex.c b/src/core/ao_mutex.c
index c82a7d57..c82a7d57 100644
--- a/src/ao_mutex.c
+++ b/src/core/ao_mutex.c
diff --git a/src/ao_panic.c b/src/core/ao_panic.c
index fdada201..244917a8 100644
--- a/src/ao_panic.c
+++ b/src/core/ao_panic.c
@@ -24,6 +24,10 @@
#if !HAS_BEEP
#define ao_beep(x)
#endif
+#if !LEDS_AVAILABLE
+#define ao_led_on(x)
+#define ao_led_off(x)
+#endif
static void
ao_panic_delay(uint8_t n)
@@ -33,7 +37,7 @@ ao_panic_delay(uint8_t n)
while (n--)
while (--j)
while (--i)
- _asm nop _endasm;
+ ao_arch_nop();
}
void
@@ -53,7 +57,10 @@ ao_panic(uint8_t reason)
}
ao_beep(AO_BEEP_OFF);
ao_panic_delay(2);
+
+#ifdef SDCC
#pragma disable_warning 126
+#endif
for (n = 0; n < reason; n++) {
ao_led_on(AO_LED_RED);
ao_beep(AO_BEEP_MID);
diff --git a/src/ao_product.c b/src/core/ao_product.c
index fb59580b..fb59580b 100644
--- a/src/ao_product.c
+++ b/src/core/ao_product.c
diff --git a/src/ao_report.c b/src/core/ao_report.c
index 3cf558e1..70f0b49d 100644
--- a/src/ao_report.c
+++ b/src/core/ao_report.c
@@ -109,7 +109,7 @@ ao_report_altitude(void)
}
}
-#if HAS_IGNITE
+#if HAS_IGNITE_REPORT
static uint8_t
ao_report_igniter_ready(enum ao_igniter igniter)
{
@@ -119,7 +119,13 @@ ao_report_igniter_ready(enum ao_igniter igniter)
static void
ao_report_continuity(void) __reentrant
{
- uint8_t c = (ao_report_igniter_ready(ao_igniter_drogue) |
+ uint8_t c;
+
+#if !HAS_IGNITE
+ if (!ao_igniter_present)
+ return;
+#endif
+ c = (ao_report_igniter_ready(ao_igniter_drogue) |
(ao_report_igniter_ready(ao_igniter_main) << 1));
if (c) {
while (c--) {
@@ -133,6 +139,7 @@ ao_report_continuity(void) __reentrant
low(AO_MS_TO_TICKS(20));
}
}
+#if HAS_LOG
if (ao_log_full()) {
pause(AO_MS_TO_TICKS(100));
c = 2;
@@ -143,9 +150,7 @@ ao_report_continuity(void) __reentrant
mid(AO_MS_TO_TICKS(100));
}
}
- c = 50;
- while (c-- && ao_flight_state == ao_flight_pad)
- pause(AO_MS_TO_TICKS(100));
+#endif
}
#endif
@@ -157,11 +162,16 @@ ao_report(void)
if (ao_flight_state == ao_flight_landed)
ao_report_altitude();
ao_report_beep();
-#if HAS_IGNITE
+#if HAS_IGNITE_REPORT
if (ao_flight_state == ao_flight_idle)
ao_report_continuity();
- while (ao_flight_state == ao_flight_pad)
+ while (ao_flight_state == ao_flight_pad) {
+ uint8_t c;
ao_report_continuity();
+ c = 50;
+ while (c-- && ao_flight_state == ao_flight_pad)
+ pause(AO_MS_TO_TICKS(100));
+ }
#endif
__critical {
while (ao_report_state == ao_flight_state)
diff --git a/src/ao_rssi.c b/src/core/ao_rssi.c
index e3964d2d..e3964d2d 100644
--- a/src/ao_rssi.c
+++ b/src/core/ao_rssi.c
diff --git a/src/ao_sample.c b/src/core/ao_sample.c
index b2b8e9f6..b2b8e9f6 100644
--- a/src/ao_sample.c
+++ b/src/core/ao_sample.c
diff --git a/src/ao_state.c b/src/core/ao_state.c
index ed197aa5..ed197aa5 100644
--- a/src/ao_state.c
+++ b/src/core/ao_state.c
diff --git a/src/ao_stdio.c b/src/core/ao_stdio.c
index c0138a30..c0138a30 100644
--- a/src/ao_stdio.c
+++ b/src/core/ao_stdio.c
diff --git a/src/ao_storage.c b/src/core/ao_storage.c
index 6ffca0e5..6ffca0e5 100644
--- a/src/ao_storage.c
+++ b/src/core/ao_storage.c
diff --git a/src/ao_task.c b/src/core/ao_task.c
index f5850fa4..a19a6a6f 100644
--- a/src/ao_task.c
+++ b/src/core/ao_task.c
@@ -24,10 +24,13 @@ __data uint8_t ao_num_tasks;
__data uint8_t ao_cur_task_index;
__xdata struct ao_task *__data ao_cur_task;
+#ifdef ao_arch_task_globals
+ao_arch_task_globals
+#endif
+
void
ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant
{
- uint8_t __xdata *stack;
uint8_t task_id;
uint8_t t;
if (ao_num_tasks == AO_NUM_TASKS)
@@ -42,90 +45,28 @@ ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *nam
ao_tasks[ao_num_tasks++] = task;
task->task_id = task_id;
task->name = name;
+ task->wchan = NULL;
/*
* Construct a stack frame so that it will 'return'
* to the start of the task
*/
- stack = task->stack;
-
- *stack++ = ((uint16_t) start); /* 0 */
- *stack++ = ((uint16_t) start) >> 8; /* 1 */
-
- /* and the stuff saved by ao_switch */
- *stack++ = 0; /* 2 acc */
- *stack++ = 0x80; /* 3 IE */
-
- /* 4 DPL
- * 5 DPH
- * 6 B
- * 7 R2
- * 8 R3
- * 9 R4
- * 10 R5
- * 11 R6
- * 12 R7
- * 13 R0
- * 14 R1
- * 15 PSW
- * 16 BP
- */
- for (t = 0; t < 13; t++)
- *stack++ = 0;
-
- task->stack_count = 17;
- task->wchan = NULL;
+ ao_arch_init_stack(task, start);
}
/* Task switching function. This must not use any stack variables */
void
-ao_yield(void) __naked
+ao_yield(void) ao_arch_naked_define
{
-
- /* Save current context */
- _asm
- /* Push ACC first, as when restoring the context it must be restored
- * last (it is used to set the IE register). */
- push ACC
- /* Store the IE register then enable interrupts. */
- push _IEN0
- setb _EA
- push DPL
- push DPH
- push b
- push ar2
- push ar3
- push ar4
- push ar5
- push ar6
- push ar7
- push ar0
- push ar1
- push PSW
- _endasm;
- PSW = 0;
- _asm
- push _bp
- _endasm;
+ ao_arch_save_regs();
if (ao_cur_task_index == AO_NO_TASK_INDEX)
ao_cur_task_index = ao_num_tasks-1;
else
{
- uint8_t stack_len;
- __data uint8_t *stack_ptr;
- __xdata uint8_t *save_ptr;
- /* Save the current stack */
- stack_len = SP - (AO_STACK_START - 1);
- ao_cur_task->stack_count = stack_len;
- stack_ptr = (uint8_t __data *) AO_STACK_START;
- save_ptr = (uint8_t __xdata *) ao_cur_task->stack;
- do
- *save_ptr++ = *stack_ptr++;
- while (--stack_len);
+ ao_arch_save_stack();
}
- /* Empty the stack; might as well let interrupts have the whole thing */
- SP = AO_STACK_START - 1;
+ ao_arch_isr_stack();
/* Find a task to run. If there isn't any runnable task,
* this loop will run forever, which is just fine
@@ -151,65 +92,21 @@ ao_yield(void) __naked
}
/* Enter lower power mode when there isn't anything to do */
- if (ao_next_task_index == ao_cur_task_index)
- PCON = PCON_IDLE;
+ if (ao_next_task_index == ao_cur_task_index) {
+ ao_arch_cpu_idle();
+ }
}
}
-
- {
- uint8_t stack_len;
- __data uint8_t *stack_ptr;
- __xdata uint8_t *save_ptr;
-
- /* Restore the old stack */
- stack_len = ao_cur_task->stack_count;
- SP = AO_STACK_START - 1 + stack_len;
-
- stack_ptr = (uint8_t __data *) AO_STACK_START;
- save_ptr = (uint8_t __xdata *) ao_cur_task->stack;
- do
- *stack_ptr++ = *save_ptr++;
- while (--stack_len);
- }
-
- _asm
- pop _bp
- pop PSW
- pop ar1
- pop ar0
- pop ar7
- pop ar6
- pop ar5
- pop ar4
- pop ar3
- pop ar2
- pop b
- pop DPH
- pop DPL
- /* The next byte of the stack is the IE register. Only the global
- enable bit forms part of the task context. Pop off the IE then set
- the global enable bit to match that of the stored IE register. */
- pop ACC
- JB ACC.7,0098$
- CLR _EA
- LJMP 0099$
- 0098$:
- SETB _EA
- 0099$:
- /* Finally pop off the ACC, which was the first register saved. */
- pop ACC
- ret
- _endasm;
+ ao_arch_restore_stack();
}
uint8_t
ao_sleep(__xdata void *wchan)
{
- __critical {
+ ao_arch_critical(
ao_cur_task->wchan = wchan;
- }
+ );
ao_yield();
- ao_cur_task->alarm = 0;
if (ao_cur_task->wchan) {
ao_cur_task->wchan = NULL;
return 1;
@@ -238,14 +135,22 @@ ao_alarm(uint16_t delay)
}
void
-ao_exit(void) __critical
+ao_clear_alarm(void)
{
- uint8_t i;
- ao_num_tasks--;
- for (i = ao_cur_task_index; i < ao_num_tasks; i++)
- ao_tasks[i] = ao_tasks[i+1];
- ao_cur_task_index = AO_NO_TASK_INDEX;
- ao_yield();
+ ao_cur_task->alarm = 0;
+}
+
+void
+ao_exit(void)
+{
+ ao_arch_critical(
+ uint8_t i;
+ ao_num_tasks--;
+ for (i = ao_cur_task_index; i < ao_num_tasks; i++)
+ ao_tasks[i] = ao_tasks[i+1];
+ ao_cur_task_index = AO_NO_TASK_INDEX;
+ ao_yield();
+ );
/* we'll never get back here */
}
@@ -253,16 +158,13 @@ void
ao_task_info(void)
{
uint8_t i;
- uint8_t pc_loc;
__xdata struct ao_task *task;
for (i = 0; i < ao_num_tasks; i++) {
task = ao_tasks[i];
- pc_loc = task->stack_count - 17;
- printf("%12s: wchan %04x pc %04x\n",
+ printf("%12s: wchan %04x\n",
task->name,
- (int16_t) task->wchan,
- (task->stack[pc_loc]) | (task->stack[pc_loc+1] << 8));
+ (int16_t) task->wchan);
}
}
diff --git a/src/ao_telem.h b/src/core/ao_telem.h
index 1a8da291..1a8da291 100644
--- a/src/ao_telem.h
+++ b/src/core/ao_telem.h
diff --git a/src/ao_telemetry.c b/src/core/ao_telemetry.c
index c7338a58..c2707e7d 100644
--- a/src/ao_telemetry.c
+++ b/src/core/ao_telemetry.c
@@ -94,6 +94,30 @@ ao_send_sensor(void)
ao_radio_send(&telemetry, sizeof (telemetry));
}
+static uint8_t ao_baro_sample;
+
+#ifdef AO_SEND_ALL_BARO
+static void
+ao_send_baro(void)
+{
+ uint8_t sample = ao_sample_adc;
+ uint8_t samples = (sample - ao_baro_sample) & (AO_ADC_RING - 1);
+
+ if (samples > 12) {
+ ao_baro_sample = (ao_baro_sample + (samples - 12)) & (AO_ADC_RING - 1);
+ samples = 12;
+ }
+ telemetry.generic.tick = ao_adc_ring[sample].tick;
+ telemetry.generic.type = AO_TELEMETRY_BARO;
+ telemetry.baro.samples = samples;
+ for (sample = 0; sample < samples; sample++) {
+ telemetry.baro.baro[sample] = ao_adc_ring[ao_baro_sample].pres;
+ ao_baro_sample = ao_adc_ring_next(ao_baro_sample);
+ }
+ ao_radio_send(&telemetry, sizeof (telemetry));
+}
+#endif
+
static void
ao_send_configuration(void)
{
@@ -193,6 +217,9 @@ ao_telemetry(void)
while (ao_telemetry_interval) {
+#ifdef AO_SEND_ALL_BARO
+ ao_send_baro();
+#endif
ao_send_sensor();
#if HAS_COMPANION
if (ao_companion_running)
@@ -203,12 +230,14 @@ ao_telemetry(void)
ao_send_location();
ao_send_satellite();
#endif
+#ifndef AO_SEND_ALL_BARO
if (ao_rdf &&
(int16_t) (ao_time() - ao_rdf_time) >= 0)
{
ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS;
- ao_radio_rdf(AO_RDF_LENGTH_MS);
+ ao_radio_rdf(AO_MS_TO_RDF_LEN(AO_RDF_LENGTH_MS));
}
+#endif
time += ao_telemetry_interval;
delay = time - ao_time();
if (delay > 0)
diff --git a/src/ao_ee.c b/src/drivers/ao_25lc1024.c
index a2fe8dc1..738f8ce6 100644
--- a/src/ao_ee.c
+++ b/src/drivers/ao_25lc1024.c
@@ -16,7 +16,7 @@
*/
#include "ao.h"
-#include "25lc1024.h"
+#include "ao_25lc1024.h"
#define EE_BLOCK_SIZE ((uint16_t) (256))
#define EE_BLOCK_SHIFT 8
diff --git a/src/25lc1024.h b/src/drivers/ao_25lc1024.h
index 44e52387..44e52387 100644
--- a/src/25lc1024.h
+++ b/src/drivers/ao_25lc1024.h
diff --git a/src/ao_flash.c b/src/drivers/ao_at45db161d.c
index bb40f6f7..aee9877a 100644
--- a/src/ao_flash.c
+++ b/src/drivers/ao_at45db161d.c
@@ -16,7 +16,7 @@
*/
#include "ao.h"
-#include "at45db161d.h"
+#include "ao_at45db161d.h"
/* Total bytes of available storage */
__pdata uint32_t ao_storage_total;
diff --git a/src/at45db161d.h b/src/drivers/ao_at45db161d.h
index 9ee6f1b6..9ee6f1b6 100644
--- a/src/at45db161d.h
+++ b/src/drivers/ao_at45db161d.h
diff --git a/src/ao_btm.c b/src/drivers/ao_btm.c
index 44155ec1..5eb78815 100644
--- a/src/ao_btm.c
+++ b/src/drivers/ao_btm.c
@@ -20,6 +20,87 @@
int8_t ao_btm_stdio;
__xdata uint8_t ao_btm_connected;
+#define BT_DEBUG 0
+
+#if BT_DEBUG
+__xdata char ao_btm_buffer[256];
+int ao_btm_ptr;
+char ao_btm_dir;
+
+static void
+ao_btm_add_char(char c)
+{
+ if (ao_btm_ptr < sizeof (ao_btm_buffer))
+ ao_btm_buffer[ao_btm_ptr++] = c;
+}
+
+static void
+ao_btm_log_char(char c, char dir)
+{
+ if (dir != ao_btm_dir) {
+ ao_btm_add_char(dir);
+ ao_btm_dir = dir;
+ }
+ ao_btm_add_char(c);
+}
+
+static void
+ao_btm_log_out_char(char c)
+{
+ ao_btm_log_char(c, '>');
+}
+
+static void
+ao_btm_log_in_char(char c)
+{
+ ao_btm_log_char(c, '<');
+}
+
+/*
+ * Dump everything received from the bluetooth device during startup
+ */
+static void
+ao_btm_dump(void)
+{
+ int i;
+ char c;
+
+ for (i = 0; i < ao_btm_ptr; i++) {
+ c = ao_btm_buffer[i];
+ if (c < ' ' && c != '\n')
+ printf("\\%03o", ((int) c) & 0xff);
+ else
+ putchar(ao_btm_buffer[i]);
+ }
+ putchar('\n');
+}
+
+static void
+ao_btm_speed(void)
+{
+ ao_cmd_decimal();
+ if (ao_cmd_lex_u32 == 57600)
+ ao_serial_set_speed(AO_SERIAL_SPEED_57600);
+ else if (ao_cmd_lex_u32 == 19200)
+ ao_serial_set_speed(AO_SERIAL_SPEED_19200);
+ else
+ ao_cmd_status = ao_cmd_syntax_error;
+}
+
+__code struct ao_cmds ao_btm_cmds[] = {
+ { ao_btm_dump, "d\0Dump btm buffer." },
+ { ao_btm_speed, "s <19200,57600>\0Set btm serial speed." },
+ { 0, NULL },
+};
+
+#define ao_btm_log_init() ao_cmd_register(&ao_btm_cmds[0])
+
+#else
+#define ao_btm_log_in_char(c)
+#define ao_btm_log_out_char(c)
+#define ao_btm_log_init()
+#endif
+
#define AO_BTM_MAX_REPLY 16
__xdata char ao_btm_reply[AO_BTM_MAX_REPLY];
@@ -39,6 +120,7 @@ ao_btm_get_line(void)
for (;;) {
while ((c = ao_serial_pollchar()) != AO_READ_AGAIN) {
+ ao_btm_log_in_char(c);
if (ao_btm_reply_len < sizeof (ao_btm_reply))
ao_btm_reply[ao_btm_reply_len++] = c;
if (c == '\r' || c == '\n')
@@ -85,6 +167,7 @@ ao_btm_echo(uint8_t echo)
void
ao_btm_putchar(char c)
{
+ ao_btm_log_out_char(c);
ao_serial_putchar(c);
ao_delay(1);
}
@@ -166,10 +249,6 @@ ao_btm(void)
*/
ao_delay(AO_SEC_TO_TICKS(3));
-#if HAS_BEEP
- ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
-#endif
-
/*
* The first time we connect, the BTM-180 comes up at 19200 baud.
* After that, it will remember and come up at 57600 baud. So, see
@@ -299,4 +378,5 @@ ao_btm_init (void)
#endif
ao_add_task(&ao_btm_task, ao_btm, "bt");
+ ao_btm_log_init();
}
diff --git a/src/ao_companion.c b/src/drivers/ao_companion.c
index 4c8f4269..2e587f8e 100644
--- a/src/ao_companion.c
+++ b/src/drivers/ao_companion.c
@@ -30,7 +30,7 @@
#define COMPANION_SELECT() do { ao_spi_get_bit(COMPANION_CS); ao_spi_slow(); } while (0)
#define COMPANION_DESELECT() do { ao_spi_fast(); ao_spi_put_bit(COMPANION_CS); } while (0)
-static __xdata struct ao_companion_command ao_companion_command;
+__xdata struct ao_companion_command ao_companion_command;
__xdata struct ao_companion_setup ao_companion_setup;
__xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS];
diff --git a/src/ao_gps_sirf.c b/src/drivers/ao_gps_sirf.c
index f2abbf84..f2abbf84 100644
--- a/src/ao_gps_sirf.c
+++ b/src/drivers/ao_gps_sirf.c
diff --git a/src/ao_gps_skytraq.c b/src/drivers/ao_gps_skytraq.c
index 7ac26946..7ac26946 100644
--- a/src/ao_gps_skytraq.c
+++ b/src/drivers/ao_gps_skytraq.c
diff --git a/src/drivers/ao_lcd.c b/src/drivers/ao_lcd.c
new file mode 100644
index 00000000..5bc89bbd
--- /dev/null
+++ b/src/drivers/ao_lcd.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+#define LCD_PORT PORTB
+#define LCD_DDR DDRB
+
+#define PIN_RS 4
+#define PIN_E 5
+#define PIN_RW 6
+
+void
+ao_lcd_set_bits(uint8_t bits)
+{
+#if 0
+ printf("\tLCD data %x RS %d R/W %d E %d\n",
+ bits & 0xf,
+ (bits & (1 << PIN_RS)) ? 1 : 0,
+ (bits & (1 << PIN_RW)) ? 1 : 0,
+ (bits & (1 << PIN_E)) ? 1 : 0);
+#endif
+ LCD_PORT = bits;
+#if 0
+ ao_delay(1);
+ if (bits & (1 << PIN_RW))
+ printf("\tLCD input %x\n", PINB);
+#endif
+}
+
+uint8_t
+ao_lcd_get_nibble(uint8_t rs)
+{
+ uint8_t data = (rs ? (1 << PIN_RS) : 0) | (1 << PIN_RW);
+ uint8_t n;
+
+ DDRB = (1 << PIN_RS) | (1 << PIN_E) | (1 << PIN_RW);
+ ao_lcd_set_bits(data);
+ ao_lcd_set_bits(data | (1 << PIN_E));
+ n = PINB & 0xf;
+ ao_lcd_set_bits(data);
+ return n;
+}
+
+uint8_t
+ao_lcd_get_status(void)
+{
+ uint8_t high, low;
+ uint8_t data;
+
+ high = ao_lcd_get_nibble(0);
+ low = ao_lcd_get_nibble(0);
+ data = (high << 4) | low;
+ printf ("\tLCD status %02x\n", data);
+ return data;
+}
+
+uint8_t
+ao_lcd_get_data(void)
+{
+ uint8_t high, low;
+ uint8_t data;
+
+ high = ao_lcd_get_nibble(1);
+ low = ao_lcd_get_nibble(1);
+ data = (high << 4) | low;
+ printf ("\tLCD data %02x\n", data);
+ return data;
+}
+
+void
+ao_lcd_wait_idle(void)
+{
+ uint8_t status;
+ uint8_t count = 0;
+
+ do {
+ status = ao_lcd_get_status();
+ count++;
+ if (count > 100) {
+ printf("idle timeout\n");
+ break;
+ }
+ } while (0); /* status & 0x80); */
+}
+
+void
+ao_lcd_send_nibble(uint8_t rs, uint8_t data)
+{
+ data = (data & 0xf) | (rs ? (1 << PIN_RS) : 0);
+ DDRB = (0xf) | (1 << PIN_RS) | (1 << PIN_E) | (1 << PIN_RW);
+ ao_lcd_set_bits(data);
+ ao_lcd_set_bits(data | (1 << PIN_E));
+ ao_lcd_set_bits(data);
+}
+
+static uint16_t ao_lcd_time = 3;
+
+void
+ao_lcd_delay(void)
+{
+ volatile uint16_t count;
+
+ for (count = 0; count < ao_lcd_time; count++)
+ ;
+}
+
+void
+ao_lcd_send_ins(uint8_t data)
+{
+// printf("send ins %02x\n", data);
+// ao_lcd_wait_idle();
+// ao_delay(1);
+ ao_lcd_delay();
+ ao_lcd_send_nibble(0, data >> 4);
+ ao_lcd_send_nibble(0, data & 0xf);
+}
+
+void
+ao_lcd_send_data(uint8_t data)
+{
+// printf ("send data %02x\n", data);
+// ao_lcd_wait_idle();
+ ao_lcd_delay();
+ ao_lcd_send_nibble(1, data >> 4);
+ ao_lcd_send_nibble(1, data & 0x0f);
+}
+
+void
+ao_lcd_send_string(char *string)
+{
+ uint8_t c;
+
+ while ((c = (uint8_t) *string++))
+ ao_lcd_send_data(c);
+}
+
+#define AO_LCD_POWER_CONTROL 0x54
+
+void
+ao_lcd_contrast_set(uint8_t contrast)
+{
+ ao_lcd_send_ins(AO_LCD_POWER_CONTROL | ((contrast >> 4) & 0x3));
+ ao_lcd_send_ins(0x70 | (contrast & 0xf));
+}
+
+void
+ao_lcd_clear(void)
+{
+ ao_lcd_send_ins(0x01);
+ ao_delay(1);
+ /* Entry mode */
+ ao_lcd_send_ins(0x04 | 0x02);
+}
+
+void
+ao_lcd_start(void)
+{
+ /* get to 4bit mode */
+ ao_lcd_send_nibble(0, 0x3);
+ ao_lcd_send_nibble(0, 0x3);
+ ao_lcd_send_nibble(0, 0x3);
+ ao_lcd_send_nibble(0, 0x2);
+
+ /* function set */
+ ao_lcd_send_ins(0x28);
+ /* function set, instruction table 1 */
+ ao_lcd_send_ins(0x29);
+
+ /* freq set */
+ ao_lcd_send_ins(0x14);
+
+ /* Power/icon/contrast control*/
+ ao_lcd_send_ins(AO_LCD_POWER_CONTROL);
+
+ /* Follower control */
+ ao_lcd_send_ins(0x6d);
+ ao_delay(AO_MS_TO_TICKS(200));
+
+ /* contrast set */
+ ao_lcd_contrast_set(0x18);
+
+ /* Display on */
+ ao_lcd_send_ins(0x08 | 0x04);
+
+ /* Clear */
+ ao_lcd_clear();
+
+}
+
+void
+ao_lcd_contrast(void)
+{
+ ao_cmd_hex();
+ if (ao_cmd_status == ao_cmd_success) {
+ printf("setting contrast to %02x\n", ao_cmd_lex_i);
+ ao_lcd_contrast_set(ao_cmd_lex_i & 0x3f);
+ }
+}
+
+static uint8_t
+ao_cmd_hex_nibble(void)
+{
+ if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
+ return ao_cmd_lex_c - '0';
+ if ('a' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'f')
+ return ao_cmd_lex_c - ('a' - 10);
+ if ('A' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'F')
+ return ao_cmd_lex_c - ('A' - 10);
+ ao_cmd_status = ao_cmd_syntax_error;
+ return 0;
+}
+
+void
+ao_lcd_string(void)
+{
+ uint8_t col = 0;
+ uint8_t c;
+
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_lcd_send_ins(0x80 | (ao_cmd_lex_i ? 0x40 : 0x00));
+ ao_cmd_white();
+ while (ao_cmd_lex_c != '\n') {
+ c = ao_cmd_lex_c;
+ if (c == '\\') {
+ ao_cmd_lex();
+ c = ao_cmd_hex_nibble() << 4;
+ ao_cmd_lex();
+ c |= ao_cmd_hex_nibble();
+ }
+ ao_lcd_send_data(c);
+ ao_cmd_lex();
+ col++;
+ }
+ while (col < 16) {
+ ao_lcd_send_data(' ');
+ col++;
+ }
+}
+
+void
+ao_lcd_delay_set(void)
+{
+ ao_cmd_decimal();
+ if (ao_cmd_status == ao_cmd_success) {
+ printf("setting LCD delay to %d\n", ao_cmd_lex_i);
+ ao_lcd_time = ao_cmd_lex_i;
+ }
+}
+
+__code struct ao_cmds ao_lcd_cmds[] = {
+ { ao_lcd_start, "S\0Start LCD" },
+ { ao_lcd_contrast, "C <contrast>\0Set LCD contrast" },
+ { ao_lcd_string, "s <line> <string>\0Send string to LCD" },
+ { ao_lcd_delay_set, "t <delay>\0Set LCD delay" },
+ { 0, NULL },
+};
+
+void
+ao_lcd_init(void)
+{
+ DDRB = (1 << PIN_RS) | (1 << PIN_E) | (1 << PIN_RW);
+ PORTB = 0;
+ ao_cmd_register(&ao_lcd_cmds[0]);
+}
diff --git a/src/ao_m25.c b/src/drivers/ao_m25.c
index d7208273..28cb1dd7 100644
--- a/src/ao_m25.c
+++ b/src/drivers/ao_m25.c
@@ -376,5 +376,7 @@ ao_storage_device_init(void)
/* Set up chip select wires */
SPI_CS_PORT |= M25_CS_MASK; /* raise all CS pins */
SPI_CS_DIR |= M25_CS_MASK; /* set CS pins as outputs */
+#ifdef SPI_CS_SEL
SPI_CS_SEL &= ~M25_CS_MASK; /* set CS pins as GPIO */
+#endif
}
diff --git a/src/drivers/ao_pyro_slave.c b/src/drivers/ao_pyro_slave.c
new file mode 100644
index 00000000..e6c73a3c
--- /dev/null
+++ b/src/drivers/ao_pyro_slave.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_product.h"
+
+struct ao_companion_command ao_companion_command;
+
+static const struct ao_companion_setup ao_telepyro_setup = {
+ .board_id = AO_idProduct_NUMBER,
+ .board_id_inverse = ~AO_idProduct_NUMBER,
+ .update_period = 50,
+ .channels = AO_TELEPYRO_NUM_ADC,
+};
+
+void ao_spi_slave(void)
+{
+ if (!ao_spi_read((uint8_t *) &ao_companion_command,
+ sizeof (ao_companion_command)))
+ return;
+
+ /* Figure out the outbound data */
+ switch (ao_companion_command.command) {
+ case AO_COMPANION_SETUP:
+ ao_spi_write((uint8_t *) &ao_telepyro_setup,
+ sizeof (ao_telepyro_setup));
+ break;
+ case AO_COMPANION_FETCH:
+ ao_spi_write((uint8_t *) &ao_adc_ring[ao_adc_ring_prev(ao_adc_head)].adc,
+ AO_TELEPYRO_NUM_ADC * sizeof (uint16_t));
+ break;
+ case AO_COMPANION_NOTIFY:
+ break;
+ default:
+ return;
+ }
+}
diff --git a/src/drivers/ao_science_slave.c b/src/drivers/ao_science_slave.c
new file mode 100644
index 00000000..e902318f
--- /dev/null
+++ b/src/drivers/ao_science_slave.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_product.h"
+
+struct ao_companion_command ao_companion_command;
+
+static const struct ao_companion_setup ao_telescience_setup = {
+ .board_id = AO_idProduct_NUMBER,
+ .board_id_inverse = ~AO_idProduct_NUMBER,
+ .update_period = 50,
+ .channels = AO_LOG_TELESCIENCE_NUM_ADC,
+};
+
+void ao_spi_slave(void)
+{
+ if (!ao_spi_read((uint8_t *) &ao_companion_command,
+ sizeof (ao_companion_command)))
+ return;
+
+ /* Figure out the outbound data */
+ switch (ao_companion_command.command) {
+ case AO_COMPANION_SETUP:
+ ao_spi_write((uint8_t *) &ao_telescience_setup,
+ sizeof (ao_telescience_setup));
+ break;
+ case AO_COMPANION_FETCH:
+ ao_spi_write((uint8_t *) &ao_adc_ring[ao_adc_ring_prev(ao_adc_head)].adc,
+ AO_LOG_TELESCIENCE_NUM_ADC * sizeof (uint16_t));
+ break;
+ case AO_COMPANION_NOTIFY:
+ break;
+ default:
+ return;
+ }
+
+ ao_log_single_write_data.telescience.tm_tick = ao_companion_command.tick;
+ if (ao_log_single_write_data.telescience.tm_state != ao_companion_command.flight_state) {
+ ao_log_single_write_data.telescience.tm_state = ao_companion_command.flight_state;
+ if (ao_flight_boost <= ao_log_single_write_data.telescience.tm_state) {
+ if (ao_log_single_write_data.telescience.tm_state < ao_flight_landed)
+ ao_log_single_start();
+ else
+ ao_log_single_stop();
+ }
+ }
+}
diff --git a/src/product/Makefile.telebt b/src/product/Makefile.telebt
new file mode 100644
index 00000000..46c87db0
--- /dev/null
+++ b/src/product/Makefile.telebt
@@ -0,0 +1,98 @@
+#
+# TeleBT build file
+#
+# Define TELEBT_VER, TELEBT_DEF, TELEBT_INC and TELEBT_SRC
+# and include this file
+
+vpath %.c ..:../core:../cc1111:../drivers:../product
+vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath ao-make-product.5c ../util
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ cc1111.h \
+ ao_product.h \
+ $(TELEBT_INC)
+
+CORE_SRC = \
+ ao_cmd.c \
+ ao_config.c \
+ ao_gps_print.c \
+ ao_monitor.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_state.c \
+ ao_stdio.c \
+ ao_task.c
+
+CC1111_SRC = \
+ ao_aes.c \
+ ao_dbg.c \
+ ao_dma.c \
+ ao_led.c \
+ ao_packet.c \
+ ao_packet_master.c \
+ ao_radio.c \
+ ao_radio_cmac.c \
+ ao_romconfig.c \
+ ao_serial.c \
+ ao_timer.c \
+ ao_usb.c \
+ _bp.c
+
+DRIVER_SRC = \
+ ao_btm.c
+
+PRODUCT_SRC = \
+ ao_telebt.c
+
+SRC = \
+ $(CORE_SRC) \
+ $(CC1111_SRC) \
+ $(DRIVER_SRC) \
+ $(PRODUCT_SRC) \
+ $(TELEBT_SRC)
+
+PROG = telebt-v$(TELEBT_VER)-$(VERSION).ihx
+PRODUCT=TeleBT-v$(TELEBT_VER)
+PRODUCT_DEF=-DTELEBT_V_$(TELEBT_DEF)
+IDPRODUCT=0x000e
+
+include ../cc1111/Makefile.cc1111
+
+NICKLE=nickle
+CHECK_STACK=sh ../util/check-stack
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: ../$(PROG)
+
+../$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+ $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean:
+ rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM)
+ rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
+ rm -f ao_product.h
+ rm -f ../$(PROG) ../$(PMAP)
+
+install:
+
+uninstall:
diff --git a/src/product/Makefile.teledongle b/src/product/Makefile.teledongle
new file mode 100644
index 00000000..56182b84
--- /dev/null
+++ b/src/product/Makefile.teledongle
@@ -0,0 +1,98 @@
+#
+# TeleDongle build file
+#
+# The various teledongle versions differ only
+# in minor pin variations
+# so the per-board makefiles simply define
+# TD_VER, TD_DEF and include
+# this file
+
+vpath %.c ..:../core:../cc1111:../drivers:../product
+vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath ao-make-product.5c ../util
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ cc1111.h \
+ ao_product.h
+
+CORE_SRC = \
+ ao_cmd.c \
+ ao_config.c \
+ ao_gps_print.c \
+ ao_monitor.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_rssi.c \
+ ao_state.c \
+ ao_stdio.c \
+ ao_task.c
+
+CC1111_SRC = \
+ ao_aes.c \
+ ao_dbg.c \
+ ao_dma.c \
+ ao_led.c \
+ ao_packet.c \
+ ao_packet_master.c \
+ ao_radio.c \
+ ao_radio_cmac.c \
+ ao_romconfig.c \
+ ao_timer.c \
+ ao_usb.c \
+ _bp.c
+
+DRIVER_SRC =
+
+PRODUCT_SRC = \
+ ao_teledongle.c
+
+SRC = \
+ $(CORE_SRC) \
+ $(CC1111_SRC) \
+ $(DRIVER_SRC) \
+ $(PRODUCT_SRC)
+
+PROG = teledongle-v$(TD_VER)-$(VERSION).ihx
+PRODUCT=TeleDongle-v$(TD_VER)
+PRODUCT_DEF=-DTELEDONGLE_V_$(TD_DEF)
+IDPRODUCT=0x000c
+
+include ../cc1111/Makefile.cc1111
+
+NICKLE=nickle
+CHECK_STACK=sh ../util/check-stack
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: ../$(PROG)
+
+../$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+ $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean:
+ rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM)
+ rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
+ rm -f ao_product.h
+ rm -f ../$(PROG) ../$(PMAP)
+
+install:
+
+uninstall:
diff --git a/src/product/Makefile.telelaunch b/src/product/Makefile.telelaunch
new file mode 100644
index 00000000..5da42e46
--- /dev/null
+++ b/src/product/Makefile.telelaunch
@@ -0,0 +1,101 @@
+#
+# TeleLaunch build file
+#
+# define TELELAUNCH_VER, TELELAUNCH_DEF
+# this file
+
+vpath %.c ..:../core:../cc1111:../drivers:../product
+vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath ao-make-product.5c ../util
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ cc1111.h \
+ ao_product.h
+
+CORE_SRC = \
+ ao_cmd.c \
+ ao_config.c \
+ ao_convert.c \
+ ao_launch.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_stdio.c \
+ ao_storage.c \
+ ao_task.c
+
+CC1111_SRC = \
+ ao_adc.c \
+ ao_aes.c \
+ ao_beep.c \
+ ao_dbg.c \
+ ao_dma.c \
+ ao_ignite.c \
+ ao_intflash.c \
+ ao_led.c \
+ ao_packet.c \
+ ao_packet_slave.c \
+ ao_radio.c \
+ ao_radio_cmac.c \
+ ao_romconfig.c \
+ ao_serial.c \
+ ao_spi.c \
+ ao_timer.c \
+ ao_usb.c \
+ _bp.c
+
+DRIVER_SRC =
+
+PRODUCT_SRC = \
+ ao_telelaunch.c
+
+SRC = \
+ $(CORE_SRC) \
+ $(CC1111_SRC) \
+ $(DRIVER_SRC) \
+ $(PRODUCT_SRC)
+
+PROG = telelaunch-v$(TELELAUNCH_VER)-$(VERSION).ihx
+PRODUCT=TeleLaunch-v$(TELELAUNCH_VER)
+PRODUCT_DEF=-DTELELAUNCH_V_$(TELELAUNCH_DEF)
+IDPRODUCT=0x000f
+CODESIZE=0x6700
+
+include ../cc1111/Makefile.cc1111
+
+NICKLE=nickle
+CHECK_STACK=sh ../util/check-stack
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: ../$(PROG)
+
+../$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+ $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean:
+ rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM)
+ rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
+ rm -f ao_product.h
+ rm -f ../$(PROG) ../$(PMAP)
+
+install:
+
+uninstall:
diff --git a/src/product/Makefile.telemetrum b/src/product/Makefile.telemetrum
new file mode 100644
index 00000000..2759ac52
--- /dev/null
+++ b/src/product/Makefile.telemetrum
@@ -0,0 +1,111 @@
+#
+# TeleMetrum build file
+#
+# The various telemetrum versions differ only
+# in which flash and GPS drivers are included,
+# so the per-board makefiles simply define
+# TM_VER, TM_DEF, TM_INC and TM_SRC and include
+# this file
+
+vpath %.c ..:../core:../cc1111:../drivers:../product
+vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath ao-make-product.5c ../util
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ cc1111.h \
+ altitude.h \
+ ao_kalman.h \
+ ao_product.h \
+ $(TM_INC)
+
+CORE_SRC = \
+ ao_cmd.c \
+ ao_config.c \
+ ao_convert.c \
+ ao_gps_report.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_stdio.c \
+ ao_storage.c \
+ ao_task.c \
+ ao_flight.c \
+ ao_sample.c \
+ ao_kalman.c \
+ ao_log.c \
+ ao_log_big.c \
+ ao_report.c \
+ ao_telemetry.c
+
+CC1111_SRC = \
+ ao_adc.c \
+ ao_beep.c \
+ ao_dbg.c \
+ ao_dma.c \
+ ao_ignite.c \
+ ao_led.c \
+ ao_packet.c \
+ ao_packet_slave.c \
+ ao_radio.c \
+ ao_romconfig.c \
+ ao_serial.c \
+ ao_spi.c \
+ ao_timer.c \
+ ao_usb.c \
+ _bp.c
+
+DRIVER_SRC = \
+ $(TM_SRC)
+
+PRODUCT_SRC = \
+ ao_telemetrum.c
+
+SRC = \
+ $(CORE_SRC) \
+ $(CC1111_SRC) \
+ $(DRIVER_SRC) \
+ $(PRODUCT_SRC)
+
+PROG = telemetrum-v$(TM_VER)-$(VERSION).ihx
+PRODUCT=TeleMetrum-v$(TM_VER)
+PRODUCT_DEF=-DTELEMETRUM_V_$(TM_DEF)
+IDPRODUCT=0x000b
+
+include ../cc1111/Makefile.cc1111
+
+NICKLE=nickle
+CHECK_STACK=sh ../util/check-stack
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: ../$(PROG)
+
+../$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+ $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean:
+ rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM)
+ rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
+ rm -f ao_product.h
+ rm -f ../$(PROG) ../$(PMAP)
+
+install:
+
+uninstall:
diff --git a/src/product/Makefile.telemini b/src/product/Makefile.telemini
new file mode 100644
index 00000000..7f251897
--- /dev/null
+++ b/src/product/Makefile.telemini
@@ -0,0 +1,100 @@
+#
+# TeleMini build file
+#
+# Define TELEMINI_VER and TELEMINI_DEF and then
+# include this file
+
+vpath %.c ..:../core:../cc1111:../drivers:../product
+vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath ao-make-product.5c ../util
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ cc1111.h \
+ ao_product.h
+
+CORE_SRC = \
+ ao_cmd.c \
+ ao_config.c \
+ ao_convert.c \
+ ao_flight.c \
+ ao_kalman.c \
+ ao_log.c \
+ ao_log_tiny.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_report.c \
+ ao_sample.c \
+ ao_stdio.c \
+ ao_storage.c \
+ ao_task.c \
+ ao_telemetry.c
+
+CC1111_SRC = \
+ ao_adc.c \
+ ao_dma.c \
+ ao_ignite.c \
+ ao_intflash.c \
+ ao_led.c \
+ ao_packet.c \
+ ao_packet_slave.c \
+ ao_radio.c \
+ ao_romconfig.c \
+ ao_timer.c \
+ _bp.c
+
+DRIVER_SRC =
+
+PRODUCT_SRC = \
+ ao_telemini.c
+
+SRC = \
+ $(CORE_SRC) \
+ $(CC1111_SRC) \
+ $(DRIVER_SRC) \
+ $(PRODUCT_SRC)
+
+PROG = telemini-v$(TELEMINI_VER)-$(VERSION).ihx
+PRODUCT=TeleMini-v$(TELEMINI_VER)
+PRODUCT_DEF=-DTELEMINI_V_$(TELEMINI_DEF)
+IDPRODUCT=0x000a
+CODESIZE=0x6700
+
+include ../cc1111/Makefile.cc1111
+
+NICKLE=nickle
+CHECK_STACK=sh ../util/check-stack
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: ../$(PROG)
+
+../$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+ $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean:
+ rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM)
+ rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
+ rm -f ao_product.h
+ rm -f ../$(PROG) ../$(PMAP)
+
+install:
+
+uninstall:
diff --git a/src/product/Makefile.telenano b/src/product/Makefile.telenano
new file mode 100644
index 00000000..c47e95ff
--- /dev/null
+++ b/src/product/Makefile.telenano
@@ -0,0 +1,99 @@
+#
+# TeleNano build file
+#
+# Define TELENANO_VER and TELENANO_DEF and then
+# include this file
+
+vpath %.c ..:../core:../cc1111:../drivers:../product
+vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath ao-make-product.5c ../util
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ cc1111.h \
+ ao_product.h
+
+CORE_SRC = \
+ ao_cmd.c \
+ ao_config.c \
+ ao_convert.c \
+ ao_flight_nano.c \
+ ao_kalman.c \
+ ao_log.c \
+ ao_log_tiny.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_report.c \
+ ao_sample.c \
+ ao_stdio.c \
+ ao_storage.c \
+ ao_task.c \
+ ao_telemetry.c
+
+CC1111_SRC = \
+ ao_adc.c \
+ ao_dma.c \
+ ao_intflash.c \
+ ao_led.c \
+ ao_packet.c \
+ ao_packet_slave.c \
+ ao_radio.c \
+ ao_romconfig.c \
+ ao_timer.c \
+ _bp.c
+
+DRIVER_SRC =
+
+PRODUCT_SRC = \
+ ao_telenano.c
+
+SRC = \
+ $(CORE_SRC) \
+ $(CC1111_SRC) \
+ $(DRIVER_SRC) \
+ $(PRODUCT_SRC)
+
+PROG = telenano-v$(TELENANO_VER)-$(VERSION).ihx
+PRODUCT=TeleNano-v$(TELENANO_VER)
+PRODUCT_DEF=-DTELENANO_V_$(TELENANO_DEF)
+IDPRODUCT=0x000a
+CODESIZE=0x6700
+
+include ../cc1111/Makefile.cc1111
+
+NICKLE=nickle
+CHECK_STACK=sh ../util/check-stack
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: ../$(PROG)
+
+../$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+ $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean:
+ rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM)
+ rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
+ rm -f ao_product.h
+ rm -f ../$(PROG) ../$(PMAP)
+
+install:
+
+uninstall:
diff --git a/src/ao_telebt.c b/src/product/ao_telebt.c
index 85565172..9e409db7 100644
--- a/src/ao_telebt.c
+++ b/src/product/ao_telebt.c
@@ -37,14 +37,23 @@ main(void)
ao_storage_init();
#endif
ao_usb_init();
- ao_monitor_init(AO_LED_GREEN, TRUE);
- ao_rssi_init(AO_LED_RED);
+ ao_monitor_init(AO_LED_RED, sizeof (union ao_telemetry_all));
+#if HAS_LOG
+ ao_report_init();
+#endif
ao_radio_init();
ao_packet_master_init();
ao_btm_init();
+#if HAS_LOG
+ ao_log_single_init();
+#endif
#if HAS_DBG
ao_dbg_init();
#endif
+#if HAS_AES
+ ao_aes_init();
+ ao_radio_cmac_init();
+#endif
ao_config_init();
ao_start_scheduler();
}
diff --git a/src/ao_teledongle.c b/src/product/ao_teledongle.c
index 008b200a..b8be9f45 100644
--- a/src/ao_teledongle.c
+++ b/src/product/ao_teledongle.c
@@ -35,6 +35,8 @@ main(void)
#if HAS_DBG
ao_dbg_init();
#endif
+ ao_aes_init();
+ ao_radio_cmac_init();
ao_config_init();
ao_start_scheduler();
}
diff --git a/src/ao_telemetrum.c b/src/product/ao_telemetrum.c
index ea77f5af..ea77f5af 100644
--- a/src/ao_telemetrum.c
+++ b/src/product/ao_telemetrum.c
diff --git a/src/ao_telemini.c b/src/product/ao_telemini.c
index fa23de01..fa23de01 100644
--- a/src/ao_telemini.c
+++ b/src/product/ao_telemini.c
diff --git a/src/ao_telenano.c b/src/product/ao_telenano.c
index d91983d0..d91983d0 100644
--- a/src/ao_telenano.c
+++ b/src/product/ao_telenano.c
diff --git a/src/ao_adc_fake.c b/src/product/ao_telepyro.c
index 6ca88d4e..a2b8f83c 100644
--- a/src/ao_adc_fake.c
+++ b/src/product/ao_telepyro.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ * Copyright © 2011 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
@@ -17,11 +17,20 @@
#include "ao.h"
-volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING];
-volatile __data uint8_t ao_adc_head;
-
-/* Stub for systems which have no ADC */
-void
-ao_adc_poll(void)
+int
+main(void)
{
+ ao_clock_init();
+
+ PORTE |= (1 << 6);
+ DDRE |= (1 << 6);
+
+ ao_avr_stdio_init();
+ ao_timer_init();
+ ao_cmd_init();
+ ao_spi_slave_init();
+ ao_usb_init();
+ ao_adc_init();
+ ao_start_scheduler();
+ return 0;
}
diff --git a/src/product/ao_telescience.c b/src/product/ao_telescience.c
new file mode 100644
index 00000000..45b6d40e
--- /dev/null
+++ b/src/product/ao_telescience.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+int
+main(void)
+{
+ ao_clock_init();
+
+ PORTE |= (1 << 6);
+ DDRE |= (1 << 6);
+
+ ao_avr_stdio_init();
+ ao_timer_init();
+ ao_cmd_init();
+ ao_spi_init();
+ ao_spi_slave_init();
+ ao_storage_init();
+ ao_usb_init();
+ ao_adc_init();
+ ao_log_single_init();
+ ao_start_scheduler();
+ return 0;
+}
diff --git a/src/ao_teleterra.c b/src/product/ao_teleterra.c
index d696b914..d696b914 100644
--- a/src/ao_teleterra.c
+++ b/src/product/ao_teleterra.c
diff --git a/src/ao_test.c b/src/product/ao_test.c
index 14c2eb75..14c2eb75 100644
--- a/src/ao_test.c
+++ b/src/product/ao_test.c
diff --git a/src/ao_tidongle.c b/src/product/ao_tidongle.c
index 3b7c2733..5adbb05c 100644
--- a/src/ao_tidongle.c
+++ b/src/product/ao_tidongle.c
@@ -34,6 +34,8 @@ main(void)
ao_rssi_init(AO_LED_RED);
ao_radio_init();
ao_dbg_init();
+ ao_aes_init();
+ ao_radio_cmac_init();
ao_config_init();
/* Bring up the USB link */
P1DIR |= 1;
diff --git a/src/telebt-v0.0/Makefile b/src/telebt-v0.0/Makefile
index d8867b19..e89639ab 100644
--- a/src/telebt-v0.0/Makefile
+++ b/src/telebt-v0.0/Makefile
@@ -1 +1,9 @@
-include ../Makefile.proto
+#
+# TeleBT v0.0 build
+#
+
+TELEBT_VER=0.0
+TELEBT_DEF=0_0
+
+include ../product/Makefile.telebt
+
diff --git a/src/telebt-v0.0/Makefile.defs b/src/telebt-v0.0/Makefile.defs
deleted file mode 100644
index f0bb5e0c..00000000
--- a/src/telebt-v0.0/Makefile.defs
+++ /dev/null
@@ -1,8 +0,0 @@
-PROG = telebt-v0.0-$(VERSION).ihx
-
-SRC = \
- $(TBT_BASE_SRC)
-
-PRODUCT=TeleBT-v0.0
-PRODUCT_DEF=-DTELEBT_V_0_0
-IDPRODUCT=0x000e
diff --git a/src/telebt-v0.1/Makefile b/src/telebt-v0.1/Makefile
index d8867b19..90cd3cac 100644
--- a/src/telebt-v0.1/Makefile
+++ b/src/telebt-v0.1/Makefile
@@ -1 +1,21 @@
-include ../Makefile.proto
+#
+# TeleBT v0.1 build
+#
+
+TELEBT_VER=0.1
+TELEBT_DEF=0_1
+
+TELEBT_INC = \
+ ao_25lc1024.h
+
+TELEBT_SRC = \
+ ao_beep.c \
+ ao_log_single.c \
+ ao_log_telem.c \
+ ao_report.c \
+ ao_spi.c \
+ ao_storage.c \
+ ao_m25.c
+
+include ../product/Makefile.telebt
+
diff --git a/src/telebt-v0.1/Makefile.defs b/src/telebt-v0.1/Makefile.defs
deleted file mode 100644
index 50657c83..00000000
--- a/src/telebt-v0.1/Makefile.defs
+++ /dev/null
@@ -1,8 +0,0 @@
-PROG = telebt-v0.1-$(VERSION).ihx
-
-SRC = \
- $(TBT_V_0_1_SRC)
-
-PRODUCT=TeleBT-v0.1
-PRODUCT_DEF=-DTELEBT_V_0_1
-IDPRODUCT=0x000e
diff --git a/src/teledongle-v0.1/.sdcdbrc b/src/teledongle-v0.1/.sdcdbrc
new file mode 100644
index 00000000..710b4a2f
--- /dev/null
+++ b/src/teledongle-v0.1/.sdcdbrc
@@ -0,0 +1 @@
+--directory=..
diff --git a/src/teledongle-v0.1/Makefile b/src/teledongle-v0.1/Makefile
index d8867b19..48425107 100644
--- a/src/teledongle-v0.1/Makefile
+++ b/src/teledongle-v0.1/Makefile
@@ -1 +1,8 @@
-include ../Makefile.proto
+#
+# TeleDongle v0.2 build
+#
+
+TD_VER=0.1
+TD_DEF=0_1
+
+include ../product/Makefile.teledongle
diff --git a/src/teledongle-v0.1/Makefile.defs b/src/teledongle-v0.1/Makefile.defs
deleted file mode 100644
index ceb80b7a..00000000
--- a/src/teledongle-v0.1/Makefile.defs
+++ /dev/null
@@ -1,9 +0,0 @@
-PROG = teledongle-v0.1-$(VERSION).ihx
-
-SRC = \
- $(TD_SRC) \
- $(DBG_SRC)
-
-PRODUCT=TeleDongle-v0.1
-PRODUCT_DEF=-DTELEDONGLE_V_0_1
-IDPRODUCT=0x000c
diff --git a/src/teledongle-v0.2/Makefile b/src/teledongle-v0.2/Makefile
index d8867b19..ce4ab437 100644
--- a/src/teledongle-v0.2/Makefile
+++ b/src/teledongle-v0.2/Makefile
@@ -1 +1,8 @@
-include ../Makefile.proto
+#
+# TeleDongle v0.2 build
+#
+
+TD_VER=0.2
+TD_DEF=0_2
+
+include ../product/Makefile.teledongle \ No newline at end of file
diff --git a/src/teledongle-v0.2/Makefile.defs b/src/teledongle-v0.2/Makefile.defs
deleted file mode 100644
index ea9713b6..00000000
--- a/src/teledongle-v0.2/Makefile.defs
+++ /dev/null
@@ -1,9 +0,0 @@
-PROG = teledongle-v0.2-$(VERSION).ihx
-
-SRC = \
- $(TD_SRC) \
- $(DBG_SRC)
-
-PRODUCT=TeleDongle-v0.2
-PRODUCT_DEF=-DTELEDONGLE_V_0_2
-IDPRODUCT=0x000c
diff --git a/src/telelaunch-v0.1/.gitignore b/src/telelaunch-v0.1/.gitignore
new file mode 100644
index 00000000..d25d7ad9
--- /dev/null
+++ b/src/telelaunch-v0.1/.gitignore
@@ -0,0 +1,2 @@
+telemetrum-v0.1-sky*
+ao_product.h
diff --git a/src/telelaunch-v0.1/.sdcdbrc b/src/telelaunch-v0.1/.sdcdbrc
new file mode 100644
index 00000000..710b4a2f
--- /dev/null
+++ b/src/telelaunch-v0.1/.sdcdbrc
@@ -0,0 +1 @@
+--directory=..
diff --git a/src/telelaunch-v0.1/Makefile b/src/telelaunch-v0.1/Makefile
new file mode 100644
index 00000000..b0d9d165
--- /dev/null
+++ b/src/telelaunch-v0.1/Makefile
@@ -0,0 +1,4 @@
+TELELAUNCH_VER=0.1
+TELELAUNCH_DEF=0_1
+
+include ../product/Makefile.telelaunch
diff --git a/src/telelaunch-v0.1/Makefile.defs b/src/telelaunch-v0.1/Makefile.defs
new file mode 100644
index 00000000..56f5730b
--- /dev/null
+++ b/src/telelaunch-v0.1/Makefile.defs
@@ -0,0 +1,14 @@
+PROG = telelaunch-v0.1-$(VERSION).ihx
+
+SRC = \
+ $(TLAUNCH_BASE_SRC) \
+ $(SPI_DRIVER_SRC) \
+ $(EE_DRIVER_SRC) \
+ ao_launch.c \
+ ao_aes.c \
+ ao_radio_cmac.c \
+ $(DBG_SRC)
+
+PRODUCT=TeleLaunch-v0.1
+PRODUCT_DEF=-DTELELAUNCH_V_0_1
+IDPRODUCT=0x000f
diff --git a/src/telemetrum-v0.1-sirf/Makefile b/src/telemetrum-v0.1-sirf/Makefile
index d8867b19..00cdc9c5 100644
--- a/src/telemetrum-v0.1-sirf/Makefile
+++ b/src/telemetrum-v0.1-sirf/Makefile
@@ -1 +1,16 @@
-include ../Makefile.proto
+#
+# TeleMetrum v0.1 with SkyTraq GPS build
+#
+
+TM_VER=0.1
+TM_DEF=0_1
+
+TM_INC = \
+ ao_25lc1024.h
+
+TM_SRC = \
+ ao_gps_sirf.c \
+ ao_25lc1024.c
+
+include ../product/Makefile.telemetrum
+
diff --git a/src/telemetrum-v0.1-sirf/Makefile.defs b/src/telemetrum-v0.1-sirf/Makefile.defs
deleted file mode 100644
index ac8dcdb9..00000000
--- a/src/telemetrum-v0.1-sirf/Makefile.defs
+++ /dev/null
@@ -1,12 +0,0 @@
-PROG = telemetrum-v0.1-sirf-$(VERSION).ihx
-
-SRC = \
- $(TM_BASE_SRC) \
- $(SPI_DRIVER_SRC) \
- $(EE_DRIVER_SRC) \
- $(SIRF_DRIVER_SRC) \
- $(DBG_SRC)
-
-PRODUCT=TeleMetrum-v0.1-SiRF
-PRODUCT_DEF=-DTELEMETRUM_V_0_1
-IDPRODUCT=0x000b
diff --git a/src/telemetrum-v0.1-sky/Makefile b/src/telemetrum-v0.1-sky/Makefile
index d8867b19..e3c61db6 100644
--- a/src/telemetrum-v0.1-sky/Makefile
+++ b/src/telemetrum-v0.1-sky/Makefile
@@ -1 +1,16 @@
-include ../Makefile.proto
+#
+# TeleMetrum v0.1 with SkyTraq GPS build
+#
+
+TM_VER=0.1
+TM_DEF=0_1
+
+TM_INC = \
+ ao_25lc1024.h
+
+TM_SRC = \
+ ao_gps_skytraq.c \
+ ao_25lc1024.c
+
+include ../product/Makefile.telemetrum
+
diff --git a/src/telemetrum-v0.1-sky/Makefile.defs b/src/telemetrum-v0.1-sky/Makefile.defs
deleted file mode 100644
index e032d1eb..00000000
--- a/src/telemetrum-v0.1-sky/Makefile.defs
+++ /dev/null
@@ -1,12 +0,0 @@
-PROG = telemetrum-v0.1-sky-$(VERSION).ihx
-
-SRC = \
- $(TM_BASE_SRC) \
- $(SPI_DRIVER_SRC) \
- $(EE_DRIVER_SRC) \
- $(SKY_DRIVER_SRC) \
- $(DBG_SRC)
-
-PRODUCT=TeleMetrum-v0.1
-PRODUCT_DEF=-DTELEMETRUM_V_0_1
-IDPRODUCT=0x000b
diff --git a/src/telemetrum-v1.0/Makefile b/src/telemetrum-v1.0/Makefile
index d8867b19..4aae84c8 100644
--- a/src/telemetrum-v1.0/Makefile
+++ b/src/telemetrum-v1.0/Makefile
@@ -1 +1,16 @@
-include ../Makefile.proto
+#
+# TeleMetrum v1.0 build
+#
+
+TM_VER=1.0
+TM_DEF=1_0
+
+TM_INC = \
+ ao_at45db161d.h
+
+TM_SRC = \
+ ao_companion.c \
+ ao_gps_skytraq.c \
+ ao_at45db161d.c
+
+include ../product/Makefile.telemetrum
diff --git a/src/telemetrum-v1.0/Makefile.defs b/src/telemetrum-v1.0/Makefile.defs
deleted file mode 100644
index 5eefc392..00000000
--- a/src/telemetrum-v1.0/Makefile.defs
+++ /dev/null
@@ -1,13 +0,0 @@
-PROG = telemetrum-v1.0-$(VERSION).ihx
-
-SRC = \
- $(TM_BASE_SRC) \
- $(SPI_DRIVER_SRC) \
- $(FLASH_DRIVER_SRC) \
- $(SKY_DRIVER_SRC) \
- $(COMPANION_SRC) \
- $(DBG_SRC)
-
-PRODUCT=TeleMetrum-v1.0
-PRODUCT_DEF=-DTELEMETRUM_V_1_0
-IDPRODUCT=0x000b
diff --git a/src/telemetrum-v1.1/Makefile b/src/telemetrum-v1.1/Makefile
index d8867b19..4bea03db 100644
--- a/src/telemetrum-v1.1/Makefile
+++ b/src/telemetrum-v1.1/Makefile
@@ -1 +1,16 @@
-include ../Makefile.proto
+#
+# AltOS build
+#
+#
+
+TM_VER=1.1
+TM_DEF=1_1
+
+TM_INC =
+
+TM_SRC = \
+ ao_companion.c \
+ ao_gps_skytraq.c \
+ ao_m25.c
+
+include ../product/Makefile.telemetrum
diff --git a/src/telemetrum-v1.1/Makefile.defs b/src/telemetrum-v1.1/Makefile.defs
deleted file mode 100644
index 3c8b8793..00000000
--- a/src/telemetrum-v1.1/Makefile.defs
+++ /dev/null
@@ -1,13 +0,0 @@
-PROG = telemetrum-v1.1-$(VERSION).ihx
-
-SRC = \
- $(TM_BASE_SRC) \
- $(SPI_DRIVER_SRC) \
- $(M25_DRIVER_SRC) \
- $(SKY_DRIVER_SRC) \
- $(COMPANION_SRC) \
- $(DBG_SRC)
-
-PRODUCT=TeleMetrum-v1.1
-PRODUCT_DEF=-DTELEMETRUM_V_1_1
-IDPRODUCT=0x000b
diff --git a/src/telemini-v1.0/Makefile b/src/telemini-v1.0/Makefile
index d8867b19..4f1c8b51 100644
--- a/src/telemini-v1.0/Makefile
+++ b/src/telemini-v1.0/Makefile
@@ -1 +1,8 @@
-include ../Makefile.proto
+#
+# TeleMini build file
+#
+
+TELEMINI_VER=1.0
+TELEMINI_DEF=1_0
+
+include ../product/Makefile.telemini
diff --git a/src/telemini-v1.0/Makefile.defs b/src/telemini-v1.0/Makefile.defs
deleted file mode 100644
index 0e91f2fc..00000000
--- a/src/telemini-v1.0/Makefile.defs
+++ /dev/null
@@ -1,9 +0,0 @@
-PROG = telemini-v1.0-$(VERSION).ihx
-
-SRC = \
- $(TMINI_BASE_SRC)
-
-PRODUCT=TeleMini-v1.0
-PRODUCT_DEF=-DTELEMINI_V_1_0
-IDPRODUCT=0x000a
-CODESIZE=0x6700
diff --git a/src/telenano-v0.1/Makefile b/src/telenano-v0.1/Makefile
index d8867b19..2714c1e9 100644
--- a/src/telenano-v0.1/Makefile
+++ b/src/telenano-v0.1/Makefile
@@ -1 +1,9 @@
-include ../Makefile.proto
+#
+# TeleNano build file
+#
+
+TELENANO_VER=0.1
+TELENANO_DEF=0_1
+
+include ../product/Makefile.telenano
+
diff --git a/src/telenano-v0.1/Makefile.defs b/src/telenano-v0.1/Makefile.defs
deleted file mode 100644
index 34cf69d1..00000000
--- a/src/telenano-v0.1/Makefile.defs
+++ /dev/null
@@ -1,9 +0,0 @@
-PROG = telenano-v0.1-$(VERSION).ihx
-
-SRC = \
- $(TNANO_BASE_SRC)
-
-PRODUCT=TeleNano-v0.1
-PRODUCT_DEF=-DTELENANO_V_0_1
-IDPRODUCT=0x000a
-CODESIZE=0x6700
diff --git a/src/telepyro-v0.1/Makefile b/src/telepyro-v0.1/Makefile
new file mode 100644
index 00000000..2f664fcb
--- /dev/null
+++ b/src/telepyro-v0.1/Makefile
@@ -0,0 +1,101 @@
+#
+# AltOS build
+#
+#
+vpath % ..:../core:../product:../drivers:../avr
+vpath ao-make-product.5c ../util
+
+MCU=atmega32u4
+DUDECPUTYPE=m32u4
+#PROGRAMMER=stk500v2 -P usb
+PROGRAMMER=usbtiny
+LOADCMD=avrdude
+LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
+CC=avr-gcc
+OBJCOPY=avr-objcopy
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_usb.h \
+ ao_pins.h \
+ altitude.h
+
+ALTOS_SRC = \
+ ao_clock.c \
+ ao_cmd.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_product.c \
+ ao_stdio.c \
+ ao_task.c \
+ ao_timer.c \
+ ao_led.c \
+ ao_avr_stdio.c \
+ ao_romconfig.c \
+ ao_usb_avr.c \
+ ao_adc_avr.c \
+ ao_pyro_slave.c \
+ ao_spi_slave.c
+
+PRODUCT=TelePyro-v0.1
+MCU=atmega32u4
+PRODUCT_DEF=-DTELEPYRO
+IDPRODUCT=0x0011
+CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../core -I..
+CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O3 -mcall-prologues -DAVR
+
+NICKLE=nickle
+
+PROG=telepyro-v0.1
+
+SRC=$(ALTOS_SRC) ao_telepyro.c
+OBJ=$(SRC:.c=.o)
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: $(PROG)
+
+CHECK=sh ../util/check-avr-mem
+
+$(PROG): Makefile $(OBJ)
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ)
+ $(call quiet,CHECK) $(PROG) || ($(RM) -f $(PROG); exit 1)
+
+$(PROG).hex: $(PROG)
+ avr-size $(PROG)
+ $(OBJCOPY) -R .eeprom -O ihex $(PROG) $@
+
+
+load: $(PROG).hex
+ $(LOADCMD) $(LOADARG)$(PROG).hex
+
+../altitude.h: make-altitude
+ nickle $< > $@
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+ao_product.rel: ao_product.c ao_product.h
+ $(call quiet,CC) -c $(CFLAGS) -D PRODUCT_DEFS='\"ao_product.h\"' -o$@ $<
+
+distclean: clean
+
+clean:
+ rm -f $(OBJ)
+ rm -f ao_product.h
+
+install:
+
+uninstall:
+
+$(OBJ): ao.h ao_product.h ao_usb.h
diff --git a/src/telescience-v0.1/Makefile b/src/telescience-v0.1/Makefile
new file mode 100644
index 00000000..a6797cbe
--- /dev/null
+++ b/src/telescience-v0.1/Makefile
@@ -0,0 +1,112 @@
+#
+# AltOS build
+#
+#
+vpath % ..:../core:../product:../drivers:../avr
+vpath ao-make-product.5c ../util
+
+MCU=atmega32u4
+DUDECPUTYPE=m32u4
+#PROGRAMMER=stk500v2 -P usb
+PROGRAMMER=usbtiny
+LOADCMD=avrdude
+LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
+CC=avr-gcc
+OBJCOPY=avr-objcopy
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_usb.h \
+ ao_pins.h \
+ altitude.h
+
+#
+# Common AltOS sources
+#
+TELESCIENCE_STORAGE= \
+ ao_m25.c \
+ ao_spi_usart.c \
+ ao_storage.c \
+
+ALTOS_SRC = \
+ ao_clock.c \
+ ao_cmd.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_product.c \
+ ao_stdio.c \
+ ao_task.c \
+ ao_timer.c \
+ ao_led.c \
+ ao_avr_stdio.c \
+ ao_romconfig.c \
+ ao_usb_avr.c \
+ ao_adc_avr.c \
+ ao_science_slave.c \
+ ao_spi_slave.c \
+ ao_log_single.c \
+ ao_log_telescience.c \
+ $(TELESCIENCE_STORAGE)
+
+PRODUCT=TeleScience-v0.1
+MCU=atmega32u4
+PRODUCT_DEF=-DTELESCIENCE
+IDPRODUCT=0x0011
+CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../core -I..
+CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O3 -mcall-prologues -DAVR
+
+NICKLE=nickle
+
+PROG=telescience-v0.1
+
+SRC=$(ALTOS_SRC) ao_telescience.c
+OBJ=$(SRC:.c=.o)
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: $(PROG)
+
+CHECK=sh ../util/check-avr-mem
+
+$(PROG): Makefile $(OBJ)
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ)
+ $(call quiet,CHECK) $(PROG) || ($(RM) -f $(PROG); exit 1)
+
+$(PROG).hex: $(PROG)
+ avr-size $(PROG)
+ $(OBJCOPY) -R .eeprom -O ihex $(PROG) $@
+
+
+load: $(PROG).hex
+ $(LOADCMD) $(LOADARG)$(PROG).hex
+
+../altitude.h: make-altitude
+ nickle $< > $@
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+ao_product.rel: ao_product.c ao_product.h
+ $(call quiet,CC) -c $(CFLAGS) -D PRODUCT_DEFS='\"ao_product.h\"' -o$@ $<
+
+distclean: clean
+
+clean:
+ rm -f $(OBJ)
+ rm -f ao_product.h
+
+install:
+
+uninstall:
+
+$(OBJ): ao.h ao_product.h ao_usb.h
diff --git a/src/test/Makefile b/src/test/Makefile
index 33203ffd..333850e4 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -1,9 +1,8 @@
-vpath % ..
-vpath % ../kalman
+vpath % ..:../core:../drivers
PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_gps_test ao_gps_test_skytraq ao_convert_test
-CFLAGS=-I.. -I.
+CFLAGS=-I.. -I. -I../core -I../drivers -O0 -g
all: $(PROGS)
@@ -13,22 +12,19 @@ clean:
install:
ao_flight_test: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h ao_kalman.h
- cc -g -o $@ $<
+ cc $(CFLAGS) -o $@ $<
ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h ao_kalman.h
- cc -g -o $@ -DHAS_ACCEL=0 ../ao_flight_test.c
+ cc $(CFLAGS) -o $@ -DHAS_ACCEL=0 ao_flight_test.c
ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h ao_kalman.h
- cc -g -o $@ -DFORCE_ACCEL=1 ../ao_flight_test.c
+ cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 ao_flight_test.c
ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h
- cc -g -o $@ $<
+ cc $(CFLAGS) -o $@ $<
ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_host.h
- cc -g -o $@ $<
+ cc $(CFLAGS) -o $@ $<
ao_convert_test: ao_convert_test.c ao_convert.c altitude.h
- cc -g -o $@ $<
-
-../ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c
- sh $< > $@
+ cc $(CFLAGS) -o $@ $<
diff --git a/src/ao_flight_test.c b/src/test/ao_flight_test.c
index 56733c89..56733c89 100644
--- a/src/ao_flight_test.c
+++ b/src/test/ao_flight_test.c
diff --git a/src/ao_gps_test.c b/src/test/ao_gps_test.c
index 93d7a9ab..93d7a9ab 100644
--- a/src/ao_gps_test.c
+++ b/src/test/ao_gps_test.c
diff --git a/src/ao_gps_test_skytraq.c b/src/test/ao_gps_test_skytraq.c
index a78fae0f..a78fae0f 100644
--- a/src/ao_gps_test_skytraq.c
+++ b/src/test/ao_gps_test_skytraq.c
diff --git a/src/tidongle/Makefile b/src/tidongle/Makefile
index d8867b19..057e420b 100644
--- a/src/tidongle/Makefile
+++ b/src/tidongle/Makefile
@@ -1 +1,94 @@
-include ../Makefile.proto
+#
+# TIDongle build file
+#
+
+vpath %.c ..:../core:../cc1111:../drivers:../product
+vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath ao-make-product.5c ../util
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ cc1111.h \
+ ao_product.h
+
+CORE_SRC = \
+ ao_cmd.c \
+ ao_config.c \
+ ao_gps_print.c \
+ ao_monitor.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_rssi.c \
+ ao_state.c \
+ ao_stdio.c \
+ ao_task.c
+
+CC1111_SRC = \
+ ao_aes.c \
+ ao_dbg.c \
+ ao_dma.c \
+ ao_led.c \
+ ao_packet.c \
+ ao_packet_master.c \
+ ao_radio.c \
+ ao_radio_cmac.c \
+ ao_romconfig.c \
+ ao_timer.c \
+ ao_usb.c \
+ _bp.c
+
+DRIVER_SRC =
+
+PRODUCT_SRC = \
+ ao_tidongle.c
+
+SRC = \
+ $(CORE_SRC) \
+ $(CC1111_SRC) \
+ $(DRIVER_SRC) \
+ $(PRODUCT_SRC)
+
+PROG = tidongle-$(VERSION).ihx
+PRODUCT=TIDongle
+PRODUCT_DEF=-DTIDONGLE
+IDPRODUCT=0x000a
+
+include ../cc1111/Makefile.cc1111
+
+NICKLE=nickle
+CHECK_STACK=sh ../util/check-stack
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: ../$(PROG)
+
+../$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+ $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean:
+ rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM)
+ rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
+ rm -f ao_product.h
+ rm -f ../$(PROG) ../$(PMAP)
+
+install:
+
+uninstall:
+
diff --git a/src/tidongle/Makefile.defs b/src/tidongle/Makefile.defs
deleted file mode 100644
index 0e13cb20..00000000
--- a/src/tidongle/Makefile.defs
+++ /dev/null
@@ -1,9 +0,0 @@
-PROG = tidongle-$(VERSION).ihx
-
-SRC = \
- $(TI_SRC)
-
-PRODUCT=TIDongle
-
-PRODUCT_DEF=-DTIDONGLE
-IDPRODUCT=0x000a
diff --git a/src/ao-make-product.5c b/src/util/ao-make-product.5c
index 5f2eb8e8..5f2eb8e8 100644
--- a/src/ao-make-product.5c
+++ b/src/util/ao-make-product.5c
diff --git a/src/util/check-avr-mem b/src/util/check-avr-mem
new file mode 100644
index 00000000..c73edbd1
--- /dev/null
+++ b/src/util/check-avr-mem
@@ -0,0 +1,9 @@
+#!/bin/sh
+nm "$@" |
+grep ' N _end' |
+awk '{ iram = strtonum("0x" $1) % 0x10000;
+if ( iram > 0xaff) {
+ printf ("%d bytes of ram more than %d available\n", iram, 0xaff);
+ exit(1);
+} else
+ exit(0); }'
diff --git a/src/check-stack b/src/util/check-stack
index 1e8044e0..1e8044e0 100755
--- a/src/check-stack
+++ b/src/util/check-stack
diff --git a/src/gps-cksum b/src/util/gps-cksum
index a08153bf..a08153bf 100755
--- a/src/gps-cksum
+++ b/src/util/gps-cksum
diff --git a/src/make-altitude b/src/util/make-altitude
index 716aa8a8..716aa8a8 100644
--- a/src/make-altitude
+++ b/src/util/make-altitude
diff --git a/src/make-kalman b/src/util/make-kalman
index 9ac35134..397d6020 100644
--- a/src/make-kalman
+++ b/src/util/make-kalman
@@ -1,6 +1,6 @@
-#!/bin/sh
+#!/bin/bash
-cd ../kalman
+cd $1 2> /dev/null 1>&2
SIGMA_BOTH="-M 2 -H 6 -A 2"
SIGMA_BARO="-M 2 -H 6 -A 2"
diff --git a/src/sirf-cksum b/src/util/sirf-cksum
index b905f318..b905f318 100755
--- a/src/sirf-cksum
+++ b/src/util/sirf-cksum
diff --git a/src/skytraq-cksum b/src/util/skytraq-cksum
index ab0464a7..ab0464a7 100644
--- a/src/skytraq-cksum
+++ b/src/util/skytraq-cksum